stl2gltf/convert.go

140 lines
3.6 KiB
Go
Raw Normal View History

2024-06-05 01:43:08 +08:00
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)
2024-06-06 14:55:35 +08:00
// padding each buffer part
2024-06-05 01:43:08 +08:00
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
}
2024-06-06 14:55:35 +08:00
// positions to byte
2024-06-05 01:43:08 +08:00
for i := range stl.TriangleNum {
t := stl.Triangles[i]
positionBuf = append(positionBuf, t.Position...)
}
positionBuf = padding(positionBuf)
2024-06-06 14:55:35 +08:00
// normals to byte
2024-06-05 01:43:08 +08:00
for i := range stl.TriangleNum {
t := stl.Triangles[i]
2024-06-06 14:55:35 +08:00
// each position, write 3 times
2024-06-05 01:43:08 +08:00
normalBuf = append(normalBuf, t.Normal...)
normalBuf = append(normalBuf, t.Normal...)
normalBuf = append(normalBuf, t.Normal...)
}
normalBuf = padding(normalBuf)
2024-06-06 14:55:35 +08:00
// indices to byte
2024-06-05 01:43:08 +08:00
for i := range stl.TriangleNum * 3 {
2024-06-06 02:17:06 +08:00
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, uint32(i))
2024-06-05 01:43:08 +08:00
indexBuf = append(indexBuf, buf...)
}
indexBuf = padding(indexBuf)
log.Println(len(positionBuf), len(normalBuf), len(indexBuf))
2024-06-06 14:55:35 +08:00
// concat
2024-06-05 01:43:08 +08:00
allData := make([]byte, 0)
2024-06-06 14:55:35 +08:00
allData = append(allData, indexBuf...) // Indices: 0
allData = append(allData, normalBuf...) // attributes["NORMAL"] = 1
allData = append(allData, positionBuf...) // attributes["POSITION"] = 2
2024-06-05 01:43:08 +08:00
base := base64.StdEncoding.EncodeToString(allData)
attributes := make(map[string]int, 0)
2024-06-06 02:26:04 +08:00
attributes["NORMAL"] = 1
2024-06-06 14:55:35 +08:00
attributes["POSITION"] = 2
2024-06-05 01:43:08 +08:00
gltf := GLTF{
Asset: Asset{Version: "2.0"},
Scenes: []Scene{{Nodes: []int{0}}},
Nodes: []Node{{Mesh: 0}},
2024-06-06 02:17:06 +08:00
Meshes: []Mesh{{Primitives: []Primitive{{Attributes: attributes, Indices: 0, Mode: 4}}}},
2024-06-06 14:55:35 +08:00
// ByteLength not length after base64
2024-06-05 01:43:08 +08:00
Buffers: []Buffer{{Uri: fmt.Sprintf("data:application/gltf-buffer;base64,%s", base), ByteLength: len(allData)}},
BufferViews: []BufferView{
2024-06-06 02:17:06 +08:00
// index
2024-06-05 01:43:08 +08:00
{
Buffer: 0,
ByteOffset: 0,
2024-06-06 02:17:06 +08:00
ByteLength: len(indexBuf),
2024-06-06 14:55:35 +08:00
Target: 34963, // ELEMENT_ARRAY_BUFFER float indices
2024-06-05 01:43:08 +08:00
},
// normal
{
Buffer: 0,
2024-06-06 02:17:06 +08:00
ByteOffset: len(indexBuf),
2024-06-06 02:26:04 +08:00
ByteLength: len(normalBuf),
2024-06-06 14:55:35 +08:00
Target: 34962, // ARRAY_BUFFER int vertex
2024-06-06 02:26:04 +08:00
},
// position
{
Buffer: 0,
ByteOffset: len(indexBuf) + len(normalBuf),
2024-06-06 02:17:06 +08:00
ByteLength: len(positionBuf),
2024-06-06 14:55:35 +08:00
Target: 34962, // ARRAY_BUFFER int vertex
2024-06-05 01:43:08 +08:00
},
},
Accessors: []Accessor{
{
BufferView: 0,
ByteOffset: 0,
2024-06-06 14:55:35 +08:00
ComponentType: 5125, // uint ; 5124 int will loss model parts
Type: "SCALAR", // index
Count: stl.TriangleNum * 3, // 1 index : 1 position
2024-06-05 01:43:08 +08:00
},
{
BufferView: 1,
ByteOffset: 0,
2024-06-06 14:55:35 +08:00
ComponentType: 5126, // float
2024-06-05 01:43:08 +08:00
Type: "VEC3",
2024-06-06 14:55:35 +08:00
Count: stl.TriangleNum * 3, // 1 normal : 1 position
Max: []float32{1, 1, 1}, // or cal from stl data
2024-06-06 02:26:04 +08:00
Min: []float32{-1, -1, -1},
},
{
BufferView: 2,
ByteOffset: 0,
2024-06-06 14:55:35 +08:00
ComponentType: 5126, // float
2024-06-06 02:26:04 +08:00
Type: "VEC3",
2024-06-06 14:55:35 +08:00
Count: len(positionBuf) / 12,// xyz = 4x3; or stl.TriangleNum * 3
Max: stl.Max, // cal from stl data
2024-06-06 02:17:06 +08:00
Min: stl.Min,
2024-06-05 01:43:08 +08:00
},
},
}
2024-06-06 14:55:35 +08:00
// or not indent
2024-06-05 01:43:08 +08:00
data, err := json.MarshalIndent(gltf, " ", " ")
if err != nil {
log.Println("marshal error: ", err.Error())
return
}
2024-06-06 14:55:35 +08:00
// output
2024-06-05 01:43:08 +08:00
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)
}