Skip to content

Instantly share code, notes, and snippets.

@Nutriz

Nutriz/OBJLoader.kt

Created May 8, 2021
Embed
What would you like to do?
OBJLoader with multiple tex-coords per Vertex support
data class Face(
val indexGroups: List<IndexesGroup>,
)
data class IndexesGroup(val idxPos: Int = NO_VALUE, val idxTextCoords: Int = NO_VALUE, val idxVecNormal: Int = NO_VALUE) {
companion object {
const val NO_VALUE = -1
}
}
object ObjLoader {
fun loadMesh(fileName: String): Mesh {
val positionsData = mutableListOf<Vector3f>()
val texCoordsData = mutableListOf<Vector2f>()
val normalsData = mutableListOf<Vector3f>()
val facesData = mutableListOf<Face>()
File(fileName).forEachLine { line ->
val tokens = line.split(" ")
when (tokens.first()) {
"v" -> positionsData += Vector3f(tokens[1].toFloat(), tokens[2].toFloat(), tokens[3].toFloat())
"vt" -> texCoordsData += Vector2f(tokens[1].toFloat(), tokens[2].toFloat())
"vn" -> normalsData += Vector3f(tokens[1].toFloat(), tokens[2].toFloat(), tokens[3].toFloat())
"f" -> {
val indexGroups = mutableListOf<IndexesGroup>()
tokens.drop(1).forEach { groupString ->
val group = groupString.split("/").map { it.toInt() - 1 }
indexGroups += IndexesGroup(group[0], group[1], group[2])
}
facesData += Face(indexGroups)
}
}
}
val usePosForIdx = positionsData.size >= texCoordsData.size
return reorderLists(positionsData, texCoordsData, normalsData, facesData, usePosForIdx)
}
private fun reorderLists(
positionsData: MutableList<Vector3f>,
texCoordsData: MutableList<Vector2f>,
normalsData: MutableList<Vector3f>,
facesData: MutableList<Face>,
usePosForIdx: Boolean = true
): Mesh {
println("Mesh reordering with positions: $usePosForIdx")
val arraySize = if (usePosForIdx) positionsData.size else texCoordsData.size
val positions = FloatArray(arraySize * 3)
val texCoords = FloatArray(arraySize * 2)
val normals = FloatArray(arraySize * 3)
val indices = mutableListOf<Int>()
facesData.forEach { face ->
face.indexGroups.forEach { groupId ->
val index = if (usePosForIdx) groupId.idxPos else groupId.idxTextCoords
val position = positionsData[groupId.idxPos]
positions[index * 3] = position.x
positions[index * 3 + 1] = position.y
positions[index * 3 + 2] = position.z
val coords = texCoordsData[groupId.idxTextCoords]
texCoords[index * 2] = coords.x
texCoords[index * 2 + 1] = 1 - coords.y
val normal = normalsData[groupId.idxVecNormal]
normals[index * 3] = normal.x
normals[index * 3 + 1] = normal.y
normals[index * 3 + 2] = normal.z
indices += index
}
}
return Mesh(positions, texCoords, normals, indices.toIntArray())
}
}
@Nutriz

This comment has been minimized.

Copy link
Owner Author

@Nutriz Nutriz commented May 8, 2021

This code is about chapter 10 of 3D Game Development with LWJGL 3 and this issue.

At the end of the chapter, the OBJLoader don't correctly with multiple tex-coords per Vertex, and the cube example look like that.

image

Line 34 and 46 are the keys to understand what we are doing, either using vertex position OR tex coords for the size of our arrays.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment