package stl2gltf import ( "encoding/binary" "encoding/json" "log" "os" ) func ConvertGLB(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 { for len(buf)%4 != 0 { 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{{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, }, }, } // 生成glb outBuf := make([]byte, 0) jsonChunkBuf := make([]byte, 0) jsonData, err := json.Marshal(gltf) if err != nil { log.Println("marshal error: ", err.Error()) return } jsonChunkBuf = binary.LittleEndian.AppendUint32(jsonChunkBuf, uint32(len(jsonData))) jsonChunkBuf = binary.LittleEndian.AppendUint32(jsonChunkBuf, uint32(0x4E4F534A)) jsonChunkBuf = append(jsonChunkBuf, jsonData...) binChunkBuf := make([]byte, 0) binChunkBuf = binary.LittleEndian.AppendUint32(binChunkBuf, uint32(len(allData))) binChunkBuf = binary.LittleEndian.AppendUint32(binChunkBuf, uint32(0x004E4942)) binChunkBuf = append(binChunkBuf, allData...) outBuf = binary.LittleEndian.AppendUint32(outBuf, uint32(0x46546C67)) outBuf = binary.LittleEndian.AppendUint32(outBuf, uint32(2)) outBuf = binary.LittleEndian.AppendUint32(outBuf, uint32(12+len(jsonChunkBuf)+len(binChunkBuf))) outBuf = append(outBuf, jsonChunkBuf...) outBuf = append(outBuf, binChunkBuf...) // 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(outBuf) }