From 23c261dae220b9fe78b03ae42147fb8b9b9f8791 Mon Sep 17 00:00:00 2001 From: Jannik-Hm Date: Tue, 2 Dec 2025 17:38:00 +0100 Subject: [PATCH 1/3] extended Mesh Add() to take multiple meshes --- pkg/MeshTypes/mesh.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/MeshTypes/mesh.go b/pkg/MeshTypes/mesh.go index c969524..d3aedb1 100644 --- a/pkg/MeshTypes/mesh.go +++ b/pkg/MeshTypes/mesh.go @@ -21,8 +21,10 @@ func (obj *Mesh) Copy() Mesh { return Mesh{Triangles: triangles} } -func (obj *Mesh) Add(mesh *Mesh) *Mesh { - obj.Triangles = append(obj.Triangles, mesh.Triangles...) +func (obj *Mesh) Add(mesh ...*Mesh) *Mesh { + for _, element := range mesh { + obj.Triangles = append(obj.Triangles, element.Triangles...) + } return obj } From 45196743094b8659aa6694fe1da4d30bf0123c79 Mon Sep 17 00:00:00 2001 From: Jannik-Hm Date: Tue, 2 Dec 2025 17:40:17 +0100 Subject: [PATCH 2/3] respect transformation matrix inside gltf + combine all gltf meshes into one --- main.go | 4 +- pkg/file_handlers/gltf.go | 81 +++++++++++++++++++++++++++++---------- 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/main.go b/main.go index 4e6940c..cb23da0 100644 --- a/main.go +++ b/main.go @@ -26,16 +26,16 @@ func LoadPrimitives() error { // Note: requires LoadPrimitives() to be run beforehand if you want to get a primitive func GetModel(conf ModelReaderConf, desiredSize *MeshTypes.Vector) (*MeshTypes.Mesh, error) { var mesh *MeshTypes.Mesh + var err error if conf.File != nil && conf.Filename != nil && *conf.Filename != "" { filetype := filepath.Ext(*conf.Filename) switch filetype { case ".gltf", ".glb": - meshes, err := FileHandlers.LoadGLTF(conf.File, desiredSize) + mesh, err = FileHandlers.LoadGLTF(conf.File, desiredSize) if err != nil { return nil, err } - mesh = meshes[0] case ".3ds": data, err := io.ReadAll(conf.File) if err != nil { diff --git a/pkg/file_handlers/gltf.go b/pkg/file_handlers/gltf.go index 9d431b0..acafdb1 100644 --- a/pkg/file_handlers/gltf.go +++ b/pkg/file_handlers/gltf.go @@ -10,26 +10,59 @@ import ( "github.com/qmuntal/gltf" ) -func LoadGLTF(file io.Reader, desiredSize *Types.Vector) ([]*Types.Mesh, error) { +func LoadGLTF(file io.Reader, desiredSize *Types.Vector) (*Types.Mesh, error) { var doc gltf.Document gltf.NewDecoder(file).Decode(&doc) - var meshes []*Types.Mesh + var meshes *Types.Mesh = &Types.Mesh{} - for _, m := range doc.Meshes { + transformationMatrices := map[int]Types.Matrix{} + + for _, node := range doc.Nodes { + if node.Mesh == nil { + continue + } + matrix := node.MatrixOrDefault() + transformationMatrices[*node.Mesh] = Types.Matrix{ + X00: matrix[0], X01: matrix[4], X02: matrix[8], X03: matrix[12], + X10: matrix[2], X11: matrix[5], X12: matrix[9], X13: matrix[13], + X20: matrix[1], X21: matrix[6], X22: matrix[10], X23: matrix[14], + X30: matrix[3], X31: matrix[7], X32: matrix[11], X33: matrix[15], + } + } + + // calculate outer dimensions + min := Types.Vector{} + max := Types.Vector{} + for meshindex, m := range doc.Meshes { for _, p := range m.Primitives { // contains Min and Max attr (for dimension calc) posAccessor := doc.Accessors[p.Attributes[gltf.POSITION]] - scaling := Types.Vector{X: 1, Y: 1, Z: 1} - if desiredSize != nil { - scaling = Types.Vector{ - // axes inverted to convert to correct coordinate system - X: desiredSize.X / (posAccessor.Max[0] - posAccessor.Min[0]), - Y: desiredSize.Y / (posAccessor.Max[2] - posAccessor.Min[2]), - Z: desiredSize.Z / (posAccessor.Max[1] - posAccessor.Min[1]), - } - } - positions, err := gltfVec3(&doc, posAccessor, scaling) + // do transformation before getting the outer dimensions + tempMin := transformationMatrices[meshindex].MulPosition(Types.Vector{ + X: posAccessor.Min[0], + Y: posAccessor.Min[2], + Z: posAccessor.Min[1], + }) + tempMax := transformationMatrices[meshindex].MulPosition(Types.Vector{ + X: posAccessor.Max[0], + Y: posAccessor.Max[2], + Z: posAccessor.Max[1], + }) + min = min.Min(&tempMin) + max = max.Max(&tempMax) + } + } + + scaling := Types.Vector{X: 1, Y: 1, Z: 1} + if desiredSize != nil { + scaling = desiredSize.Div(max.Sub(min)) + } + + for meshindex, m := range doc.Meshes { + for _, p := range m.Primitives { + posAccessor := doc.Accessors[p.Attributes[gltf.POSITION]] + positions, err := gltfVec3(&doc, posAccessor, transformationMatrices[meshindex], scaling) if err != nil { return nil, err } @@ -37,7 +70,7 @@ func LoadGLTF(file io.Reader, desiredSize *Types.Vector) ([]*Types.Mesh, error) var normals []Types.Vector if nIdx, ok := p.Attributes[gltf.NORMAL]; ok { normalAccessor := doc.Accessors[nIdx] - normals, err = gltfVec3(&doc, normalAccessor, Types.Vector{X: 1, Y: 1, Z: 1}) + normals, err = gltfVec3(&doc, normalAccessor, transformationMatrices[meshindex], Types.Vector{X: 1, Y: 1, Z: 1}) if err != nil { return nil, err } @@ -68,14 +101,14 @@ func LoadGLTF(file io.Reader, desiredSize *Types.Vector) ([]*Types.Mesh, error) mesh.AddTriangle(&Types.Triangle{V0: v0, V1: v1, V2: v2}) } - meshes = append(meshes, &mesh) + meshes.Add(&mesh) } } } return meshes, nil } -func gltfVec3(doc *gltf.Document, acc *gltf.Accessor, scaling Types.Vector) ([]Types.Vector, error) { +func gltfVec3(doc *gltf.Document, acc *gltf.Accessor, transformationMatrix Types.Matrix, scaling Types.Vector) ([]Types.Vector, error) { bufView := doc.BufferViews[*acc.BufferView] buffer := doc.Buffers[bufView.Buffer] @@ -87,10 +120,18 @@ func gltfVec3(doc *gltf.Document, acc *gltf.Accessor, scaling Types.Vector) ([]T for i := 0; i < acc.Count; i++ { base := i * 12 // axes inverted to convert to correct coordinate system - x := math.Float32frombits(binary.LittleEndian.Uint32(raw[base+0:])) - y := -(math.Float32frombits(binary.LittleEndian.Uint32(raw[base+8:]))) - z := math.Float32frombits(binary.LittleEndian.Uint32(raw[base+4:])) - vectors[i] = Types.Vector{X: float64(x) * scaling.X, Y: float64(y) * scaling.Y, Z: float64(z) * scaling.Z} + vec := Types.Vector{ + X: float64(math.Float32frombits(binary.LittleEndian.Uint32(raw[base+0:]))), + Y: float64(math.Float32frombits(binary.LittleEndian.Uint32(raw[base+4:]))), + Z: float64(math.Float32frombits(binary.LittleEndian.Uint32(raw[base+8:]))), + } + transformed := transformationMatrix.MulPosition(vec) + scaled := Types.Vector{ + X: transformed.X, + Y: -transformed.Z, + Z: transformed.Y, + }.Mult(scaling) + vectors[i] = scaled // vec.Mult(scaling) } return vectors, nil From bcfabf2b661cc96c8f9e203784a46192bfe9f76d Mon Sep 17 00:00:00 2001 From: Jannik-Hm Date: Tue, 2 Dec 2025 18:29:46 +0100 Subject: [PATCH 3/3] fixed elements in gltf transformation matrix being mixed up --- pkg/file_handlers/gltf.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/file_handlers/gltf.go b/pkg/file_handlers/gltf.go index acafdb1..d5c846e 100644 --- a/pkg/file_handlers/gltf.go +++ b/pkg/file_handlers/gltf.go @@ -25,8 +25,8 @@ func LoadGLTF(file io.Reader, desiredSize *Types.Vector) (*Types.Mesh, error) { matrix := node.MatrixOrDefault() transformationMatrices[*node.Mesh] = Types.Matrix{ X00: matrix[0], X01: matrix[4], X02: matrix[8], X03: matrix[12], - X10: matrix[2], X11: matrix[5], X12: matrix[9], X13: matrix[13], - X20: matrix[1], X21: matrix[6], X22: matrix[10], X23: matrix[14], + X10: matrix[1], X11: matrix[5], X12: matrix[9], X13: matrix[13], + X20: matrix[2], X21: matrix[6], X22: matrix[10], X23: matrix[14], X30: matrix[3], X31: matrix[7], X32: matrix[11], X33: matrix[15], } }