I wrote an obj loader in GoLang and am attempting to render a cube. The cube is already pre triangulated and I have made sure the UV's are set correctly in blender before exporting it. The issue is the texture is not rendering correctly on the cube and I'm not sure what's causing it. I do sort the texture coords and normals by the indices first. What I currently get: Cube Side Cube Front
What I expect to get: Expected
Code (Here's a Gist link to if that makes it)
package obj
import (
"bytes"
"fmt"
"github.com/go-gl/mathgl/mgl32"
"io"
"kami/render/models"
"kami/util"
)
func LoadModel(file string) models.Model {
objData := util.ReadAsset(file)
objReader := bytes.NewReader(objData)
modelPart := models.ModelPart{}
var x, y, z float32
var textureCoords []mgl32.Vec2
var normals []mgl32.Vec3
for {
var lineType string
_, err := fmt.Fscanf(objReader, "%s", &lineType)
if err != nil {
if err == io.EOF {
break
}
}
switch lineType {
// VERTICES.
case "v":
fmt.Fscanf(objReader, "%f %f %f\n", &x, &y, &z)
modelPart.Vertices = append(modelPart.Vertices, x, y, z)
// NORMALS.
case "vn":
fmt.Fscanf(objReader, "%f %f %f\n", &x, &y, &z)
normals = append(normals, mgl32.Vec3{x, y, z})
// TEXTURE VERTICES.
case "vt":
fmt.Fscanf(objReader, "%f %f\n", &x, &y)
textureCoords = append(textureCoords, mgl32.Vec2{x, y})
// INDICES.
case "f":
norm := make([]float32, 4)
indices := make([]float32, 4)
uv := make([]float32, 4)
matches, _ := fmt.Fscanf(objReader, "%f/%f/%f %f/%f/%f %f/%f/%f %f/%f/%f\n", &indices[0], &uv[0], &norm[0], &indices[1], &uv[1], &norm[1], &indices[2], &uv[2], &norm[2], &indices[3], &uv[3], &norm[3])
if (matches != 9 && matches != 12) || textureCoords == nil || normals == nil {
panic("Cannot read OBJ file")
}
modelPart.Indices = append(modelPart.Indices, uint32(indices[0]-1))
modelPart.Indices = append(modelPart.Indices, uint32(indices[1]-1))
modelPart.Indices = append(modelPart.Indices, uint32(indices[2]-1))
modelPart.TextureCoords = append(modelPart.TextureCoords, textureCoords[int(uv[0]) -1].X(), 1 - textureCoords[int(uv[0]) -1].Y())
modelPart.TextureCoords = append(modelPart.TextureCoords, textureCoords[int(uv[1]) -1].X(), 1 - textureCoords[int(uv[1]) -1].Y())
modelPart.TextureCoords = append(modelPart.TextureCoords, textureCoords[int(uv[2]) -1].X(), 1 - textureCoords[int(uv[2]) -1].Y())
modelPart.Normals = append(modelPart.Normals, normals[int(norm[0]) - 1].X(), normals[int(norm[0]) - 1].Y(), normals[int(norm[0]) - 1].Z())
modelPart.Normals = append(modelPart.Normals, normals[int(norm[1]) - 1].X(), normals[int(norm[1]) - 1].Y(), normals[int(norm[1]) - 1].Z())
modelPart.Normals = append(modelPart.Normals, normals[int(norm[2]) - 1].X(), normals[int(norm[2]) - 1].Y(), normals[int(norm[2]) - 1].Z())
//Triangulate if face is a Quad
if matches == 12 {
modelPart.Indices = append(modelPart.Indices, uint32(indices[0]-1), uint32(indices[2]-1), uint32(indices[3]-1))
modelPart.TextureCoords = append(modelPart.TextureCoords, textureCoords[int(uv[0]) -1].X(), 1 - textureCoords[int(uv[0]) -1].Y())
modelPart.TextureCoords = append(modelPart.TextureCoords, textureCoords[int(uv[2]) -1].X(), 1 - textureCoords[int(uv[2]) -1].Y())
modelPart.TextureCoords = append(modelPart.TextureCoords, textureCoords[int(uv[3]) -1].X(), 1 - textureCoords[int(uv[3]) -1].Y())
modelPart.Normals = append(modelPart.Normals, normals[int(norm[0]) - 1].X(), normals[int(norm[0]) - 1].Y(), normals[int(norm[0]) - 1].Z())
modelPart.Normals = append(modelPart.Normals, normals[int(norm[2]) - 1].X(), normals[int(norm[2]) - 1].Y(), normals[int(norm[2]) - 1].Z())
modelPart.Normals = append(modelPart.Normals, normals[int(norm[3]) - 1].X(), normals[int(norm[3]) - 1].Y(), normals[int(norm[3]) - 1].Z())
}
}
}
modelPart.GenerateModelVAO()
return models.Model{Parts:[]models.ModelPart{modelPart}}
}
For actually rendering the model, I Simple bind the texture, create a transformation matrix, bind the VAO i generated earlier, and then draw the elements
gl.ActiveTexture(gl.TEXTURE0)
gl.BindTexture(gl.TEXTURE_2D, texture)
rotation := mgl32.AnglesToQuat(0, 0, 0, mgl32.XYZ)
transformMatrix := render.CreateTransformMatrix(mgl32.Vec3{0, 0, -10}, rotation, 1)
for _, element := range cubeModel.Parts {
element.Vao.Bind()
gl.UniformMatrix4fv(transformationMatrixUniform, 1, false, &transformMatrix[0])
gl.DrawElements(gl.TRIANGLES, int32(len(element.Indices)), gl.UNSIGNED_INT, gl.Ptr(element.Indices))
}