Ubershader Archive Files
An ubershader archive provides a way to bundle up a set of filamat
files along with some metadata
that conveys which glTF features each material can handle. It is a file that has been compressed
with zstd
and has an .uberz
file extension. In uncompressed form, it has the following layout
(little endian is assumed).
[u32] magic identifier: UBER
[u32] simple (unpartitioned) version number for the archive format
[u64] number of specs
[u64] byte offset to SPECS
SPECS:
foreach spec {
[u8] shading model
[u8] blending model
[u16] number of flags
[u32] size in bytes of the filamat blob
[u64] byte offset to FLAGLIST for this spec
[u64] byte offset to FILAMAT for this spec
}
foreach spec {
FLAGLIST:
foreach flag {
[u64] byte offset to FLAGNAME for this spec/flag pair
[u64] flag value: 0 = unsupported, 1 = optional, or 2 = required
}
}
foreach spec {
foreach flag {
FLAGNAME:
[u8...] flag name, including null terminator
}
}
foreach spec {
FILAMAT:
[u8...] filamat blob
}
In the above specification, each "offset" is a number of bytes between the top of the file to the given label. These offsets are 64 bits so that they can be replaced with pointers in a C struct, which allows the file to be consumed without any parsing. On 32-bit architectures, this still works because we can simply ignore the unused padding after every pointer.
Ubershader Spec Files
An ubershader spec file is a simple text file with a .spec
extension. It contains a list of
key-value pairs conforming to the following grammar. Each key-value pair is either a feature flag
or a fundamental aspect.
- Each feature flag can be unsupported, required, or optional.
- The fundamental aspect of the material cannot be changed, such as the blend mode.
spec = { [ comment | key_value_pair ] , "\n" } ;
comment = "#" , { any } ;
key_value_pair = ( fundamental_aspect | feature_flag ) ;
fundamental_aspect = ( blending | shading ) ;
feature_flag = identifier , equals , ("unsupported" | "required" | "optional") ;
blending = "BlendingMode" , equals ,
( "opaque" | "transparent" | "fade" | "add" | "masked" | "multiply" | "screen" ) ;
shading = "ShadingModel" , equals ,
( "lit" | "subsurface" | "cloth" | "unlit" | "specularGlossiness") ;
equals = [ whitespace ] , "=" , [ whitespace ] ;
any = ? any character other than newline ? ;
whitespace = ? sequence of tabs and spaces ? ;
identifier = ? sequence of alphanumeric characters ? ;
If a fundamental aspect is missing from the spec, then the loader will assume that the spec can
handle all possible values for that aspect. For example, we may wish to override the glTF
blending mode in certain ubershader materials (e.g. materials that support KHR_materials_volume
).
These materials should simply omit the BlendingMode
line from the spec.
If any feature flag is missing from the spec, it implicitly has the value of unsupported
. For an
up-to-date list of recognized feature flags, look at the source for UbershaderProvider::getMaterial
.
If a particular feature flag is set to required
for a particular material, then the glTF loader
will bind that material to a given glTF mesh only if that feature is enabled in the mesh.
Usually, features are either unsupported
or optional
. For example, if the ubershader user can
set normalIndex
in the material to -1
to signal that they do not have a normal map, then normal
mapping should be specified as an optional
feature of the ubershader.