168 lines
3.9 KiB
Go
168 lines
3.9 KiB
Go
|
package stl2gltf
|
||
|
|
||
|
import (
|
||
|
"encoding/base64"
|
||
|
"encoding/binary"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
)
|
||
|
|
||
|
func Convert2(stl STL2, outFile string) {
|
||
|
// buf
|
||
|
indexBuf := make([]byte, 0)
|
||
|
normalBuf := make([]byte, 0)
|
||
|
positionBuf := make([]byte, 0)
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
uniquePositions := make([][3]uint32, 0)
|
||
|
indices := make([]int16, len(stl.Positions))
|
||
|
for i := 0; i < len(stl.Positions); i++ {
|
||
|
position := stl.Positions[i]
|
||
|
// if in uniqt
|
||
|
found := false
|
||
|
for u, ut := range uniquePositions {
|
||
|
if ut[0] == position[0] && ut[1] == position[1] && ut[2] == position[2] {
|
||
|
// exist
|
||
|
indices[i] = int16(u)
|
||
|
found = true
|
||
|
}
|
||
|
}
|
||
|
if !found {
|
||
|
uniquePositions = append(uniquePositions, position)
|
||
|
indices[i] = int16(len(uniquePositions) - 1)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 写入顶点
|
||
|
for _, ip := range uniquePositions {
|
||
|
buf := make([]byte, 0)
|
||
|
buf = binary.LittleEndian.AppendUint32(buf, uint32(ip[0]))
|
||
|
buf = binary.LittleEndian.AppendUint32(buf, uint32(ip[1]))
|
||
|
buf = binary.LittleEndian.AppendUint32(buf, uint32(ip[2]))
|
||
|
positionBuf = append(positionBuf, buf...)
|
||
|
}
|
||
|
positionBuf = padding(positionBuf)
|
||
|
|
||
|
// 写入法向量
|
||
|
// for i := range stl.TriangleNum {
|
||
|
// t := stl.Triangles[i]
|
||
|
// normalBuf = append(normalBuf, t.Normal...)
|
||
|
// normalBuf = append(normalBuf, t.Normal...)
|
||
|
// normalBuf = append(normalBuf, t.Normal...)
|
||
|
// }
|
||
|
normalBuf = padding(normalBuf)
|
||
|
// 写入索引
|
||
|
for i := range indices {
|
||
|
buf := make([]byte, 2)
|
||
|
binary.LittleEndian.PutUint16(buf, uint16(i))
|
||
|
indexBuf = append(indexBuf, buf...)
|
||
|
}
|
||
|
indexBuf = padding(indexBuf)
|
||
|
|
||
|
log.Println(len(positionBuf), len(normalBuf), len(indexBuf))
|
||
|
|
||
|
allData := make([]byte, 0)
|
||
|
allData = append(allData, positionBuf...)
|
||
|
allData = append(allData, indexBuf...)
|
||
|
// allData = append(allData, normalBuf...)
|
||
|
|
||
|
base := base64.StdEncoding.EncodeToString(allData)
|
||
|
|
||
|
attributes := make(map[string]int, 0)
|
||
|
attributes["POSITION"] = 0
|
||
|
// attributes["NORMAL"] = 1
|
||
|
|
||
|
gltf := GLTF{
|
||
|
Asset: Asset{Version: "2.0"},
|
||
|
Scenes: []Scene{{Nodes: []int{0}}},
|
||
|
Nodes: []Node{{Mesh: 0}},
|
||
|
Meshes: []Mesh{{Primitives: []Primitive{{Attributes: attributes, Indices: 1, Mode: 4}}}},
|
||
|
Buffers: []Buffer{{Uri: fmt.Sprintf("data:application/gltf-buffer;base64,%s", base), ByteLength: len(allData)}},
|
||
|
BufferViews: []BufferView{
|
||
|
// index
|
||
|
|
||
|
// normal
|
||
|
// {
|
||
|
// Buffer: 0,
|
||
|
// ByteOffset: len(indexBuf),
|
||
|
// ByteLength: len(normalBuf),
|
||
|
// Target: 34962,
|
||
|
// },
|
||
|
// position
|
||
|
{
|
||
|
Buffer: 0,
|
||
|
ByteOffset: 0,
|
||
|
// ByteOffset: len(indexBuf) + len(normalBuf),
|
||
|
ByteLength: len(positionBuf),
|
||
|
Target: 34962,
|
||
|
},
|
||
|
{
|
||
|
Buffer: 0,
|
||
|
ByteOffset: len(positionBuf),
|
||
|
ByteLength: len(indexBuf),
|
||
|
Target: 34963,
|
||
|
},
|
||
|
},
|
||
|
Accessors: []Accessor{
|
||
|
|
||
|
// {
|
||
|
// BufferView: 1,
|
||
|
// ByteOffset: 0,
|
||
|
// ComponentType: 5126,
|
||
|
// Type: "VEC3",
|
||
|
// Count: int(stl.TriangleNum),
|
||
|
// // Max: []float32{1, 1, 1},
|
||
|
// // Min: []float32{-1, -1, -1},
|
||
|
// },
|
||
|
{
|
||
|
BufferView: 0,
|
||
|
ByteOffset: 0,
|
||
|
ComponentType: 5126,
|
||
|
Type: "VEC3",
|
||
|
Count: len(positionBuf) / 12,
|
||
|
Max: f2i(stl.Max),
|
||
|
Min: f2i(stl.Min),
|
||
|
},
|
||
|
{
|
||
|
BufferView: 1,
|
||
|
ByteOffset: 0,
|
||
|
ComponentType: 5123,
|
||
|
Type: "SCALAR",
|
||
|
Count: stl.TriangleNum,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
data, err := json.MarshalIndent(gltf, " ", " ")
|
||
|
if err != nil {
|
||
|
log.Println("marshal error: ", err.Error())
|
||
|
return
|
||
|
}
|
||
|
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)
|
||
|
}
|
||
|
|
||
|
func f2i(p []uint32) []float32 {
|
||
|
a := make([]float32, len(p))
|
||
|
for i := 0; i < len(p); i++ {
|
||
|
a[i] = float32(p[i])
|
||
|
}
|
||
|
return a
|
||
|
}
|