sss
This commit is contained in:
commit
37cdc242d9
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch Package",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${fileDirname}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.dengqn.com/dqn/stl2gltf"
|
||||||
|
)
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
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 := func(buf []byte) []byte {
|
||||||
|
log.Println("padding: ", len(buf)%4)
|
||||||
|
for len(buf)%4 != 0 {
|
||||||
|
log.Println("padding")
|
||||||
|
buf = append(buf, 0x00)
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入顶点
|
||||||
|
for i := range stl.TriangleNum {
|
||||||
|
t := stl.Triangles[i]
|
||||||
|
positionBuf = append(positionBuf, t.Position...)
|
||||||
|
}
|
||||||
|
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 stl.TriangleNum * 3 {
|
||||||
|
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, normalBuf...)
|
||||||
|
allData = append(allData, indexBuf...)
|
||||||
|
|
||||||
|
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: 2, 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),
|
||||||
|
ByteLength: len(indexBuf),
|
||||||
|
Target: 34963,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Accessors: []Accessor{
|
||||||
|
{
|
||||||
|
BufferView: 0,
|
||||||
|
ByteOffset: 0,
|
||||||
|
ComponentType: 5126,
|
||||||
|
Type: "VEC3",
|
||||||
|
Count: len(positionBuf) / 12,
|
||||||
|
Max: stl.Max,
|
||||||
|
Min: stl.Min,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package stl2gltf
|
||||||
|
|
||||||
|
// Triangle 50B
|
||||||
|
type Triangle struct {
|
||||||
|
Normal []byte // 4 * 3 12
|
||||||
|
Position []byte // 4 * 3 * 3 36
|
||||||
|
Attribute []byte // 2 02
|
||||||
|
}
|
||||||
|
|
||||||
|
type STL struct {
|
||||||
|
Header string
|
||||||
|
TriangleNum int
|
||||||
|
Triangles []Triangle
|
||||||
|
|
||||||
|
Max []float32
|
||||||
|
Min []float32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Asset struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Scene struct {
|
||||||
|
Nodes []int `json:"nodes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
Mesh int `json:"mesh"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Primitive struct {
|
||||||
|
Attributes map[string]int `json:"attributes"`
|
||||||
|
Indices int `json:"indices"`
|
||||||
|
Mode int `json:"mode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mesh struct {
|
||||||
|
Primitives []Primitive `json:"primitives"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Buffer struct {
|
||||||
|
Uri string `json:"uri"`
|
||||||
|
ByteLength int `json:"byteLength"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BufferView struct {
|
||||||
|
Buffer int `json:"buffer"`
|
||||||
|
ByteOffset int `json:"byteOffset"`
|
||||||
|
ByteLength int `json:"byteLength"`
|
||||||
|
Target int `json:"target"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Accessor struct {
|
||||||
|
BufferView int `json:"bufferView"`
|
||||||
|
ByteOffset int `json:"byteOffset"`
|
||||||
|
ComponentType int `json:"componentType"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Max []float32 `json:"max,omitempty"`
|
||||||
|
Min []float32 `json:"min,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GLTF struct {
|
||||||
|
Asset Asset `json:"asset"`
|
||||||
|
|
||||||
|
Scenes []Scene `json:"scenes"`
|
||||||
|
|
||||||
|
Nodes []Node `json:"nodes"`
|
||||||
|
|
||||||
|
Meshes []Mesh `json:"meshes"`
|
||||||
|
|
||||||
|
Buffers []Buffer `json:"buffers"`
|
||||||
|
|
||||||
|
BufferViews []BufferView `json:"bufferViews"`
|
||||||
|
|
||||||
|
Accessors []Accessor `json:"accessors"`
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,72 @@
|
||||||
|
package stl2gltf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Load(filePath string) (stl STL) {
|
||||||
|
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.Triangles = make([]Triangle, 0)
|
||||||
|
|
||||||
|
max := []float32{0, 0, 0}
|
||||||
|
min := []float32{0, 0, 0}
|
||||||
|
for range stl.TriangleNum {
|
||||||
|
normalBuf := make([]byte, 4*3)
|
||||||
|
file.Read(normalBuf)
|
||||||
|
|
||||||
|
positionBuf := make([]byte, 4*3*3)
|
||||||
|
file.Read(positionBuf)
|
||||||
|
|
||||||
|
for r := range 3 {
|
||||||
|
x := math.Float32frombits(binary.LittleEndian.Uint32(positionBuf[:4+(r*4)]))
|
||||||
|
y := math.Float32frombits(binary.LittleEndian.Uint32(positionBuf[(r * 4) : (r*4)+4]))
|
||||||
|
z := math.Float32frombits(binary.LittleEndian.Uint32(positionBuf[(r*4)+4 : (r*4)+8]))
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeBuf := make([]byte, 2)
|
||||||
|
file.Read(attributeBuf)
|
||||||
|
|
||||||
|
stl.Triangles = append(stl.Triangles, Triangle{
|
||||||
|
Normal: normalBuf,
|
||||||
|
Position: positionBuf,
|
||||||
|
Attribute: attributeBuf,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
stl.Max = max
|
||||||
|
stl.Min = min
|
||||||
|
|
||||||
|
return stl
|
||||||
|
}
|
Loading…
Reference in New Issue