142 lines
4.3 KiB
Go
142 lines
4.3 KiB
Go
package exporter
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"image"
|
|
"image/png"
|
|
"log"
|
|
"os"
|
|
|
|
_ "github.com/ftrvxmtrx/tga"
|
|
"github.com/qmuntal/gltf"
|
|
"github.com/qmuntal/gltf/modeler"
|
|
|
|
"git.influ.su/artmares/digglestool/pkg/threedb"
|
|
)
|
|
|
|
type Model struct {
|
|
doc *gltf.Document
|
|
materialMap map[uint16]int
|
|
}
|
|
|
|
func (m *Model) Generate(model *threedb.Model, cache *Cache[*CacheItem], meshIndexes ...int) (*gltf.Document, error) {
|
|
m.doc = gltf.NewDocument()
|
|
m.doc.Scenes = []*gltf.Scene{}
|
|
m.materialMap = make(map[uint16]int)
|
|
log.Println("Generate use mesh indexes", len(meshIndexes))
|
|
for i, meshIndex := range meshIndexes {
|
|
mesh := model.Meshes[meshIndex]
|
|
var nodeIndexes []int
|
|
for index, link := range mesh.Links {
|
|
materialIndex, err := m.materialIndex(model, cache, link.Material)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
verticesIndex := m.generateVertices(model.Points[link.Points])
|
|
textureCoordIndex := m.generateTextureCoordinate(model.TextureCoordinates[link.TextureCoordinates])
|
|
trianglesIndex := modeler.WriteAccessor(m.doc, gltf.TargetArrayBuffer, model.Triangles[link.Triangles])
|
|
m.doc.Meshes = append(m.doc.Meshes, &gltf.Mesh{
|
|
Name: fmt.Sprintf("%s-%d-%d", model.Name, i, index),
|
|
Primitives: []*gltf.Primitive{{
|
|
Attributes: gltf.PrimitiveAttributes{
|
|
gltf.POSITION: verticesIndex,
|
|
gltf.TEXCOORD_0: textureCoordIndex,
|
|
},
|
|
Indices: gltf.Index(trianglesIndex),
|
|
Material: gltf.Index(materialIndex),
|
|
}},
|
|
})
|
|
nodeIndexes = append(nodeIndexes, len(m.doc.Nodes))
|
|
m.doc.Nodes = append(m.doc.Nodes, &gltf.Node{
|
|
Mesh: gltf.Index(len(m.doc.Meshes) - 1),
|
|
})
|
|
}
|
|
m.doc.Scenes = append(m.doc.Scenes, &gltf.Scene{
|
|
Name: fmt.Sprintf("Root Scene-%d", meshIndex),
|
|
Nodes: nodeIndexes,
|
|
})
|
|
}
|
|
m.doc.Samplers = []*gltf.Sampler{{}}
|
|
return m.doc, nil
|
|
}
|
|
|
|
func (m *Model) generateVertices(vectors []threedb.Vector) int {
|
|
var vertices [][3]float32
|
|
for _, vector := range vectors {
|
|
vector = vector.Transform(100)
|
|
vertices = append(vertices, vector.Normalize())
|
|
}
|
|
|
|
return modeler.WriteAccessor(m.doc, gltf.TargetElementArrayBuffer, vertices)
|
|
}
|
|
|
|
func (m *Model) generateTextureCoordinate(coordinates []threedb.Coordinate) int {
|
|
var coords [][2]float32
|
|
for _, coordinate := range coordinates {
|
|
coords = append(coords, coordinate)
|
|
}
|
|
return modeler.WriteAccessor(m.doc, gltf.TargetArrayBuffer, coords)
|
|
}
|
|
|
|
func (m *Model) materialIndex(model *threedb.Model, cache *Cache[*CacheItem], meshMaterialIndex uint16) (int, error) {
|
|
//logger, logPutter := helpers.NewBuffer()
|
|
//defer func() {
|
|
// logPutter(logger)
|
|
//}()
|
|
materialIndex, ok := m.materialMap[meshMaterialIndex]
|
|
//logger.WriteString(fmt.Sprintf("Try find material index %d\n", meshMaterialIndex))
|
|
if !ok {
|
|
//logger.WriteString(fmt.Sprintf("Material index %d not found\n", meshMaterialIndex))
|
|
material := model.Materials[meshMaterialIndex]
|
|
item, ok := cache.Get(material.Name)
|
|
if !ok {
|
|
return 0, nil
|
|
}
|
|
//logger.WriteString(fmt.Sprintf("Try found material name %s\n", material.Name))
|
|
if item.Bytes == nil {
|
|
//logger.WriteString(fmt.Sprintf("Material name %s not found in cache\n", material.Name))
|
|
f, err := os.Open(item.Path)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer f.Close()
|
|
img, _, err := image.Decode(f)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
item.Bytes = &bytes.Buffer{}
|
|
if err = png.Encode(item.Bytes, img); err != nil {
|
|
return 0, err
|
|
}
|
|
cache.Set(material.Name, item)
|
|
}
|
|
//log.Printf("material index: %d, material name: %s, data: %d", meshMaterialIndex, material.Name, len(data))
|
|
imageIndex, err := modeler.WriteImage(m.doc, material.Name, "image/png", item.Bytes)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
m.doc.Textures = append(m.doc.Textures, &gltf.Texture{
|
|
Name: material.Name,
|
|
Sampler: gltf.Index(0),
|
|
Source: gltf.Index(imageIndex),
|
|
})
|
|
materialIndex = len(m.doc.Materials)
|
|
m.doc.Materials = append(m.doc.Materials, &gltf.Material{
|
|
Name: material.Name,
|
|
AlphaMode: gltf.AlphaOpaque,
|
|
AlphaCutoff: gltf.Float(0.5),
|
|
PBRMetallicRoughness: &gltf.PBRMetallicRoughness{
|
|
BaseColorTexture: &gltf.TextureInfo{Index: imageIndex},
|
|
BaseColorFactor: &[4]float64{0.8, 0.8, 0.8, 1},
|
|
MetallicFactor: gltf.Float(0.1),
|
|
RoughnessFactor: gltf.Float(0.99),
|
|
},
|
|
})
|
|
m.materialMap[meshMaterialIndex] = materialIndex
|
|
}
|
|
//log.Println(logger.String())
|
|
|
|
return materialIndex, nil
|
|
}
|