This commit is contained in:
dengqn 2024-06-06 02:17:06 +08:00
parent 37cdc242d9
commit 4cf895656d
7 changed files with 315 additions and 38 deletions

View File

@ -7,7 +7,14 @@ import (
func main() {
stl := stl2gltf.Load("D:\\src\\go\\stl2gltf\\example\\0c448109-7ac9-4f6d-aaf6-ce6bb744032f.stl")
// log.Println(stl)
stl2gltf.Convert(stl, "C:\\Users\\13040\\Downloads\\0c448109-7ac9-4f6d-aaf6-ce6bb744032f.gltf")
// stl = stl2gltf.Load("D:\\src\\go\\stl2gltf\\example\\1ec91891-c25a-4905-a79c-f3bc96045d37.stl")
// // log.Println(stl)
// stl2gltf.Convert(stl, "C:\\Users\\13040\\Downloads\\1ec91891-c25a-4905-a79c-f3bc96045d37.gltf")
// stl = stl2gltf.Load("D:\\src\\go\\stl2gltf\\example\\3ea057e5-1520-4898-a59c-f33a6c955bd7.stl")
// // log.Println(stl)
// stl2gltf.Convert(stl, "C:\\Users\\13040\\Downloads\\3ea057e5-1520-4898-a59c-f33a6c955bd7.gltf")
}

View File

@ -41,8 +41,8 @@ func Convert(stl STL, outFile string) {
normalBuf = padding(normalBuf)
// 写入索引
for i := range stl.TriangleNum * 3 {
buf := make([]byte, 2)
binary.LittleEndian.PutUint16(buf, uint16(i))
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, uint32(i))
indexBuf = append(indexBuf, buf...)
}
indexBuf = padding(indexBuf)
@ -50,70 +50,72 @@ func Convert(stl STL, outFile string) {
log.Println(len(positionBuf), len(normalBuf), len(indexBuf))
allData := make([]byte, 0)
allData = append(allData, positionBuf...)
allData = append(allData, normalBuf...)
allData = append(allData, indexBuf...)
// allData = append(allData, normalBuf...)
allData = append(allData, positionBuf...)
base := base64.StdEncoding.EncodeToString(allData)
attributes := make(map[string]int, 0)
attributes["POSITION"] = 0
attributes["NORMAL"] = 1
attributes["POSITION"] = 1
// 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: 2, Mode: 4}}}},
Meshes: []Mesh{{Primitives: []Primitive{{Attributes: attributes, Indices: 0, Mode: 4}}}},
Buffers: []Buffer{{Uri: fmt.Sprintf("data:application/gltf-buffer;base64,%s", base), ByteLength: len(allData)}},
BufferViews: []BufferView{
// position
{
Buffer: 0,
ByteOffset: 0,
ByteLength: len(positionBuf),
Target: 34962,
},
// normal
{
Buffer: 0,
ByteOffset: len(positionBuf),
ByteLength: len(normalBuf),
Target: 34962,
},
// index
{
Buffer: 0,
ByteOffset: len(positionBuf) + len(normalBuf),
ByteOffset: 0,
ByteLength: len(indexBuf),
Target: 34963,
},
// normal
// {
// Buffer: 0,
// ByteOffset: len(indexBuf),
// ByteLength: len(normalBuf),
// Target: 34962,
// },
// position
{
Buffer: 0,
ByteOffset: len(indexBuf),
// ByteOffset: len(indexBuf) + len(normalBuf),
ByteLength: len(positionBuf),
Target: 34962,
},
},
Accessors: []Accessor{
{
BufferView: 0,
ByteOffset: 0,
ComponentType: 5126,
Type: "VEC3",
Count: len(positionBuf) / 12,
Max: stl.Max,
Min: stl.Min,
ComponentType: 5125,
Type: "SCALAR",
Count: stl.TriangleNum * 3,
},
// {
// BufferView: 1,
// ByteOffset: 0,
// ComponentType: 5126,
// Type: "VEC3",
// Count: int(stl.TriangleNum),
// // Max: []float32{1, 1, 1},
// // Min: []float32{-1, -1, -1},
// },
{
BufferView: 1,
ByteOffset: 0,
ComponentType: 5126,
Type: "VEC3",
Count: int(stl.TriangleNum),
// Max: []float32{1, 1, 1},
// Min: []float32{-1, -1, -1},
},
{
BufferView: 2,
ByteOffset: 0,
ComponentType: 5123,
Type: "SCALAR",
Count: stl.TriangleNum,
Count: len(positionBuf) / 12,
Max: stl.Max,
Min: stl.Min,
},
},
}

167
convert2.go Normal file
View File

@ -0,0 +1,167 @@
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
}

