// =========================================================================== // Copyright 2018 Autodesk, Inc. All rights reserved. // // Use of this software is subject to the terms of the Autodesk license // agreement provided at the time of installation or download, or which // otherwise accompanies this software in either electronic or hard copy form. // =========================================================================== proc string[] expandedListOfRenderableObjects(string $object) { // Check to see if this object has multiple instances or not. // string $tokens[]; tokenize($object, "|", $tokens); string $objectShortName = $tokens[size($tokens)-1]; // Make a list of the object's parents with their full path. // string $instances[] = `listRelatives -allParents -fullPath $object`; // Make a list of the object's different instances. // The object's instance's full name = full_path|objectShortName. // int $i; for ($i = 0; $i < size($instances); $i++) { $instances[$i] = $instances[$i]+"|"+$objectShortName; } return $instances; } proc string getSurfaceShaderForShadingGroup(string $shadingGroup) // Description: This procedure gets the surface shader for the // given shading group. // { string $surfaceShaders[] = `listConnections -source on -destination off ($shadingGroup+".surfaceShader")`; if (size($surfaceShaders) == 0) { // There is no surface shader for the given shading group. // return ""; } return $surfaceShaders[0]; } proc string[] getComponentShadingGroup(string $object) // Description: This procedure returns the shading groups for the // given object's components. // { return `listConnections -source off -destination on -type shadingEngine ($object+".instObjGroups[0].objectGroups")`; } proc perObjectMaterialDiagnostics(string $object, string $shadingGroup) // Description: This procedure assumes the given object has per object // material assignment through the given shadingGroup. It checks // if there is any problem or inconsistency in the material // assignment. // { // Check for situation where we expect per object material // assignment, but there is no material. // if (getSurfaceShaderForShadingGroup($shadingGroup) == "") { // There is no surface shader for the given shading group. // string $msg = (uiRes("m_objectMaterialDiagnostics.kIncomplete")); warning(`format -stringArg $object -stringArg $shadingGroup $msg`); } // Check for situation where both per object and per face // shading information co-exists, either the information is // complete or incomplete. // string $componentShadingGroups[] = getComponentShadingGroup($object); if (size($componentShadingGroups) > 0) { string $msg = (uiRes("m_objectMaterialDiagnostics.kPerObjectPerFace")); warning(`format -stringArg $object $msg`); } } // Description: Check to see if the component has an // object group component list. // proc int hasComponentListForComponent( string $objectComponentInfoPlug, string $groupIdNode) { // Case 1: The object group component list can be stored in the // shape.instObjGroups[i].objectGroups[j].objectGrpComp // attribute. // string $componentList[] = `getAttr ($objectComponentInfoPlug+".objectGrpCompList")`; if (size($componentList) >= 1) { if ($componentList[0] != "") { return true; } } // Case 2: The object group component list can be stored in // the groupParts node connected to the groupId node // which was connected to the shape's component. // if ($groupIdNode == "") { // The object component has no groupId node connected to it. // Hence there is no groupParts connected to it. // return false; } string $groupParts[] = `listConnections -source off -destination on -type groupParts ($groupIdNode+".groupId")`; if (size($groupParts) != 0) { $componentList = `getAttr ($groupParts[0]+".inputComponents")`; if (size($componentList) >= 1) { if ($componentList[0] != "") { return true; } } } return false; } // Description: This procedure is used to obtain a list of object // group in the multi attribute // shape.instObjGroups[i].objectGroups. // Input: // $objectGroupPlug = shape.instObjGroups[i].objectGroups. // proc string[] listExistingObjectGroups(string $objectGroupsPlug) { // Note: This method is used to get the object groups in the // multi attribute // shape.instObjGroups[i].objectGroups // because the "getAttr -size" method counts only the // objectGroups with data in it. We could have a situation // where // objectGroups[0] [2] [4] // have data and // objectGroups[1] [3] // does not have data. So // "getAttr -size shape.instObjGroups[i].objectGroups" // returns size "3". But we don't know which 3 has data. // // So we decided to use // "listAttr -multi -leaf" to figure out which // objectGroups indices might exist. // string $listOfLeafAttr[] = `listAttr -multi -leaf $objectGroupsPlug`; // The $listOfLeafAttr might look like // // Result: objectGroups[0] objectGrpCompList // objectGroupId objectGrpColor objectGroups[1] // objectGrpCompList objectGroupId objectGrpColor // // We want to get the elements which says "objectGroups[j]" where // j=0,1,2,etc. // string $attrName; string $objectGroupsList[]; for ($attrName in $listOfLeafAttr) { if (size($attrName) > 13 && `substring $attrName 1 13` == "objectGroups[") { $objectGroupsList[size($objectGroupsList)] = $attrName; } } return $objectGroupsList; } // Description: This procedure is used to find the relevand // entries of an attribute of type multi. // // For instance, a shape's material assignment information // is stored in the shape.instObjGroups attribute. // The shape can have many instances. // . Instance #0 uses shape.instObjGroups[0] // . Instance #1 uses shape.instObjGroups[1] // . Instance #2 uses shape.instObjGroups[2] // In reality, an instance does not have a number. // To figure out which instObjGroups entry is related to // an instance, we can pass this procedure the path of the plug // $multiPlugPath = instance's_full_path|shape.instObjGroups, // The procedure will return the relevant entry // instObjGroups[i]. // // Note: For this procedure to work correctly, the $multiPlugPath // has to use the attribute's full name not short name. // In the example above, we need to use "..... .instObjGroups" // not the short name "iog". // proc string[] listOfRelevantMultiEntries(string $multiPlugPath) { string $listOfLeafAttr[] = `listAttr -multi -leaf $multiPlugPath`; // Get the attribute's short name. // string $tokens[]; tokenize($multiPlugPath, ".", $tokens); string $multiAttrShortName = $tokens[size($tokens)-1]; string $attrName; string $relevantMultiEntries[]; int $multiAttrShortNameSizePlusOne = size($multiAttrShortName)+1; string $searchForString = $multiAttrShortName+"["; for ($attrName in $listOfLeafAttr) { if (size($attrName) > $multiAttrShortNameSizePlusOne && `substring $attrName 1 $multiAttrShortNameSizePlusOne` == $searchForString) { $relevantMultiEntries[size($relevantMultiEntries)] = $attrName; } } return $relevantMultiEntries; } proc string relevantInstObjGroups(string $instObjGroupsPlugPath) { string $entries[] = listOfRelevantMultiEntries($instObjGroupsPlugPath); if (size($entries) >= 1) { // We are really only expect one relevant entry. // return $entries[0]; } return ""; } // Description: This procedure analyzes the material assignments // to the object's component. // Input: // $instObjGroups = shape_full_path.instObjGroups[i], // it is an attribute which stores rendering // related information for an instance of a // shape. // $objectGroups[] = a list of objectGroups component which might // exists under the // instObjGroups[i] attribute, for example, // the list could be // {"objectGroups[2]", "objectGroups[3]"}. // proc perFaceMaterialDiagnostics(string $instObjGroups, string $objectGroups[]) { // Check to see if there is any groupId node connected to this // instObjGroups. // string $groupIds[] = `listConnections -type groupId ($instObjGroups+".objectGroups")`; if (size($groupIds) == 0) { // If the components have no groupId node connected to them, // then it cannot be rendered. // string $msg = (uiRes("m_objectMaterialDiagnostics.kNoGroupid")); warning(`format -stringArg $instObjGroups $msg`); return; } string $objectGroup; for ($objectGroup in $objectGroups) { string $objectComponentInfoPlug = $instObjGroups+"."+$objectGroup; // Check to see if the component has groupId or not. // string $groupId = ""; string $groupIds[] = `listConnections -source on -destination off -type groupId ($objectComponentInfoPlug+".objectGroupId")`; if (size($groupIds) != 0) { $groupId = $groupIds[0]; } if ($groupId == "") { // The component has no groupId node connected to it. // It cannot be rendered. // continue; } // Check to see if the component has an // object group component list, i.e. a list of faces in the // component. // if (!hasComponentListForComponent($objectComponentInfoPlug, $groupId)) { // This objectGroup does not have any faces. We don't // worry about if it has a shading group or not. // continue; } // The connection between the object component to the // shading group is from source // objectName.instObjGroups[p].objectGroups[i] // to destination // $shadingGroups[$j].dagSetMembers[k]. // string $shadingGroups[] = `listConnections -source off -destination on -type shadingEngine $objectComponentInfoPlug`; if (size($shadingGroups) == 0) { string $msg = (uiRes("m_objectMaterialDiagnostics.kNotConnected")); warning(`format -stringArg $objectComponentInfoPlug $msg`); } else { string $shadingGroup = $shadingGroups[0]; // Check to see if the component's shading engine has // a material or not. // if (getSurfaceShaderForShadingGroup($shadingGroup) == "") { string $msg = (uiRes("m_objectMaterialDiagnostics.kConnected")); warning(`format -stringArg $objectComponentInfoPlug -stringArg $shadingGroup $msg`); } } } } global proc objectMaterialDiagnostics() // // Description: This procedure gives a diagnostics of object material // assignment problems, such as // . a renderable object with no material, // . an object has both per object and per face assignment, // { // Get a list of renderable objects. // string $renderableObjects[] = `lsThroughFilter renderableObjectShapeFilter`; print("\n"); string $object; for ($object in $renderableObjects) { // Get all the instances of this object. // string $instances[] = expandedListOfRenderableObjects($object); string $instance; for ($instance in $instances) { string $instObjGroups = relevantInstObjGroups($instance+".instObjGroups"); $instObjGroups = $instance + "."+$instObjGroups; // Check to see if the object is linked to a shading group // on per object basis. // string $shadingGroup[] = `listConnections -source off -destination on -type shadingEngine $instObjGroups`; if (size($shadingGroup) == 0) { // Make a list of objectGroups for this instance of the object. // string $objectGroups[] = `listExistingObjectGroups( $instObjGroups+".objectGroups")`; if (size($objectGroups) >= 0) { // The given object has no per object shading group // connected to it. It has components. We look for //----------------------------------- // per face material assignment. //----------------------------------- perFaceMaterialDiagnostics($instObjGroups, $objectGroups); } else { // This instance of the object has // . no per object material assignment, // . no per face material assignment, // assignment. // string $msg = (uiRes("m_objectMaterialDiagnostics.kNoMaterial")); warning(`format -stringArg $instance $msg`); } } else { // The given object has per object shading group connected // to it. // //---------------------------------- // per object material assignment //---------------------------------- perObjectMaterialDiagnostics($instance, $shadingGroup[0]); } } } }