BlenderUSDHydraAddon
BlenderUSDHydraAddon copied to clipboard
MaterialX materials are not instanced
Tested with latest master (1.0.77) and Blender 3.0.1.
To reproduce:
- create two cubes and one material with MaterialX graph assigned
- assign the material to both cubes
- export USD to file
usdeditfile or convert to USDA- see that the material has been emitted two times instead of only once
This can lead to very long compile times and slow rendering.
See USDA of the exported file
#usda 1.0
(
doc = """Generated from Composed Stage of root layer c:\\Users\\pablode\\AppData\\Local\\Temp\\hdusd\\4784\\tmpls_3rcd2.usda
"""
metersPerUnit = 1
upAxis = "Z"
)
def Xform "Camera"
{
matrix4d xformOp:transform = ( (0.6859206557273865, 0.7276763319969177, 0, 0), (-0.32401347160339355, 0.305420845746994, 0.8953956365585327, 0), (0.6515582203865051, -0.6141703724861145, 0.44527140259742737, 0), (7.358891487121582, -6.925790786743164, 4.958309173583984, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
def Camera "Camera"
{
float2 clippingRange = (0.1, 100)
float focalLength = 50
float horizontalAperture = 36
float horizontalApertureOffset = 0
token projection = "perspective"
float verticalAperture = 20.25
float verticalApertureOffset = 0
}
}
def Xform "Cube"
{
matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (3.391047239303589, 0, 0, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
def Mesh "Cube"
{
uniform bool doubleSided = 1
int[] faceVertexCounts = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
int[] faceVertexIndices = [0, 1, 3, 0, 3, 2, 2, 3, 7, 2, 7, 6, 6, 7, 5, 6, 5, 4, 4, 5, 1, 4, 1, 0, 2, 6, 4, 2, 4, 0, 7, 3, 1, 7, 1, 5]
rel material:binding = </Cube/Material/Materials/USD_Default>
normal3f[] normals = [(-1, -0, 0), (-1, -0, 0), (-1, -0, 0), (-1, -0, 0), (-1, -0, 0), (-1, -0, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (1, -0, 0), (1, -0, 0), (1, -0, 0), (1, -0, 0), (1, -0, 0), (1, -0, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, -0, 1), (0, -0, 1), (0, -0, 1), (0, -0, 1), (0, -0, 1), (0, -0, 1)] (
interpolation = "faceVarying"
)
point3f[] points = [(-1, -1, -1), (-1, -1, 1), (-1, 1, -1), (-1, 1, 1), (1, -1, -1), (1, -1, 1), (1, 1, -1), (1, 1, 1)]
texCoord2f[] primvars:st = [(0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.375, 0.25), (0.625, 0.25), (0.625, 0.5), (0.375, 0.5), (0.375, 0.5), (0.625, 0.5), (0.625, 0.75), (0.375, 0.75), (0.375, 0.75), (0.625, 0.75), (0.625, 1), (0.375, 1), (0.125, 0.5), (0.375, 0.5), (0.375, 0.75), (0.125, 0.75), (0.625, 0.5), (0.875, 0.5), (0.875, 0.75), (0.625, 0.75)] (
interpolation = "faceVarying"
)
int[] primvars:st:indices = [0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23]
uniform token subdivisionScheme = "none"
}
def "Material"
{
def "Materials"
{
def Material "USD_Default"
{
float inputs:clearcoat = 0
float inputs:clearcoatRoughness = 0.01
color3f inputs:diffuseColor = (0.18, 0.18, 0.18)
float inputs:displacement = 0
color3f inputs:emissiveColor = (0, 0, 0)
float inputs:ior = 1.5
float inputs:metallic = 0
float3 inputs:normal = (0, 0, 1)
float inputs:occlusion = 1
float inputs:opacity = 1
float inputs:opacityThreshold = 0
float inputs:roughness = 0.5
color3f inputs:specularColor = (0, 0, 0)
int inputs:useSpecularWorkflow = 0
token outputs:mtlx:surface.connect = </Cube/Material/Materials/USD_Default/ND_UsdPreviewSurface_surfaceshader.outputs:surface>
def Shader "ND_UsdPreviewSurface_surfaceshader"
{
uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
float inputs:clearcoat.connect = </Cube/Material/Materials/USD_Default.inputs:clearcoat>
float inputs:clearcoatRoughness.connect = </Cube/Material/Materials/USD_Default.inputs:clearcoatRoughness>
color3f inputs:diffuseColor.connect = </Cube/Material/Materials/USD_Default.inputs:diffuseColor>
float inputs:displacement.connect = </Cube/Material/Materials/USD_Default.inputs:displacement>
color3f inputs:emissiveColor.connect = </Cube/Material/Materials/USD_Default.inputs:emissiveColor>
float inputs:ior.connect = </Cube/Material/Materials/USD_Default.inputs:ior>
float inputs:metallic.connect = </Cube/Material/Materials/USD_Default.inputs:metallic>
float3 inputs:normal.connect = </Cube/Material/Materials/USD_Default.inputs:normal>
float inputs:occlusion.connect = </Cube/Material/Materials/USD_Default.inputs:occlusion>
float inputs:opacity.connect = </Cube/Material/Materials/USD_Default.inputs:opacity>
float inputs:opacityThreshold.connect = </Cube/Material/Materials/USD_Default.inputs:opacityThreshold>
float inputs:roughness.connect = </Cube/Material/Materials/USD_Default.inputs:roughness>
color3f inputs:specularColor.connect = </Cube/Material/Materials/USD_Default.inputs:specularColor>
int inputs:useSpecularWorkflow.connect = </Cube/Material/Materials/USD_Default.inputs:useSpecularWorkflow>
token outputs:surface
}
}
}
def "Shaders"
{
def Shader "ND_UsdPreviewSurface_surfaceshader"
{
uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
token outputs:surface
}
}
}
}
def Xform "Cube_001"
{
matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (-4.016847610473633, 0, 0, 1) )
uniform token[] xformOpOrder = ["xformOp:transform"]
def Mesh "Cube_001"
{
uniform bool doubleSided = 1
int[] faceVertexCounts = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
int[] faceVertexIndices = [0, 1, 3, 0, 3, 2, 2, 3, 7, 2, 7, 6, 6, 7, 5, 6, 5, 4, 4, 5, 1, 4, 1, 0, 2, 6, 4, 2, 4, 0, 7, 3, 1, 7, 1, 5]
rel material:binding = </Cube_001/Material/Materials/USD_Default>
normal3f[] normals = [(-1, -0, 0), (-1, -0, 0), (-1, -0, 0), (-1, -0, 0), (-1, -0, 0), (-1, -0, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (1, -0, 0), (1, -0, 0), (1, -0, 0), (1, -0, 0), (1, -0, 0), (1, -0, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, -0, 1), (0, -0, 1), (0, -0, 1), (0, -0, 1), (0, -0, 1), (0, -0, 1)] (
interpolation = "faceVarying"
)
point3f[] points = [(-1, -1, -1), (-1, -1, 1), (-1, 1, -1), (-1, 1, 1), (1, -1, -1), (1, -1, 1), (1, 1, -1), (1, 1, 1)]
texCoord2f[] primvars:st = [(0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.375, 0.25), (0.625, 0.25), (0.625, 0.5), (0.375, 0.5), (0.375, 0.5), (0.625, 0.5), (0.625, 0.75), (0.375, 0.75), (0.375, 0.75), (0.625, 0.75), (0.625, 1), (0.375, 1), (0.125, 0.5), (0.375, 0.5), (0.375, 0.75), (0.125, 0.75), (0.625, 0.5), (0.875, 0.5), (0.875, 0.75), (0.625, 0.75)] (
interpolation = "faceVarying"
)
int[] primvars:st:indices = [0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23]
uniform token subdivisionScheme = "none"
}
def "Material"
{
def "Materials"
{
def Material "USD_Default"
{
float inputs:clearcoat = 0
float inputs:clearcoatRoughness = 0.01
color3f inputs:diffuseColor = (0.18, 0.18, 0.18)
float inputs:displacement = 0
color3f inputs:emissiveColor = (0, 0, 0)
float inputs:ior = 1.5
float inputs:metallic = 0
float3 inputs:normal = (0, 0, 1)
float inputs:occlusion = 1
float inputs:opacity = 1
float inputs:opacityThreshold = 0
float inputs:roughness = 0.5
color3f inputs:specularColor = (0, 0, 0)
int inputs:useSpecularWorkflow = 0
token outputs:mtlx:surface.connect = </Cube_001/Material/Materials/USD_Default/ND_UsdPreviewSurface_surfaceshader.outputs:surface>
def Shader "ND_UsdPreviewSurface_surfaceshader"
{
uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
float inputs:clearcoat.connect = </Cube_001/Material/Materials/USD_Default.inputs:clearcoat>
float inputs:clearcoatRoughness.connect = </Cube_001/Material/Materials/USD_Default.inputs:clearcoatRoughness>
color3f inputs:diffuseColor.connect = </Cube_001/Material/Materials/USD_Default.inputs:diffuseColor>
float inputs:displacement.connect = </Cube_001/Material/Materials/USD_Default.inputs:displacement>
color3f inputs:emissiveColor.connect = </Cube_001/Material/Materials/USD_Default.inputs:emissiveColor>
float inputs:ior.connect = </Cube_001/Material/Materials/USD_Default.inputs:ior>
float inputs:metallic.connect = </Cube_001/Material/Materials/USD_Default.inputs:metallic>
float3 inputs:normal.connect = </Cube_001/Material/Materials/USD_Default.inputs:normal>
float inputs:occlusion.connect = </Cube_001/Material/Materials/USD_Default.inputs:occlusion>
float inputs:opacity.connect = </Cube_001/Material/Materials/USD_Default.inputs:opacity>
float inputs:opacityThreshold.connect = </Cube_001/Material/Materials/USD_Default.inputs:opacityThreshold>
float inputs:roughness.connect = </Cube_001/Material/Materials/USD_Default.inputs:roughness>
color3f inputs:specularColor.connect = </Cube_001/Material/Materials/USD_Default.inputs:specularColor>
int inputs:useSpecularWorkflow.connect = </Cube_001/Material/Materials/USD_Default.inputs:useSpecularWorkflow>
token outputs:surface
}
}
}
def "Shaders"
{
def Shader "ND_UsdPreviewSurface_surfaceshader"
{
uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
token outputs:surface
}
}
}
}
def "World"
{
def DomeLight "World"
{
color3f inputs:color = (0.05087609, 0.05087609, 0.05087609)
float inputs:intensity = 1
custom float inputs:transparency = 1
float xformOp:rotateX = 180
float xformOp:rotateX:orientToStageUpAxis = 90
float xformOp:rotateY = -90
uniform token[] xformOpOrder = ["xformOp:rotateX:orientToStageUpAxis", "xformOp:rotateX", "xformOp:rotateY"]
}
}
Hi.
Thanks for report. Now this is expected behavior - materials are created exclusively for every object.
Why? This disallows serious work based on exported scenes.
Hello, initially we have separate USD prim with all materials. But we had significant reasons to change it to the way: object has its own material. One of the reason is USD node tree where we have different nodes including Merge, Filter, Instancing, Root. Using separate global USD prim for materials produces problems of using such nodes.
Thanks for the answer, this definitely makes sense!
But I think that instancing is possible even without a root-level USD prim. I've crafted an example here:
#usda 1.0
(
defaultPrim = "Geom"
metersPerUnit = 1
upAxis = "Y"
)
def Scope "Geom"
{
def Xform "node1"
{
def Mesh "mesh"
{
def Material "someMaterial"
{
token outputs:surface.connect = </Geom/node1/mesh/someMaterial/node.outputs:surface>
def Shader "node"
{
uniform token info:id = "UsdPreviewSurface"
float3 inputs:diffuseColor = (1.0, 0.0, 0.0)
token outputs:surface
}
}
int[] faceVertexCounts = [3, 3]
int[] faceVertexIndices = [1, 0, 3, 1, 3, 2]
normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1)] (interpolation = "vertex")
point3f[] points = [(0.5, -0.5, 0), (-0.5, -0.5, 0), (-0.5, 0.5, 0), (0.5, 0.5, 0)]
uniform token subdivisionScheme = "none"
rel material:binding:preview = </Geom/node1/mesh/someMaterial>
}
}
def Xform "node2"
{
def Mesh "mesh"
{
over "someMaterial" (
references = </Geom/node1/mesh/someMaterial>
)
{
}
int[] faceVertexCounts = [3, 3]
int[] faceVertexIndices = [1, 0, 3, 1, 3, 2]
normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1)] (interpolation = "vertex")
point3f[] points = [(0.5, -0.5, 1), (-0.5, -0.5, 1), (-0.5, 0.5, 1), (0.5, 0.5, 1)]
uniform token subdivisionScheme = "none"
rel material:binding:preview = </Geom/node2/mesh/someMaterial>
}
}
}
EDIT: after tinkering with this a bit more I realized that true material instancing with the instanceable metadatum, unlike the use of inheritance I outlined, does require a root level prim..