33
data.go
View File

@ -1,10 +1,26 @@
package stl2gltf
import "encoding/binary"
// Triangle 50B
type Triangle struct {
Normal []byte // 4 * 3 12
Position []byte // 4 * 3 * 3 36
Attribute []byte // 2 02
XYZ []float32
}
func (t Triangle) EuqalsPosition(position []byte) bool {
x1 := binary.LittleEndian.Uint32(position[:4])
y1 := binary.LittleEndian.Uint32(position[4:8])
z1 := binary.LittleEndian.Uint32(position[8:12])
x2 := binary.LittleEndian.Uint32(t.Position[:4])
y2 := binary.LittleEndian.Uint32(t.Position[4:8])
z2 := binary.LittleEndian.Uint32(t.Position[8:12])
return x1 == x2 && y1 == y2 && z1 == z2
}
type STL struct {
@ -16,6 +32,23 @@ type STL struct {
Min []float32
}
type Triangle2 struct {
Normal []byte // 4 * 3 12
Position [][3]float32 // 4 * 3 * 3 36
Attribute []byte // 2 02
XYZ []float32
}
type STL2 struct {
Header string
TriangleNum int
Positions [][3]uint32
Max []uint32
Min []uint32
}
type Asset struct {
Version string `json:"version"`
}

Binary file not shown.

Binary file not shown.

68
load.go
View File

@ -70,3 +70,71 @@ func Load(filePath string) (stl STL) {
return stl
}
func Load2(filePath string) (stl STL2) {
file, err := os.OpenFile(filePath, os.O_RDONLY, os.ModePerm)
if err != nil {
log.Panic("open file " + filePath + " error: " + err.Error())
}
headerBuf := make([]byte, 80)
file.Read(headerBuf)
triangleNumBuf := make([]byte, 4)
file.Read(triangleNumBuf)
stl.Header = string(headerBuf)
stl.TriangleNum = int(binary.LittleEndian.Uint32(triangleNumBuf))
stl.Positions = make([][3]uint32, 0)
max := []uint32{0, 0, 0}
min := []uint32{0, 0, 0}
for range stl.TriangleNum {
normalBuf := make([]byte, 4*3)
file.Read(normalBuf)
positionBuf := make([]byte, 4*3*3)
file.Read(positionBuf)
x := uint32(0)
y := uint32(0)
z := uint32(0)
for r := range 3 {
x1 := math.Float32frombits(binary.LittleEndian.Uint32(positionBuf[:4+(r*4)]))
y1 := math.Float32frombits(binary.LittleEndian.Uint32(positionBuf[(r * 4) : (r*4)+4]))
z1 := math.Float32frombits(binary.LittleEndian.Uint32(positionBuf[(r*4)+4 : (r*4)+8]))
// x = uint32(x1) * 10000 / 10000
// y = uint32(y1) * 10000 / 10000
// z = uint32(z1) * 10000 / 10000
x = uint32(x1) * 1 / 1
y = uint32(y1) * 1 / 1
z = uint32(z1) * 1 / 1
if max[0] < x {
max[0] = x
}
if max[1] < y {
max[1] = y
}
if max[2] < z {
max[2] = z
}
if min[0] > x {
min[0] = x
}
if min[1] > y {
min[1] = y
}
if min[2] > z {
min[2] = z
}
stl.Positions = append(stl.Positions, [3]uint32{x, y, z})
}
attributeBuf := make([]byte, 2)
file.Read(attributeBuf)
}
stl.Max = max
stl.Min = min
return stl
}