-
Notifications
You must be signed in to change notification settings - Fork 367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Material assignments to child objects #1109
Comments
Here's a reduced test case with only 2 objects. <look name="L_ParentChildTest">
<!-- Larger parent cube should be blue. -->
<materialassign name="L_Parent" geom="/Parent" material="M_Parent" />
<!-- Smaller child cube should be orange. -->
<materialassign name="L_Child" geom="/Parent/Child" material="M_Child" />
</look> The expected behavior is a large blue parent cube, with a smaller orange child: But when I load the .mtlx file, I see the child's material assigned to both: |
Hi @emackey , I'm pinging @dbsmythe and @jstone-lucasfilm as I can't find anywhere in the spec which says what the behaviour is supposed to be in this case, and whether it's worth pursuing support for this as USD is supposed to handle "full" assignment logic. Does this import into USD for instance?
"nodes": [
{
"mesh": 0,
"name": "Child",
"translation": [
0,
1.4495644569396973,
0
]
},
{
"children": [
0
],
"mesh": 1,
"name": "Parent"
}
], |
I tried specifying This sort of hierarchy is fairly common for inorganic or hard-surface models. It's especially notable on robotic arms and other situations with multiple mechanical joints that build on each other. And it's useful on the chess set's pawns too, because the top requires a different material (because of transmission, realtime systems must render its material in a separate pass from the opaque pawn base material). If the base were to move or animate, the top must come with it, and that makes the top a child. |
The intention of the assignments is that they would in fact work as emackey believes, with the blue parent cube and orange child cube. The "Geometry Representation" part of the Spec says this (bold emphasis added for this discussion): |
So it might be understandable for a parent's material to end up on a child, if the child did not express its own material. But surely it's a bug to have the child's material ever end up on the parent, which is what's observed here. |
Right- as we move forward with separating out the "Geometry Extensions" from the main Specification (in 1.38) into a separate, optional (but still standard) specification document (in 1.39), and applications move toward other mechanisms like USD for doing material/etc assignments to geometries, this will hopefully be less of a problem. I do think though that MaterialXView should support those "Geometry Extensions" (the syntax and mechanics aren't changing at all, just where they are defined in Spec documents), and the "blue vs orange" assignment issue demonstrated above really should be fixed to work as expected. |
Took a look at this, and the support logic is there but it's "reversed" for membership so parents are assigned child materials. @emackey If you get chance, can you try out this change to see if it works overall for your tests / chess set ? It's a one line change in C++ and a few lines for web if your using that. If it's good feel free to use it. @jstone-lucasfilm , leaving a ping for when your back as I think either you or I wrote this code from a few years back. Thanks. |
As a FYI, I asked in the ASWF USD/MaterialX group for USD side support. Here is an example I posted for this parent-child relationship as well as child faceset support. @emackey , as far as I can tell indexing is on a mesh in glTF so if you want to specify a subset to assign a material to you need to create a new mesh. I created them as children so that they are leaves when deriving the path syntax. If worthwhile can pull a faceset example request issue out. I asked @ashwinbhat if perhaps we could add something like this as a reference for USD/MTLX/glTF equivalence.
<?xml version="1.0"?>
<materialx version="1.38" colorspace="lin_rec709" >
<!-- Parent Material -->
<gltf_pbr name="S_Parent" type="surfaceshader">
<input name="base_color" type="color3" value="0.1 0.4 0.7" />
<input name="metallic" type="float" value="0" />
<input name="roughness" type="float" value="0.4" />
</gltf_pbr>
<surfacematerial name="M_Parent" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="S_Parent" />
</surfacematerial>
<!-- Child Material -->
<gltf_pbr name="S_Child" type="surfaceshader">
<input name="base_color" type="color3" value="0.7 0.4 0.1" />
<input name="metallic" type="float" value="0" />
<input name="roughness" type="float" value="0.4" />
</gltf_pbr>
<surfacematerial name="M_Child" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="S_Child" />
</surfacematerial>
<!-- Child Face Set 1 Material -->
<gltf_pbr name="S_Child_Set1" type="surfaceshader">
<input name="base_color" type="color3" value="0, 0, 0" />
<input name="metallic" type="float" value="0" />
<input name="roughness" type="float" value="0.4" />
</gltf_pbr>
<surfacematerial name="M_Child_Set1" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="S_Child_Set1" />
</surfacematerial>
<!-- Child Face Set 2 Material -->
<gltf_pbr name="S_Child_Set2" type="surfaceshader">
<input name="base_color" type="color3" value="1, 1, 1" />
<input name="metallic" type="float" value="0" />
<input name="roughness" type="float" value="0.4" />
</gltf_pbr>
<surfacematerial name="M_Child_Set2" type="material">
<input name="surfaceshader" type="surfaceshader" nodename="S_Child_Set2" />
</surfacematerial>
<!-- Look -->
<look name="L_ParentChildTest">
<!-- Larger parent cube should be blue. -->
<materialassign name="L_Parent" geom="/Parent" material="M_Parent" />
<!-- Smaller child cube should be orange. -->
<materialassign name="L_Child" geom="/Parent/Child" material="M_Child" />
<!-- Child cube faceset 1 should be black . -->
<materialassign name="L_Child_Set1" geom="/Parent/Child/Child_subset1" material="M_Child_Set1" />
<!-- Child cube faceset 2 should be white. -->
<materialassign name="L_Child_Set2" geom="/Parent/Child/Child_subset2" material="M_Child_Set2" />
</look>
</materialx>
def Material "M_Parent"
{
def Shader "S_Parent"
{ ... }
}
def Material "M_Child"
{
def Shader "S_Child"
{ ... }
}
def Material "M_Child_Set1"
{
def Shader "S_Child_Set1"
{ ... }
}
def Material "M_Child_Set2"
{
def Shader "M_Child_Set2"
{ ... }
}
def Xform "Root"
{
def Xform "Parent"
{
def Mesh "Parent"
{
rel material:binding:full = </M_Parent>
}
def Xform "Child"
{
def Mesh "Child"
{
rel material:binding = </M_Child>
def GeomSubset "Child_subset1"
{
uniform token elementType = "face"
int[] indices = [1, 2, 3, 5]
rel material:binding = </M_Child_Set1>
}
def GeomSubset "Child_subset2"
{
uniform token elementType = "face"
int[] indices = [0]
rel material:binding = </M_Child_Set2>
}
}
}
}
}
"nodes": [
{
"mesh": 0,
"children": [
1,2
],
"name": "Child",
"translation": [
0,
1.4495644569396973,
0
]
},
{
"mesh": 1,
"name": "Child_subset1",
},
{
"mesh": 2,
"name": "Child_subset2",
},
{
"children": [
0
],
"mesh": 3,
"name": "Parent"
}
], |
In glTF, meshes contain an array of "primitives," and each primitive has a different material assigned. A glTF mesh with only one material needs only one glTF primitive. A multi-material mesh will need one glTF primitive per material. The idea is that a realtime system will draw the whole primitive with a single draw call, and change textures or shader programs before drawing the next primitive. There's no per-index material assignment, because typically GPUs don't do that. |
Spotted by @pablode in #1098 (comment)
When two objects have a parent/child relationship,
<materialassign ... geom="...">
cannot distinguish between them correctly. In the linked PR, there is a chess set pawn object, and it has a "top" child object with a different material.The first line above should assign the pawn's body material to the base of the pawn, which is the parent object. The next line should assign a separate material to the top of the pawn, which is a child of the base.
In MaterialXView, I see the top material get assigned to both parent and child.
The text was updated successfully, but these errors were encountered: