guc's conversion process produces self-containing components, which can then be composed as part of a larger assembly. A consumer may modify the components as needed, however artist-friendliness (layering, shading network complexity) can not be ensured due to the lack of usage annotations and the need to support the space of legal glTF constructions. The converted assets are hence intended to be used "as-is", for instance as leaf nodes in a USD-based pipeline, and not as intermediate products in a content-authoring pipeline.
In the following example, we're going to see how guc translates the golden triangle from Chapter 11 of Khronos's glTF tutorial.
A render of the golden glTF triangle (left), and its corresponding JSON (right).
Upon conversion, guc creates a root prim, /Asset
, under which scenes and materials reside.
Scenes contain Xform, mesh, camera and light prims.
For the "golden triangle" example above, following high-level scene structure is generated:
#usda 1.0
(
defaultPrim = "Asset"
doc = "Converted from glTF with guc 0.2"
metersPerUnit = 1
upAxis = "Y"
)
def Xform "Asset" (
customData = {
string version = "2.0"
}
kind = "component"
)
{
def Xform "Scenes"
{
def Xform "scene"
{
# ...
Only the default scene is authored as visible, and if no scenes exists, the glTF file is a library.
guc then generates an asset-level /Nodes
prim.
Nodes are glTF graph elements with an optional transformation, which can either contain a number of nodes, or a reference to a mesh, camera, or light. Nodes are translated to Xforms under the scene prim. Meshes, cameras and lights are "instanced" across scenes through references, but instancing of node trees does not exist.
The glTF buffer, bufferView and accessor concepts are reduced to a single prim, in the case of the example above, following mesh prim:
def Mesh "submesh" (
prepend apiSchemas = ["MaterialBindingAPI"]
)
{
float3[] extent = [(0, 0, 0), (1, 1, 0)]
int[] faceVertexCounts = [3]
int[] faceVertexIndices = [0, 1, 2]
rel material:binding = </Asset/Materials/MaterialX/Materials/mat>
rel material:binding:preview = </Asset/Materials/UsdPreviewSurface/Materials/mat>
normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1)] (
customData = {
dictionary guc = {
bool generated = 1
}
}
interpolation = "vertex"
)
point3f[] points = [(0, 0, 0), (1, 0, 0), (0, 1, 0)]
color3f[] primvars:displayColor = [(1, 0.766, 0.336)] (
customData = {
dictionary guc = {
bool generated = 1
}
}
interpolation = "constant"
)
uniform token subdivisionScheme = "none"
}
Depending on material parameters and available accessors, guc creates following primvars:
Name | Description |
---|---|
color[N] | Vertex color set N |
displayColor | Display color (constant or per-vertex) |
displayOpacity | Display opacity (constant or per-vertex) |
opacity[N] | Vertex opacity set N |
st[N] | Texture coordinate set N |
tangents | Three-component tangent vectors |
bitangentSigns | Bitangent handedness |
Additionally, a material binding relationship is always authored on the prim and its overrides, potentially binding a default material.
guc authors UsdPreviewSurface and MaterialX material collections on an asset-level /Materials
prim.
The exact path is motivated by the behaviour of UsdMtlx, which implicitly creates prim scopes.
The generated UsdPreviewSurface material for the example above looks like this:
def Material "mat"
{
token outputs:surface.connect = </Asset/Materials/UsdPreviewSurface/Materials/mat/node.outputs:surface>
def Shader "node"
{
uniform token info:id = "UsdPreviewSurface"
float3 inputs:diffuseColor = (1, 0.766, 0.336)
float inputs:metallic = 0.5
float inputs:roughness = 0.1
token outputs:surface
}
}
While the generated MaterialX document is approximately the following:
<?xml version="1.0"?>
<materialx version="1.38" colorspace="lin_rec709">
<gltf_pbr name="SR_mat" type="surfaceshader">
<input name="base_color" type="color3" value="1, 0.766, 0.336" />
<input name="occlusion" type="float" value="1" />
<input name="metallic" type="float" value="0.5" />
<input name="roughness" type="float" value="0.1" />
</gltf_pbr>
<surfacematerial name="mat" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="SR_mat" />
</surfacematerial>
</materialx>
guc makes use of MaterialX's glTF PBR implementation, with the shading logic being maintained and developed by MaterialX contributors.
guc's leftover responsibility is to instantiate the <gltf_pbr>
node and to populate its inputs.
For example, if Chapter 3.9.2 of the glTF specification defines the base color to consist of a texture value, a factor and the vertex color, the following node graph is generated:
flowchart RL;
A["<font color=red><!-- baseColorFactor --></font> <br/> <font color=blue><constant></font>"];
B["<font color=red><!-- COLOR_0 --></font> <br/> <font color=blue><geompropvalue></font>"];
C["<font color=blue><multiply></font>"];
D["<font color=red><!-- baseColorTexture --></font> <br/> <font color=blue><image></font>"];
E["<font color=red><!-- channel extraction --></font>"];
F["<font color=#f99><!-- opt. colorspace transformation --></font>"];
G["<font color=blue><multiply></font>"];
H["<font color=blue><gltf_pbr> <br/> <font color=red> <!-- base_color input --> <br/> <font color=blue> </gltf_pbr></font> "];
A-->C
B-->C
C-->G
D-->E
E-->F
F-->G
G-->H
classDef default fill:#fff,stroke:#999
Depending on conversion options, the graph may contain additional color space transformation nodes.
Normal mapped assets require tangents generated by the MikkTSpace algorithm. These are four-component vectors, with the last component specifiying the handedness of the bitangent.
guc constructs the tangent space from two authored primvars, tangents and bitangentSigns, which are
read directly into a custom normal map node implementation, accounting for a limitation
of MaterialX's <normalmap>
node (see Ecosystem Limitations).
There are a number of improvements that can be made to the mapping process.
For instance, the MaterialX graph complexity can be reduced with the introduction of helper nodes. Resulting USD assets could make use of payloads, and in general, incremental changes motivated by the USD Asset WG Structure Guidelines are to be expected.
Lastly, user feedback is welcome in ensuring that assets conform to best practices.