Opened 4 years ago
Closed 4 years ago
#4792 closed enhancement (fixed)
Save gltf using instancing to reduce file size
Reported by: | Tom Goddard | Owned by: | Tom Goddard |
---|---|---|---|
Priority: | moderate | Milestone: | |
Component: | Input/Output | Version: | |
Keywords: | Cc: | ||
Blocked By: | Blocking: | ||
Notify when closed: | kristen.browne@nih.gov | Platform: | all |
Project: | ChimeraX |
Description
Kristen Browne tried saving a virus capsid to gltf using
open 6htx
sym #1 assembly 1
surface #2
save virus.glb
This creates an enormous 1.6 Gbyte gltf file because the 60 copies of the asymmetric unit are all copied. Using instancing in the GLTF fie reduces the file size by a factor of 60.
Similar massive file sizes occur when simply saving atomic models since the atoms are instances that get copied. This creates a file 100 times larger when atoms use 2000 triangles (for small numbers of displayed atoms). At 20 triangles per atoms we expect similar file sizes because the GLTF node instances apparently take about the same number of bytes as 20 triangles. The node instances will probably be much slower to read than the copied geometry and 100,000 nodes may overwhelm software like Blender. So we may want to copy atom geometry for large numbers of atoms, also bonds.
Change History (8)
comment:1 by , 4 years ago
comment:2 by , 4 years ago
GLTF with instanced atom spheres (1a0m) works fine in babylonjs.
GLTF with instanced surfaces for a virus capsid fails to open in babylonjs giving "/nodes/2: Invalid recursive node hierarchy". Apparently it will not accept that the 60 capsid asymmetric unit nodes all have the same four child chain surface nodes. I guess it refuses to allow a node to be a child of more than one node. Not sure if the GLTF specification allows that. If not, it would not be hard to duplicate the nodes. The case of atoms works because the atom nodes only belong to one parent and they share the same mesh (not the same child node).
comment:3 by , 4 years ago
Yes, GLTF prohibits a node from being the child of more than one other node:
"For Version 2.0 conformance, the glTF node hierarchy is not a directed acyclic graph (DAG) or scene graph, but a disjoint union of strict trees. That is, no node may be a direct descendant of more than one node. This restriction is meant to simplify implementation and facilitate conformance."
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
comment:4 by , 4 years ago
I tried gltf save code that makes a new node for every instance. Works in babylon.js. But with each atom as a separate node, a medium size model like 6vxx coronavirus spike with 24000 atoms shown as sphere gives unusable bad performance, about 1 frame per second rotating and uses 4 Gbytes of memory. On the positive side the file size is only 7 Mbytes while copying geometry to make all spheres one node gives file size 115 Mbytes (using 184 triangles per atom sphere). Babylonjs on the 115 Mbyte model rotates equally slowly (~1 frame / sec) and uses 830 Mbytes of memory. So performance in both cases is horrible for this 4.4 million triangle model.
The babylon.js tests were in Safari on 2019 MacBook Pro laptop with AMD Vega 20 graphics and macOS Catalina 10.15.7.
comment:5 by , 4 years ago
Tests in Chrome on same Mac laptop give better performance. 60 frames / sec for copied geometry and sluggish 7 frames/sec with instanced 24000 atoms.
Copied geometry shows Chrome Helper GPU process 406 Mb and Chrome Helper Render process at 600 Mbytes. Instanced shows a Chrome Helper GPU process 844 Mb and Chrome Helper Render process 478 Mb. Chrome version 91.0.4472.114.
comment:6 by , 4 years ago
To avoid nodes for every atom and every halfbond (twice the number of atoms!) I could have leaf-level instances use copied geometry and non-leaf level (e.g. virus capsid 60-fold symmetry) use separate nodes. File size will still be very large for showing 100,000 atoms but it looks like gltf does not offer any solution for that case.
comment:7 by , 4 years ago
I added an "instancing" option when saving gltf that determines whether atoms/bonds (leaf node instances) become individual gltf nodes, or get merged into one mode. Default is false, meaning merge which creates a bigger file but with fewer nodes so viewer speed is better.
comment:8 by , 4 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
Done.
By default atoms have all the sphere geometries copied instead of instanced, same with bonds (and all leaf drawing instancing), because having thousands of GLTF nodes impairs GLTF viewer performance. I added an "instancing" option to the save gltf command, default false, that if set true will make atom and bond instances, which can make smaller file sizes. Even with the default instancing false, non-leaf drawings still get instanced in the written GLTF, so for instance a virus capsid with 60-fold symmetry produces a 60 times smaller file. I also now have the saved gltf use materials for single (not per-vertex) colored drawings.
Instanced atoms are using about 500 bytes per atom in the GLTF file for the node that gives the matrix and color.