- Pär Winzell, Facebook, @zellski
- Andrew Prasetyo Jo, Facebook
Draft
Written against the glTF 2.0 spec.
This extension annotates glTF scene
objects with a summary of the cumulative geometric complexity and scene-space extents of the scene's associated scene graph. Each recursively referenced mesh is enumerated for total vertex and primitive count, and each individual vertex is transformed into scene-space for a perfectly computed bounding box.
Some proven real-world applications for this information:
- When a viewer needs to make a quick, high-level decision which
scene
to display. This is perhaps most meaningful e.g. whenscenes
are used to represent different variants (e.g. LoD levels) of a model. - When server-side systems need to make decisions based on geometric complexity, and don't want to have to include their own complex matrix/vector code.
The summary data is defined as an optional extension to a glTF scene
, by adding an extensions
property and defining a KHR_lights_punctual
property with a lights
array inside it:
"extensions": {
"FB_geometry_metadata" : {
"vertexCount": 28727,
"primitiveCount": 15451,
"sceneBounds": {
"min": [
-3.0651053919852,
0,
-2.6551087079312
],
"max": [
3.0651053919852,
9.8512265772065,
2.6538096091834
]
}
}
}
All these values should be computed with disregard for animation: all morph targets are inactive, all node
transforms are in their static form and unaffected by any animation. Consequently, an application that parses the model should interpret the values the same way.
Conceptually, computing and gathering this information is very straight-forward. On a hypothetical glTF node
object:
public function computeGeometryMetadata(
GltfMat44f $world_transform,
inout A3DGltfBounds $bounds,
inout int $vertex_count,
inout int $primitive_count,
): void {
// compute world transform forward
$world_transform = A3DGltfMath::multiplyMatrices(
$world_transform,
$this->computeLocalTransform(),
);
// if this node references a mesh, traverse it
$this->mesh?->computeGeometryMetadata(
$world_transform,
inout $bounds,
inout $vertex_count,
inout $primitive_count,
);
// depth-first scene graph traversal
foreach ($this->getChildren() as $child) {
$child->computeGeometryMetadata(
$world_transform,
inout $bounds,
inout $vertex_count,
inout $primitive_count,
);
}
}
and on the mesh
primitive
, simply:
public function computeGeometryMetadata(
GltfMat44f $world_transform,
inout A3DGltfBounds $bounds,
inout int $vertex_count,
inout int $primitive_count,
): void {
$vertex_count += $this->getVertexCount();
$primitive_count += $this->getPrimitiveCount();
// this is very expensive, and will one day move to native code
foreach ($this->positions as $position) {
$bounds->expandByVec(
A3DGltfMath::transformVec3($world_transform, $position),
);
}
}