package stl2gltf import ( "encoding/base64" "encoding/binary" "encoding/json" "fmt" "log" "os" ) func Convert(stl STL, outFile string) { // buf indexBuf := make([]byte, 0) normalBuf := make([]byte, 0) positionBuf := make([]byte, 0) // padding each buffer part padding := func(buf []byte) []byte { log.Println("padding: ", len(buf)%4) for len(buf)%4 != 0 { log.Println("padding") buf = append(buf, 0x00) } return buf } // positions to byte for i := range stl.TriangleNum { t := stl.Triangles[i] positionBuf = append(positionBuf, t.Position...) } positionBuf = padding(positionBuf) // normals to byte for i := range stl.TriangleNum { t := stl.Triangles[i] // each position, write 3 times normalBuf = append(normalBuf, t.Normal...) normalBuf = append(normalBuf, t.Normal...) normalBuf = append(normalBuf, t.Normal...) } normalBuf = padding(normalBuf) // indices to byte for i := range stl.TriangleNum * 3 { buf := make([]byte, 4) binary.LittleEndian.PutUint32(buf, uint32(i)) indexBuf = append(indexBuf, buf...) } indexBuf = padding(indexBuf) log.Println("positions: ", len(positionBuf), " normals: ", len(normalBuf), " indices: ", len(indexBuf)) // concat allData := make([]byte, 0) allData = append(allData, indexBuf...) // Indices: 0 allData = append(allData, normalBuf...) // attributes["NORMAL"] = 1 allData = append(allData, positionBuf...) // attributes["POSITION"] = 2 base := base64.StdEncoding.EncodeToString(allData) attributes := make(map[string]int, 0) attributes["NORMAL"] = 1 attributes["POSITION"] = 2 gltf := GLTF{ Asset: Asset{Version: "2.0"}, Scenes: []Scene{{Nodes: []int{0}}}, Nodes: []Node{{Mesh: 0}}, Meshes: []Mesh{{Primitives: []Primitive{{Attributes: attributes, Indices: 0, Mode: 4}}}}, // ByteLength not length after base64 Buffers: []Buffer{{Uri: fmt.Sprintf("data:application/gltf-buffer;base64,%s", base), ByteLength: len(allData)}}, BufferViews: []BufferView{ // index { Buffer: 0, ByteOffset: 0, ByteLength: len(indexBuf), Target: 34963, // ELEMENT_ARRAY_BUFFER float indices }, // normal { Buffer: 0, ByteOffset: len(indexBuf), ByteLength: len(normalBuf), Target: 34962, // ARRAY_BUFFER int vertex }, // position { Buffer: 0, ByteOffset: len(indexBuf) + len(normalBuf), ByteLength: len(positionBuf), Target: 34962, // ARRAY_BUFFER int vertex }, }, Accessors: []Accessor{ { BufferView: 0, ByteOffset: 0, ComponentType: 5125, // uint ; 5124 int will loss model parts Type: "SCALAR", // index Count: stl.TriangleNum * 3, // 1 index : 1 position }, { BufferView: 1, ByteOffset: 0, ComponentType: 5126, // float Type: "VEC3", Count: stl.TriangleNum * 3, // 1 normal : 1 position Max: []float32{1, 1, 1}, // or cal from stl data Min: []float32{-1, -1, -1}, }, { BufferView: 2, ByteOffset: 0, ComponentType: 5126, // float Type: "VEC3", Count: len(positionBuf) / 12, // xyz = 4x3; or stl.TriangleNum * 3 Max: stl.Max, // cal from stl data Min: stl.Min, }, }, } // or not indent data, err := json.MarshalIndent(gltf, " ", " ") if err != nil { log.Println("marshal error: ", err.Error()) return } // output os.Remove(outFile) f, err := os.OpenFile(outFile, os.O_CREATE, os.ModePerm) if err != nil { log.Println("write file error: ", err.Error()) return } defer f.Close() f.Write(data) }