2025-08-06 16:09:32 +03:00

221 lines
6.4 KiB
Go

package main
import (
"bytes"
"encoding/json"
"fmt"
"math/rand/v2"
"os"
"path"
"github.com/gabriel-vasile/mimetype"
"github.com/qmuntal/gltf"
"github.com/qmuntal/gltf/modeler"
"git.influ.su/artmares/digglestool/internal/pkg/logger"
"git.influ.su/artmares/digglestool/internal/services/exporter"
"git.influ.su/artmares/digglestool/pkg/threedb"
)
const (
outputPath = "./models"
texturesCacheFile = "./textures.cache"
)
func main() {
texturesPath := os.Getenv("TEXTURES_PATH")
if texturesPath == "" {
logger.Info("TEXTURES_PATH environment variable not set")
return
}
inputPath := "./data"
inputModel := "produktionsstaetten"
f, err := os.Open(path.Join(inputPath, inputModel+".3db"))
if err != nil {
logger.Fatal(err)
}
defer f.Close()
model := threedb.Model{}
err = threedb.NewDecoder(f).Decode(&model)
if err != nil {
logger.Error(err)
return
}
//log.Printf("DB Version: %v\n", model.DBVersion)
//log.Printf("Name: %v\n", model.Name)
//log.Printf("Materials: %d\n", len(model.Materials))
//for _, material := range model.Materials {
// log.Printf("\t: %v\n", material)
//}
//log.Printf("Meshes: %d\n", len(model.Meshes))
//log.Printf("Objects: %+v\n", model.Objects)
//log.Printf("Animations: %d\n", len(model.Animations))
//for _, animation := range model.Animations {
// log.Printf("\t: %+v\n", animation)
//}
//log.Printf("Triangles: %d\n", len(model.Triangles))
//log.Printf("Texture Coordinates: %d\n", len(model.TextureCoordinates))
//log.Printf("Points: %d\n", len(model.Points))
//log.Printf("Brightness: %d\n", len(model.Brightness))
logFile, err := os.OpenFile(fmt.Sprintf("./%s.json", inputModel), os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
logger.Error(err)
return
}
defer logFile.Close()
enc := json.NewEncoder(logFile)
enc.SetIndent("", " ")
if err = enc.Encode(model); err != nil {
logger.Error(err)
return
}
export := exporter.NewExporter(
exporter.WithTexturesBasePath(texturesPath),
exporter.WithOnlyBaseMesh(),
exporter.WithAnimation(),
)
if err = export.Export(outputPath, &model); err != nil {
logger.Error(err)
return
}
//if err = export(&model, inputModel, texturesCache); err != nil {
// log.Println(err)
// return
//}
}
func exportFn(model *threedb.Model, inputModel string, cache map[string]string) error {
//maxMeshIndex := 133
//meshIndex := randRange(0, len(model.Meshes)-1)
meshIndex := 0
//log.Println("Mesh Index:", meshIndex)
binaryCache := make(map[string][]byte)
//for meshIndex := 0; meshIndex < len(model.Meshes); meshIndex++ {
doc := gltf.NewDocument()
//doc.Materials = []*gltf.Material{{
// Name: "Default", AlphaMode: gltf.AlphaOpaque, AlphaCutoff: gltf.Float(0.5),
// PBRMetallicRoughness: &gltf.PBRMetallicRoughness{BaseColorFactor: &[4]float64{0.8, 0.8, 0.8, 1}, MetallicFactor: gltf.Float(0.1), RoughnessFactor: gltf.Float(0.99)},
//}}
for _, material := range model.Materials {
data, ok := binaryCache[material.Name]
if !ok {
texturePath, ok := cache[material.Name]
if !ok {
logger.Warnf("Invalid texture cache %q", material.Name)
continue
return fmt.Errorf("invalid texture cache %q", material.Name)
}
data, err := os.ReadFile(texturePath)
if err != nil {
return err
}
binaryCache[material.Name] = data
}
mt := mimetype.Detect(data)
if mt == nil {
return fmt.Errorf("can't geting mimetype %q", material.Name)
}
imageIndex, err := modeler.WriteImage(doc, material.Name+".tga", mt.String(), bytes.NewBuffer(data))
if err != nil {
return err
}
doc.Textures = append(doc.Textures, &gltf.Texture{
Name: material.Name,
//Sampler: gltf.Index(0),
Source: gltf.Index(imageIndex),
})
doc.Materials = append(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),
},
})
}
mesh := model.Meshes[meshIndex]
for _, meshLink := range mesh.Links {
triangles := model.Triangles[meshLink.Triangles]
points := model.Points[meshLink.Points]
textureCoordinates := model.TextureCoordinates[meshLink.TextureCoordinates]
material := model.Materials[meshLink.Material]
var vertices [][3]float32
var mins []float64
var maxs []float64
for _, point := range points {
vec := point.Transform(100)
vec = vec.Normalize()
vertices = append(vertices, vec)
mins = append(mins, float64(vec.Min()))
maxs = append(maxs, float64(vec.Max()))
}
verticesIndex := modeler.WriteAccessor(doc, gltf.TargetElementArrayBuffer, vertices)
var textureCoords [][2]float32
for _, txc := range textureCoordinates {
textureCoords = append(textureCoords, txc)
}
textureIndex := modeler.WriteAccessor(doc, gltf.TargetArrayBuffer, textureCoords)
trianglesIndex := modeler.WriteAccessor(doc, gltf.TargetArrayBuffer, triangles)
materialIndex := len(doc.Materials)
doc.Meshes = append(doc.Meshes, &gltf.Mesh{
Name: fmt.Sprintf("%s-%d", model.Name, len(doc.Meshes)),
Primitives: []*gltf.Primitive{{
Attributes: gltf.PrimitiveAttributes{
gltf.POSITION: verticesIndex,
gltf.TEXCOORD_0: textureIndex,
},
Indices: gltf.Index(trianglesIndex),
Material: gltf.Index(materialIndex),
}},
})
//imageIndex, err := modeler.WriteImage(doc)
doc.Materials = append(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),
},
})
doc.Nodes = append(doc.Nodes, &gltf.Node{
Mesh: gltf.Index(len(doc.Meshes) - 1),
})
}
var nodes []int
for index := range doc.Nodes {
nodes = append(nodes, index)
}
doc.Scenes = []*gltf.Scene{
{Name: "Root Scene", Nodes: nodes},
}
if err := gltf.Save(doc, path.Join(outputPath, fmt.Sprintf("%s-%d.gltf", inputModel, meshIndex))); err != nil {
return err
}
//if err := gltf.SaveBinary(doc, fmt.Sprintf("./%s.glb", inputModel)); err != nil {
// return err
//}
//}
return nil
}
func randRange(min, max int) int {
return rand.IntN(max-min) + min
}