Skip to content

Commit

Permalink
Updating gltf loader.
Browse files Browse the repository at this point in the history
It will now print or panic when resolving dependent libraries and either doesn't get a library, or the library doesn't have the right object, respectively.
Autobatching updated to handle autobatching whenever the scene's hierarchy changes and something is rendered.
INTERNAL FIX: Vector.Equals() / Vector.IsZero() is now more lenient as the epsilon tolerance is not as strict.
  • Loading branch information
SolarLune committed Dec 13, 2022
1 parent 206348e commit b847038
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 59 deletions.
2 changes: 2 additions & 0 deletions camera.go
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,8 @@ var bayerMatrix = []float32{
// Note that each MeshPart of a Model has a maximum renderable triangle count of 21845.
func (camera *Camera) Render(scene *Scene, models ...*Model) {

scene.HandleAutobatch()

frametimeStart := time.Now()

sceneLights := []ILight{}
Expand Down
20 changes: 13 additions & 7 deletions gltf.go
Original file line number Diff line number Diff line change
Expand Up @@ -1101,16 +1101,22 @@ func LoadGLTFData(data []byte, gltfLoadOptions *GLTFLoadOptions) (*Library, erro
clone = findNode(cloneName).Clone()
} else {
path = strings.ReplaceAll(path, "//", "") // Blender relative paths have double-slashes; we don't need them to

if gltfLoadOptions.DependentLibraryResolver == nil {
panic("Error in instantiating linked element " + cloneName + " as the Dependent Library Resolver function is nil.")
}

if library := gltfLoadOptions.DependentLibraryResolver(path); library != nil {
if foundNode := library.FindNode(cloneName); foundNode != nil {
clone = foundNode.Clone()
log.Printf("Warning: No dependent library resolver defined to resolve dependent library %s for object %s.\n", path, cloneName)
} else {

if library := gltfLoadOptions.DependentLibraryResolver(path); library != nil {
if foundNode := library.FindNode(cloneName); foundNode != nil {
clone = foundNode.Clone()
} else {
panic("Error in instantiating linked element: " + cloneName + " as there is no such object in the returned library.")
}
} else {
log.Printf("Warning: No library returned in resolving dependent library %s for object %s.\n", path, cloneName)
}

}

}

if clone != nil {
Expand Down
27 changes: 9 additions & 18 deletions model.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type Model struct {
// Automatic batching mode; when set and a Model changes parenting, it will be automatically batched as necessary according to
// the AutoBatchMode set.
AutoBatchMode int
autoBatched bool
}

// NewModel creates a new Model (or instance) of the Mesh and Name provided. A Model represents a singular visual instantiation of a Mesh.
Expand All @@ -68,8 +69,6 @@ func NewModel(mesh *Mesh, name string) *Model {
DynamicBatchModels: map[*MeshPart][]*Model{},
}

model.Node.onParentChange = model.onParentChange

model.Node.onTransformUpdate = model.onTransformUpdate

radius := 0.0
Expand Down Expand Up @@ -105,7 +104,6 @@ func (model *Model) Clone() INode {

newModel.Node = model.Node.Clone().(*Node)
newModel.Node.onTransformUpdate = newModel.onTransformUpdate
newModel.Node.onParentChange = newModel.onParentChange
for _, child := range newModel.children {
child.setParent(newModel)
}
Expand Down Expand Up @@ -165,21 +163,6 @@ func (model *Model) onTransformUpdate() {

}

// When changing a Model's hierarchy, we have to handle auto batching.
func (model *Model) onParentChange() {

if model.Scene() != nil {

if model.AutoBatchMode == AutoBatchDynamic {
model.Scene().autobatchDynamic(model)
} else if model.AutoBatchMode == AutoBatchStatic {
model.Scene().autobatchStatic(model)
}

}

}

func (model *Model) modelAlreadyDynamicallyBatched(batchedModel *Model) bool {

for _, modelSlice := range model.DynamicBatchModels {
Expand Down Expand Up @@ -918,11 +901,19 @@ func (model *Model) AddChildren(children ...INode) {
model.addChildren(model, children...)
}

func (model *Model) setParent(parent INode) {
model.Node.setParent(parent)
if model.AutoBatchMode != AutoBatchNone && model.Scene() != nil {
model.Scene().updateAutobatch = true
}
}

// Unparent unparents the Model from its parent, removing it from the scenegraph.
func (model *Model) Unparent() {
if model.parent != nil {
model.parent.RemoveChildren(model)
}
model.autoBatched = false
}

// Type returns the NodeType for this object.
Expand Down
10 changes: 4 additions & 6 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ type Property struct {
Value interface{}
}

// Set sets the property's value to the given value.
func (prop *Property) Set(value interface{}) {
prop.Value = value
}
Expand Down Expand Up @@ -262,8 +263,9 @@ func (prop *Property) IsVector() bool {
return false
}

// AsPosition returns the value associated with the specified tag (key) as a 3D position Vector clone.
// The axes are corrected to account for the difference between Blender's axis order and Tetra3D's.
// AsVector returns the value associated with the specified tag (key) as a 3D position Vector clone.
// The axes are corrected to account for the difference between Blender's axis order and Tetra3D's (i.e.
// Blender's +X, +Y, +Z becomes Tetra3D's +X, +Z, +Y).
// Note that this does not sanity check to ensure the tag is a vector first.
func (prop *Property) AsVector() Vector {
return prop.Value.(Vector)
Expand Down Expand Up @@ -338,7 +340,6 @@ type Node struct {
library *Library // The Library this Node was instantiated from (nil if it wasn't instantiated with a library at all)
scene *Scene
onTransformUpdate func()
onParentChange func()
}

// NewNode returns a new Node.
Expand Down Expand Up @@ -786,9 +787,6 @@ func (node *Node) Parent() INode {
// setParent sets the Node's parent.
func (node *Node) setParent(parent INode) {
node.parent = parent
if node.onParentChange != nil {
node.onParentChange()
}
}

// Scene looks for the Node's parents recursively to return what scene it exists in.
Expand Down
73 changes: 47 additions & 26 deletions scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Scene struct {
World *World
props *Properties

updateAutobatch bool
autobatchDynamicMap map[*Material]*Model
autobatchStaticMap map[*Material]*Model
}
Expand All @@ -21,10 +22,12 @@ type Scene struct {
func NewScene(name string) *Scene {

scene := &Scene{
Name: name,
Root: NewNode("Root"),
World: NewWorld("World"),
props: NewProperties(),
Name: name,
Root: NewNode("Root"),
World: NewWorld("World"),
props: NewProperties(),
autobatchDynamicMap: map[*Material]*Model{},
autobatchStaticMap: map[*Material]*Model{},
}

scene.Root.(*Node).scene = scene
Expand All @@ -45,6 +48,8 @@ func (scene *Scene) Clone() *Scene {
newScene.World = scene.World // Here, we simply reference the same world; we don't clone it, since a single world can be shared across multiple Scenes
newScene.props = scene.props.Clone()

newScene.updateAutobatch = true

return newScene

}
Expand All @@ -58,34 +63,50 @@ func (scene *Scene) Properties() *Properties {
return scene.props
}

func (scene *Scene) autobatchDynamic(model *Model) {
var autobatchBlankMat = NewMaterial("autobatch null material")

if scene.autobatchDynamicMap == nil {
scene.autobatchDynamicMap = map[*Material]*Model{}
}
func (scene *Scene) HandleAutobatch() {

mat := model.Mesh.Materials()[0]
if _, exists := scene.autobatchDynamicMap[mat]; !exists {
mp := NewMesh("auto dynamic batch")
mp.AddMeshPart(mat)
scene.autobatchDynamicMap[mat] = NewModel(mp, "auto dynamic batch")
scene.Root.AddChildren(scene.autobatchDynamicMap[mat])
}
scene.autobatchDynamicMap[mat].DynamicBatchAdd(scene.autobatchDynamicMap[mat].Mesh.MeshParts[0], model)
if scene.updateAutobatch {

}
for _, node := range scene.Root.ChildrenRecursive() {

func (scene *Scene) autobatchStatic(model *Model) {
if model, ok := node.(*Model); ok && !model.autoBatched {

if scene.autobatchStaticMap == nil {
scene.autobatchStaticMap = map[*Material]*Model{}
}
mat := autobatchBlankMat

if mats := model.Mesh.Materials(); len(mats) > 0 {
mat = mats[0]
}

if model.AutoBatchMode == AutoBatchDynamic {

if _, exists := scene.autobatchDynamicMap[mat]; !exists {
mesh := NewMesh("auto dynamic batch")
mesh.AddMeshPart(mat)
scene.autobatchDynamicMap[mat] = NewModel(mesh, "auto dynamic batch")
scene.Root.AddChildren(scene.autobatchDynamicMap[mat])
}
scene.autobatchDynamicMap[mat].DynamicBatchAdd(scene.autobatchDynamicMap[mat].Mesh.MeshParts[0], model)

} else if model.AutoBatchMode == AutoBatchStatic {

if _, exists := scene.autobatchStaticMap[mat]; !exists {
scene.autobatchStaticMap[mat] = NewModel(NewMesh("auto static merge"), "auto static merge")
scene.Root.AddChildren(scene.autobatchStaticMap[mat])
}
scene.autobatchStaticMap[mat].StaticMerge(model)

}

model.autoBatched = true

}

}

scene.updateAutobatch = false

mat := model.Mesh.Materials()[0]
if _, exists := scene.autobatchStaticMap[mat]; !exists {
scene.autobatchStaticMap[mat] = NewModel(NewMesh("auto static merge"), "auto static merge")
scene.Root.AddChildren(scene.autobatchStaticMap[mat])
}
scene.autobatchStaticMap[mat].StaticMerge(model)

}
4 changes: 2 additions & 2 deletions vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ func (vec Vector) Floats() [4]float64 {
// Equals returns true if the two Vectors are close enough in all values (excluding W).
func (vec Vector) Equals(other Vector) bool {

eps := 1e-6
eps := 1e-4

if math.Abs(float64(vec.X-other.X)) > eps || math.Abs(float64(vec.Y-other.Y)) > eps || math.Abs(float64(vec.Z-other.Z)) > eps {
return false
Expand All @@ -276,7 +276,7 @@ func (vec Vector) Equals(other Vector) bool {
// IsZero returns true if the values in the Vector are extremely close to 0 (excluding W).
func (vec Vector) IsZero() bool {

eps := 1e-8
eps := 1e-4

if math.Abs(float64(vec.X)) > eps || math.Abs(float64(vec.Y)) > eps || math.Abs(float64(vec.Z)) > eps {
return false
Expand Down

0 comments on commit b847038

Please sign in to comment.