Last active
September 20, 2023 09:31
-
-
Save davemackintosh/67959fa9dfd9018d79a4 to your computer and use it in GitHub Desktop.
Really simple OBJ loader in Golang. Done this loads in C++ and thought I'd see how easy it was in Go, turns out it's really easy. No license, feel free to whatever with this.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package model | |
import ( | |
"fmt" | |
"io" | |
"os" | |
"github.com/go-gl/mathgl/mgl32" | |
) | |
// Model is a renderable collection of vecs. | |
type Model struct { | |
// For the v, vt and vn in the obj file. | |
Normals, Vecs []mgl32.Vec3 | |
Uvs []mgl32.Vec2 | |
// For the fun "f" in the obj file. | |
VecIndices, NormalIndices, UvIndices []float32 | |
} | |
// NewModel will read an OBJ model file and create a Model from its contents | |
func NewModel(file string) Model { | |
// Open the file for reading and check for errors. | |
objFile, err := os.Open(file) | |
if err != nil { | |
panic(err) | |
} | |
// Don't forget to close the file reader. | |
defer objFile.Close() | |
// Create a model to store stuff. | |
model := Model{} | |
// Read the file and get it's contents. | |
for { | |
var lineType string | |
// Scan the type field. | |
_, err := fmt.Fscanf(objFile, "%s", &lineType) | |
// Check if it's the end of the file | |
// and break out of the loop. | |
if err != nil { | |
if err == io.EOF { | |
break | |
} | |
} | |
// Check the type. | |
switch lineType { | |
// VERTICES. | |
case "v": | |
// Create a vec to assign digits to. | |
vec := mgl32.Vec3{} | |
// Get the digits from the file. | |
fmt.Fscanf(objFile, "%f %f %f\n", &vec[0], &vec[1], &vec[2]) | |
// Add the vector to the model. | |
model.Vecs = append(model.Vecs, vec) | |
// NORMALS. | |
case "vn": | |
// Create a vec to assign digits to. | |
vec := mgl32.Vec3{} | |
// Get the digits from the file. | |
fmt.Fscanf(objFile, "%f %f %f\n", &vec[0], &vec[1], &vec[2]) | |
// Add the vector to the model. | |
model.Normals = append(model.Normals, vec) | |
// TEXTURE VERTICES. | |
case "vt": | |
// Create a Uv pair. | |
vec := mgl32.Vec2{} | |
// Get the digits from the file. | |
fmt.Fscanf(objFile, "%f %f\n", &vec[0], &vec[1]) | |
// Add the uv to the model. | |
model.Uvs = append(model.Uvs, vec) | |
// INDICES. | |
case "f": | |
// Create a vec to assign digits to. | |
norm := make([]float32, 3) | |
vec := make([]float32, 3) | |
uv := make([]float32, 3) | |
// Get the digits from the file. | |
matches, _ := fmt.Fscanf(objFile, "%f/%f/%f %f/%f/%f %f/%f/%f\n", &vec[0], &uv[0], &norm[0], &vec[1], &uv[1], &norm[1], &vec[2], &uv[2], &norm[2]) | |
if matches != 9 { | |
panic("Cannot read your file") | |
} | |
// Add the numbers to the model. | |
model.NormalIndices = append(model.NormalIndices, norm[0]) | |
model.NormalIndices = append(model.NormalIndices, norm[1]) | |
model.NormalIndices = append(model.NormalIndices, norm[2]) | |
model.VecIndices = append(model.VecIndices, vec[0]) | |
model.VecIndices = append(model.VecIndices, vec[1]) | |
model.VecIndices = append(model.VecIndices, vec[2]) | |
model.UvIndices = append(model.UvIndices, uv[0]) | |
model.UvIndices = append(model.UvIndices, uv[1]) | |
model.UvIndices = append(model.UvIndices, uv[2]) | |
} | |
} | |
// Return the newly created Model. | |
return model | |
} | |
// GetRenderableVertices returns a slice of float32s | |
// formatted in X, Y, Z, U, V. That is, XYZ of the | |
// vertex and the texture position. | |
func (model Model) GetRenderableVertices() []float32 { | |
// Create a slice for the outward float32s. | |
var out []float32 | |
// Loop over each vec3 in the indices property. | |
for _, position := range model.VecIndices { | |
index := int(position) - 1 | |
vec := model.Vecs[index] | |
uv := model.Uvs[int(model.UvIndices[index])-1] | |
out = append(out, vec.X(), vec.Y(), vec.Z(), uv.X(), uv.Y()) | |
} | |
// Return the array. | |
return out | |
} |
Hi Dave, I'm busy learning OpenGL. Would you mind if I use this as a foundation to work from in model loading? I don't see a license so figured I would ask. I will probably be changing it quite a lot but it looks like a great base to work from.
Feel free to use this, I absolutely cannot say whether it still works or not but go ahead and use/attribute, honestly don't remember this code at all haha. Take care and stay safe.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Not sure why but Github has totally fecked my 2 spaces and won't change it. Wtf?