Working with 3D Assets
StereoKit’s core 3D asset format is the GLTF! While there is still support for other formats, like STL, OBJ and PLY, GLTF is StereoKit’s preferred format of choice. It has a well defined modern specification, and a large collection of quality tooling available in the ecosystem.
GLB is still just the “binary” format of GLTF, typically with all related textures bundled inside it.
I’ve found Blender to have a very nice GLTF exporter! So if your tool of choice doesn’t support GLTF yet, exporting to Blender for a final pass can be a good approach! However, most tools will at least have a plugin for GLTF export.
Most 3D asset creation tools have material systems more geared towards cinematic rendering, rather than realtime rendering, so it can be important to understand how materials are exported in GLTF format (via Blender), as well as how StereoKit interprets them.
Materials
StereoKit’s rules for interpreting GLTF materials are mostly straightforward!
If the GLTF material is PBR (the normal case), StereoKit will use a PBR shader. It uses the metallic roughness definition of PBR, and does not currently support the specular/glossiness GLTF extension.
If the GLTF material is Unlit (In Blender, this is a material using a Background or Emission surface) StereoKit will use an Unlit shader.
If the GLTF material has alpha mask on, StereoKit will use a “clip” variant of the PBR or Unlit shaders that discards transparent pixels.
It’s good to note that GLTF supports vertex color data, and almost all StereoKit default shaders support vertex coloring! Vertex colors don’t often show in 3D asset tools out-of-the-box, but this can be a nice way to add cheap baked lighting to Unlit materials, or add color variation to looping textures, or other creative uses!
Lightmaps
StereoKit also supports a Ligtmapped material from GLTF files! This is a somewhat non-standard setup not found in the original spec, but is a very useful one for performant applications. It is not unusual to find bad GLTFs where lighting data is baked down into the diffuse texture, expanding a “looped” texture into something much much larger. This consumes much more RAM than preserving the original looped texture and combining it with a separate lightmap texture!
Instead, if StereoKit encounters a material that has:
- An emissive texture (the base color, like an Unlit material)
- An occlusion texture using the second UV channel (the lightmap)
- No texture for PBR base color
- No texture for PBR metal/roughness
This will trigger StereoKit to switch to a high-performance Unlit + Lightmap shader.
Best Practices
Optimize with GLTFPack
StereoKit supports all the GLTF extensions required for GLTFPack to work properly! Mesh compression, KTX textures, quantization and transform all work. If you can optimize your GLTF files in advance with a tool like this, you can get 50-80% smaller files (even on GPU!), much faster load times, and improved render performance!
gltfpack.exe -cc -tc -i modelName.glb -o modelName.opt.glb
This is effective with just about any model, but especially for photogrammetry-like assets this type of optimization is absolutely critical!
Backface Culling
GLTF supports a setting for enabling or disabling backface culling, an important optimization that will skip rendering triangles that face away from the viewer. Having backface culling ON can improve performance significantly, and in most normal cases, is completely unnoticeable! For whatever reason, many 3D tools seem to disable backface culling by default, and this mistake is very common to find in many GLTF files!
Always make sure your materials have backface culling ON whenever possible!
PBR Shaders vs. Unlit
Physically Based shaders look great! But the accuracy they provide costs a lot of computation. If you can use an Unlit material instead, do it!
For more information about shaders and material, check out StereoKit’s Material guide!
References
A quick note about how Asset types (Model/Material/Tex, etc.) work in StereoKit!
When you work with an Asset, you’ll want to keep in mind that you’re actually working with a reference to the Asset! Sometimes the handle you have is just one of many references to the Asset, and so changing the Asset will affect all other references to it as well.
If you want to change an Asset’s property without affecting other
references to that Asset, then you should Copy()
that Asset, and modify
that new, unique instance instead! This is why you’ll frequently see the
example code doing something like Material.Default.Copy()
before
changing any of the properties.
GLTF extension support
On a more technical note, here’s a specific list of what GLTF extensions StereoKit supports.
- KHR_materials_unlit
- KHR_mesh_quantization
- KHR_texture_basisu
- KHR_texture_transform (not rotation)
- EXT_meshopt_compression
Notes About Alternative Formats
Why no FBX you might ask? FBX is an old and poorly defined format. Early versions of StereoKit supported it, but it ended up being far too much pain. Among other things, FBX has no reliable concept of “units” or even “which direction is forward”.
Why not USD? USD unfortunately has no format specification! It’s less of a file format, and more of a library. As such, it has a very poor tooling ecosystem making the “format” difficult to support well. If you want to support USD correctly, you must use the singular implementation of USD. And unfortunately, that implementation doesn’t pass my smell test for code quality.
Found an issue with these docs, or have some additional questions? Create an Issue on Github!