OpenPype icon indicating copy to clipboard operation
OpenPype copied to clipboard

Maya: per face shaders assignment validator

Open m-u-r-p-h-y opened this issue 2 years ago • 6 comments

We need to validate per face shader assignments as it breaks look publishing

per face shaders should be forbidden as we are not able to handle topology changes and identify faces/shaders relationship consistently.

[cuID:2eqzt6m]

m-u-r-p-h-y avatar Jun 02 '22 14:06 m-u-r-p-h-y

There is validator for this but seems that it doesn't work for all cases validate_look_single_shader.py

We need to test it more

antirotor avatar Jun 02 '22 15:06 antirotor

If you can provide me scenes that do incorrectly pass the validation let me know how to reproduce and I'd be happy to patch it up.

BigRoy avatar Jun 03 '22 12:06 BigRoy

If we only count the number of shader connections to assume there are component level assignments we are missing the case where you select ALL faces of an object and assign the shader.

So there will be only one shader but on a component level.

m-u-r-p-h-y avatar Jun 03 '22 12:06 m-u-r-p-h-y

Valid point! Will have a look.

BigRoy avatar Jun 03 '22 12:06 BigRoy

We could do this to detect component assignments specifically:

from maya import cmds

NODE_TYPE_FACE_COMPONENTS = {
    "mesh": ".f[*]",
    "nurbsSurface": ".sf[*][*]"
}

for node in cmds.ls(type=["mesh", "nurbsSurface"]):
    sets = cmds.listSets(o=mesh)
    shading_engines = cmds.ls(sets, type="shadingEngine")
    
    # Check if any face or surface patch component assignments
    # were made to a shadingEngine
    node_type = cmds.nodeType(node)
    node_components = node + NODE_TYPE_FACE_COMPONENTS[node_type]
    
    for shading_engine in shading_engines:
        has_component_assignments = cmds.sets(node_components, anyMember=shading_engine)
        print(f"{node} has component assignments with {shading_engine}")

Not sure if there's a simpler way.


Actually, this might be the way:

from maya import cmds

for node in cmds.ls(type=("mesh", "nurbsSurface")):
    
    component_assignments = cmds.listConnections(node + ".compInstObjGroups[*].compObjectGroups[*]", type="shadingEngine")
    print(component_assignments)
    
    shape_assignments = cmds.listConnections(node + ".instObjGroups[*].objectGroups[*]", type="shadingEngine")
    print(shape_assignments)

BigRoy avatar Jun 03 '22 12:06 BigRoy

If we only count the number of shader connections to assume there are component level assignments we are missing the case where you select ALL faces of an object and assign the shader.

❤️ We actually ran into this with a scene and it wasn't trivial to figure out that that was the issue in the scene. A mixture of Pyblish plug-ins started failing due to this.

Here's the quick workaround I wrote to 'repair' the scene:

# Re-assign shaders that are assigned to *ALL* face components of a mesh
from maya import cmds

for sg in cmds.ls(type="shadingEngine"):
    members = cmds.sets(sg, query=True) or []
    for member in members:
        if ".f[" in member:
            node, component = member.split(".", 1)
            
            num_faces = cmds.polyEvaluate(node, face=True)
            if member.endswith(f".f[0:{num_faces-1}]"):
                print(f"Fixing {member}")
                # All faces are assigned. Assign the node instead
                cmds.sets(node, forceElement=sg)

Note the Py3 f-string formatting...

BigRoy avatar Jun 22 '22 14:06 BigRoy