//=========================================================================== // Copyright ©2002 Radical Entertainment Ltd. All rights reserved. // // Created: 17 April, 2002 // // Component: optimizeShaders.mel // // Description: Sorts file textures by their '.fileTextureName' attributes, // and for those whose input file matches compares all input // attributes to see if they can be considered equivalent. // Equivalent file textures are "merged" so one serves the // duties previously served by both. // // Materials and Shading Groups are evaluated and optimized // in similar fashion. // // Constraints: // // Creator: Bryan Ewert // //=========================================================================== //=========================================================================== // version //=========================================================================== // Description: Returns the current version for this MEL script. // Used for version control. // // Constraints: Used with assertCurrent(). // //=========================================================================== proc float version() { return ( 1.1 ); } // //////////////////////////////////////////////////////////////// // rootNode // // Description: Strips the dot-suffix of the specified string. // e.g. "object.attribute" is returned as "object" proc string rootNode( string $object ) { string $buffer[]; tokenize $object "." $buffer; return $buffer[0]; } //=========================================================================== // hasInput //=========================================================================== // Description: Returns TRUE if specified attribute has an input connection. // // Constraints: // // Parameters: string $node: The node. // string $attr: The attribute. // // Return: TRUE if specified attribute has an input connection; // else FALSE. // //=========================================================================== proc int hasInput( string $node, string $attr ) { int $hasInput = false; if ( `attributeQuery -node $node -exists $attr` ) { string $c[] = `listConnections -d false -s true ( $node + "." + $attr )`; $hasInput = ( $c[0] != "" ); } return $hasInput; } //=========================================================================== // isMinorType //=========================================================================== // Description: Compares the type of the specified node against those in // a static list. If the type matches it is considered a // minor type. This is used to determine the "significance" // of a connection to a node. If a node's connections serve // only nodes of these types then it is assumed that the node // may be safely deleted without impacting scene requirements. // // Constraints: // // Parameters: string $node: The node to evaluate. // // Return: (int): TRUE if specified node is a minor type; else FALSE. // //=========================================================================== proc int isMinorType( string $node ) { int $isMinorType = false; string $minorNodeTypes[] = { "defaultLightList", "defaultRenderUtilityList", "defaultShaderList", "defaultTextureList", "lightLinker", "materialInfo", "partition" }; string $nodeType = `nodeType $node`; for ( $minor in $minorNodeTypes ) { if ( $minor == $nodeType ) { $isMinorType = true; break; } } return $isMinorType; } //=========================================================================== // hasOnlyMinorOutputConnections //=========================================================================== // Description: Considers all output connections from the specified node // and determines if all of them may be considered "minor." // A minor connection is one which serves only the node in // question and not other parts of the scene. If a node // provides no connections to other significant nodes in the // scene it may be considered safe to delete without impacting // scene requirements. // // Constraints: // // Parameters: string $node: The node to evaluate. // // Return: (int): TRUE if all output connections are minor, or if node // has no output connections; FALSE if at least one // non-minor connection exists. // //=========================================================================== proc int hasOnlyMinorOutputConnections( string $node ) { int $onlyMinorTypes = true; string $outputs[] = `listConnections -s false -d true $node`; for ( $c in $outputs ) { if ( !isMinorType( $c ) ) { $onlyMinorTypes = false; break; } } return $onlyMinorTypes; } //=========================================================================== // safeDelete //=========================================================================== // Description: Deletes the specified node _only_ if it is considered to have // little impact on the scene. // // All nodes providing input connections to the specified node // are evaluated in iterative fashion. // // Constraints: // // Parameters: string $node: The node that will be deleted. // // Return: (none) // //=========================================================================== proc safeDelete( string $node ) { if ( `objExists $node` ) { string $inputs[] = `listConnections -s true -d false $node`; if ( hasOnlyMinorOutputConnections( $node ) ) { delete $node; } for ( $i in $inputs ) { safeDelete( $i ); } } } //=========================================================================== // compareInt //=========================================================================== // Description: Performs an integer comparison for one attribute on // two nodes. // // Constraints: This handles all "int" relatives; e.g. enum, short, bool. // // Parameters: string $node1: The first node. // string $node2: The second node. // string $attr: The attribute for both nodes which is compared. // // Return: (int): TRUE if attributes match; else FALSE. // //=========================================================================== proc int compareInt( string $node1, string $node2, string $attr ) { int $i1 = `getAttr ( $node1 + "." + $attr )`; int $i2 = `getAttr ( $node2 + "." + $attr )`; return ( $i1 == $i2 ); } //=========================================================================== // compareFloat //=========================================================================== // Description: Performs a float comparison for one attribute on // two nodes. // // Constraints: This handles all "float" relatives; e.g. doubleAngle // // Parameters: string $node1: The first node. // string $node2: The second node. // string $attr: The attribute for both nodes which is compared. // // Return: (int): TRUE if attributes match; else FALSE. // //=========================================================================== proc int compareFloat( string $node1, string $node2, string $attr ) { float $f1 = `getAttr ( $node1 + "." + $attr )`; float $f2 = `getAttr ( $node2 + "." + $attr )`; return ( $f1 == $f2 ); } //=========================================================================== // compareFloat2 //=========================================================================== // Description: Performs a float2 comparison (i.e. array of two floats) // for one attribute on two nodes. // // Constraints: // // Parameters: string $node1: The first node. // string $node2: The second node. // string $attr: The attribute for both nodes which is compared. // // Return: (int): TRUE if attributes match; else FALSE. // //=========================================================================== proc int compareFloat2( string $node1, string $node2, string $attr ) { float $f1[2] = `getAttr ( $node1 + "." + $attr )`; float $f2[2] = `getAttr ( $node2 + "." + $attr )`; return ( ( $f1[0] == $f2[0] ) && ( $f1[1] == $f2[1] ) ); } //=========================================================================== // compareFloat3 //=========================================================================== // Description: Performs a vector comparison for one attribute on // two nodes. This would commonly be used to compare // color attributes. // // Constraints: // // Parameters: string $node1: The first node. // string $node2: The second node. // string $attr: The attribute for both nodes which is compared. // // Return: (int): TRUE if attributes match; else FALSE. // //=========================================================================== proc int compareFloat3( string $node1, string $node2, string $attr ) { float $f1[3] = `getAttr ( $node1 + "." + $attr )`; float $f2[3] = `getAttr ( $node2 + "." + $attr )`; return ( ( $f1[0] == $f2[0] ) && ( $f1[1] == $f2[1] ) && ( $f1[2] == $f2[2] ) ); } //=========================================================================== // compareString //=========================================================================== // Description: Performs a string comparison for one attribute on // two nodes. // // Constraints: // // Parameters: string $node1: The first node. // string $node2: The second node. // string $attr: The attribute for both nodes which is compared. // // Return: (int): TRUE if attributes match; else FALSE. // //=========================================================================== proc int compareString( string $node1, string $node2, string $attr ) { string $s1 = `getAttr ( $node1 + "." + $attr )`; string $s2 = `getAttr ( $node1 + "." + $attr )`; return ( $s1 == $s2 ); } //=========================================================================== // compareConnections //=========================================================================== // Description: Compares the connections for one attribute on two nodes. // // If neither attribute is connected, the attributes match. // // If one attribute is connected but the other is not, then // the attributes do not match. // // If both attributes are connected there is a match only if // both connections are to the same node. // // Constraints: // // Parameters: string $node1: The first node. // string $node2: The second node. // string $attr: The attribute for both nodes which is compared. // // Return: (int): TRUE if attributes match; else FALSE. // //=========================================================================== proc int compareConnections( string $node1, string $node2, string $attr ) { // If neither has this attribute, consider it a match. if ( !`attributeQuery -node $node1 -exists $attr` && !`attributeQuery -node $node2 -exists $attr` ) { return true; } // If one has the attribute, but the other doesn't, no match. if ( ( `attributeQuery -node $node1 -exists $attr` && !`attributeQuery -node $node2 -exists $attr` ) || ( !`attributeQuery -node $node1 -exists $attr` && `attributeQuery -node $node2 -exists $attr` ) ) { return false; } string $c1[] = `listConnections -d false -s true ( $node1 + "." + $attr )`; string $c2[] = `listConnections -d false -s true ( $node2 + "." + $attr )`; // TRUE if neither or connected, or both are connected to the same node. return ( $c1[0] == $c2[0] ); } //=========================================================================== // compareAttributes //=========================================================================== // Description: Compares the value for one attribute on two nodes. // The attribute type is used to determine the type of // comparison performed. The attribute must exist on both // nodes, and the attribute type must be the same for both // nodes, else the two do not match. // // Constraints: // // Parameters: string $node1: The first node. // string $node2: The second node. // string $attr: The attribute for both nodes which is compared. // // Return: (int): TRUE if attributes match; else FALSE. // //=========================================================================== proc int compareAttributes( string $node1, string $node2, string $attr ) { int $isEqual = true; // If neither has this attribute, consider it a match. if ( !`attributeQuery -node $node1 -exists $attr` && !`attributeQuery -node $node2 -exists $attr` ) { // Some objects have different attributes than others (e.g. lambert and layered shaders) // warning( "! Attributes don't exist in compareAttributes( " + $node1 + ", " + $node2 + " ) !" ); return true; } // If one has the attribute, but the other doesn't, no match. if ( ( `attributeQuery -node $node1 -exists $attr` && !`attributeQuery -node $node2 -exists $attr` ) || ( !`attributeQuery -node $node1 -exists $attr` && `attributeQuery -node $node2 -exists $attr` ) ) { // This would be a bug. The script should take care that this will not happen. warning( "! Attribute mismatch in compareAttributes( " + $node1 + ", " + $node2 + " ) !" ); return false; } // If one is connected but the other isn't, don't consider them equal. if ( ( hasInput( $node1, $attr ) && !hasInput( $node2, $attr ) ) || ( !hasInput( $node1, $attr ) && hasInput( $node2, $attr ) ) ) { // warning( "! Connection mismatch in compareAttributes( " + $node1 + ", " + $node2 + " ) !" ); return false; } string $attrType1 = `getAttr -type ( $node1 + "." + $attr )`; string $attrType2 = `getAttr -type ( $node2 + "." + $attr )`; if ( $attrType1 != $attrType2 ) return false; switch ( $attrType1 ) { case "bool": case "enum": case "short": { $isEqual = compareInt( $node1, $node2, $attr ); break; } case "doubleAngle": case "float": { $isEqual = compareFloat( $node1, $node2, $attr ); break; } case "float2": { $isEqual = compareFloat2( $node1, $node2, $attr ); break; } case "float3": { // As if this will work... likely a colour attribute and // this will just compare black to black. $isEqual = compareFloat3( $node1, $node2, $attr ); break; } case "string": { $isEqual = compareString( $node1, $node2, $attr ); break; } default: { error ( "Unsupported attribute type: " + $attrType1 ); break; } } return $isEqual; } //=========================================================================== // mergeShadingGroup //=========================================================================== // Description: The two Shading Groups have been deemed to be equal. // The members for the latter are assigned to the former and // the latter is deleted from the scene. // // Constraints: // // Parameters: string $sg1: The Shading Group to keep. // string $sg2: The Shading Group to discard. // // Return: (none) // //=========================================================================== proc mergeShadingGroup( string $sg1, string $sg2 ) { string $members[] = `sets -q $sg2`; if ( `size $members` > 0 ) // just to avert useless Maya warning { sets -forceElement $sg1 $members; } safeDelete( $sg2 ); } //=========================================================================== // compareShadingGroups //=========================================================================== // Description: Compares the connections and attributes for two specified // Shading Groups and evaluates if they can be considered // equivalent. If equivalent, the two are merged. // // Constraints: If the two Shading Groups are equal, $sg2 will likely be // deleted from the scene and will not exist when this function // call returns. // // Parameters: string $sg1: The first Shading Group. // string $sg2: The second Shading Group. // // Return: (int): TRUE if the two Shading Groups are equal; else FALSE. // If TRUE it is likely that $sg2 was deleted. // //=========================================================================== proc int compareShadingGroups( string $sg1, string $sg2 ) { int $isEqual = true; // Has same alpha? $isEqual = $isEqual && compareConnections( $sg1, $sg2, "surfaceShader" ); $isEqual = $isEqual && compareConnections( $sg1, $sg2, "volumeShader" ); $isEqual = $isEqual && compareConnections( $sg1, $sg2, "displacementShader" ); $isEqual = $isEqual && compareAttributes( $sg1, $sg2, "memberWireframeColor" ); if ( $isEqual ) { mergeShadingGroup( $sg1, $sg2 ); } return $isEqual; } //=========================================================================== // mergeMaterial //=========================================================================== // Description: The two Materials have been deemed to be equal. // The former adopts the output connections for the latter and // the latter is deleted from the scene. // // Constraints: // // Parameters: string $sg1: The Material to keep. // string $sg2: The Material to discard. // // Return: (none) // //=========================================================================== proc mergeMaterial( string $mat1, string $mat2 ) { string $c1[] = `listConnections ( $mat1 + ".outColor" )`; string $c2[] = `listConnections ( $mat2 + ".outColor" )`; // If no connection, or if connections are already the same, take no action. if ( ( $c1[0] != "" && $c2[0] != "" ) && ( $c1[0] != $c2[0] ) ) { // Deprecate and delete $mat2 string $cc[] = `listConnections -source false -d true -plugs true ( $mat2 + ".outColor" )`; disconnectAttr ( $mat2 + ".outColor" ) $cc[0]; connectAttr ( $mat1 + ".outColor" ) $cc[0]; safeDelete( $mat2 ); } } //=========================================================================== // compareMaterials //=========================================================================== // Description: Compares the connections and attributes for two specified // Materials and evaluates if they can be considered // equivalent. If equivalent, the two are merged. // // Constraints: If the two Materials are equal, $mat2 will likely be // deleted from the scene and will not exist when this function // call returns. // // Parameters: string $mat1: The first Material. // string $mat2: The second Material. // // Return: (int): TRUE if the two Materials are equal; else FALSE. // If TRUE it is likely that $mat2 was deleted. // //=========================================================================== proc int compareMaterials( string $mat1, string $mat2 ) { int $isEqual = true; $isEqual = $isEqual && compareConnections( $mat1, $mat2, "color" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "color" ); $isEqual = $isEqual && compareConnections( $mat1, $mat2, "transparency" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "transparency" ); $isEqual = $isEqual && compareConnections( $mat1, $mat2, "ambient" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "ambient" ); $isEqual = $isEqual && compareConnections( $mat1, $mat2, "diffuse" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "diffuse" ); $isEqual = $isEqual && compareConnections( $mat1, $mat2, "emissive" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "emissive" ); $isEqual = $isEqual && compareConnections( $mat1, $mat2, "specular" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "specular" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "shininess" ); // Pure3D attributes // '.pddiShaderName' will short-circuit the remainder if shader types aren't equal. $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "pddiShaderName" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "alphaCompare" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "alphaTest" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "blendMode" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "doubleSided" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "dynamicallyLit" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "filterMode" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "isLightMapped" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "isLit" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "isTranslucent" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "K" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "L" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "mipmapmax" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "mipmapmin" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "mmsharpness" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "prelightMode" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "proceduralXRes" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "proceduralYRes" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "shadeMode" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "shininess" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "uvMode" ); $isEqual = $isEqual && compareAttributes( $mat1, $mat2, "vertexShaderName" ); if ( $isEqual ) { // Navigate to each Material and compare them. string $out1[] = `listConnections ( $mat1 + ".outColor" )`; string $out2[] = `listConnections ( $mat2 + ".outColor" )`; mergeMaterial( $mat1, $mat2 ); compareShadingGroups( $out1[0], $out2[0] ); } return $isEqual; } //=========================================================================== // mergeFile //=========================================================================== // Description: The two file textures have been deemed to be equal. // The former adopts the output connections for the latter and // the latter is deleted from the scene. // // Constraints: // // Parameters: string $file1: The file texture to keep. // string $file2: The file texture to discard. // // Return: (none) // //=========================================================================== proc mergeFile( string $file1, string $file2 ) { string $c1[] = `listConnections ( $file1 + ".outColor" )`; string $c2[] = `listConnections ( $file2 + ".outColor" )`; // If no connection, or if connections are already the same, take no action. if ( ( $c1[0] != "" && $c2[0] != "" ) && ( $c1[0] != $c2[0] ) ) { string $cc[] = `listConnections -source false -d true -plugs true ( $file2 + ".outColor" )`; disconnectAttr ( $file2 + ".outColor" ) $cc[0]; connectAttr ( $file1 + ".outColor" ) $cc[0]; safeDelete( $file2 ); } } //=========================================================================== // compareFiles //=========================================================================== // Description: Compares the connections and attributes for two specified // file textures and evaluates if they can be considered // equivalent. If equivalent, the two are merged. // // Constraints: If the two file textures are equal, $file2 will likely be // deleted from the scene and will not exist when this function // call returns. // // Parameters: string $file1: The first file texture. // string $file2: The second file texture. // // Return: (int): TRUE if the two file textures are equal; else FALSE. // If TRUE it is likely that $file2 was deleted. // //=========================================================================== global proc int compareFiles( string $file1, string $file2 ) { int $isEqual = true; // Compare place2d attributes $isEqual = $isEqual && compareAttributes( $file1, $file2, "coverage" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "mirror" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "noiseUV" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "offset" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "uvFilterSize" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "repeatUV" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "rotateFrame" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "rotateUV" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "stagger" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "translateFrame" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "wrapU" ); $isEqual = $isEqual && compareAttributes( $file1, $file2, "wrapV" ); if ( $isEqual ) { // Navigate to each Material and compare them. string $out1[] = `listConnections ( $file1 + ".outColor" )`; string $out2[] = `listConnections ( $file2 + ".outColor" )`; mergeFile( $file1, $file2 ); if ( $out1[0] != "" && $out2[0] != "" ) { $isEqual = compareMaterials( $out1[0], $out2[0] ); } } return $isEqual; } //=========================================================================== // getSortedShadingGroups //=========================================================================== // Description: It is only relevant to compare two Shading Groups for merging // if they share the same Surface Shader. This returns an array // of all Shading Groups sorted by the names of the nodes // connected to their .surfaceShader inputs. // // Constraints: // // Parameters: (none) // // Return: (string[]): Array of all Shading Groups, sorted by their // '.surfaceShader' inputs. // //=========================================================================== proc string[] getSortedShadingGroups() { string $allShadingGroups[]; string $shadingGroups[] = `ls -type "shadingEngine"`; for ( $f in $shadingGroups ) { string $cc[] = `listConnections -d false -s true ( $f + ".surfaceShader" )`; $allShadingGroups[`size $allShadingGroups`] = ( $cc[0] + "*" + $f ); } $allShadingGroups = `sort $allShadingGroups`; clear $shadingGroups; for ( $f in $allShadingGroups ) { string $tokens[]; tokenize $f "*" $tokens; $shadingGroups[`size $shadingGroups`] = $tokens[1]; } return $shadingGroups; } //=========================================================================== // getSortedMaterials //=========================================================================== // Description: It is only relevant to compare two Materials for merging // if they share the same Color connection. This returns an // array of all Materials sorted by the names of the nodes // connected to their .color inputs. // // Constraints: // // Parameters: (none) // // Return: (string[]): Array of all Materials, sorted by their // '.color' inputs. // //=========================================================================== proc string[] getSortedMaterials() { string $allMaterials[]; string $materials[] = `ls -materials`; for ( $f in $materials ) { string $cc[] = `listConnections -d false -s true ( $f + ".color" )`; $allMaterials[`size $allMaterials`] = ( $cc[0] + "*" + $f ); } $allMaterials = `sort $allMaterials`; clear $materials; for ( $f in $allMaterials ) { string $tokens[]; tokenize $f "*" $tokens; $materials[`size $materials`] = $tokens[1]; } return $materials; } //=========================================================================== // getSortedFileTextures //=========================================================================== // Description: It is only relevant to compare two file textures for merging // if they share the same input file. This returns an array // of all file textures sorted by the names of their source // files, obtained from the '.fileTextureName' attribute. // // Constraints: // // Parameters: (none) // // Return: (string[]): Array of all file textures, sorted by their // '.fileTextureName' inputs. // //=========================================================================== proc string[] getSortedFileTextures() { string $allFiles[]; string $files[] = `ls -type "file"`; for ( $f in $files ) { string $ftn = `getAttr ( $f + ".fileTextureName" )`; $allFiles[`size $allFiles`] = ( $ftn + "*" + $f ); } $allFiles = `sort $allFiles`; clear $files; for ( $f in $allFiles ) { string $tokens[]; tokenize $f "*" $tokens; $files[`size $files`] = $tokens[1]; } return $files; } //=========================================================================== // optimizeShadingGroups //=========================================================================== // Description: Entry point to optimize Shading Groups. // // Constraints: Will not attempt to merge Materials that could serve to // optimize Shading Groups. Only Shading Groups already sharing // a common Material will be merged. // // Parameters: (none) // // Return: (none) // //=========================================================================== proc optimizeShadingGroups() { waitCursor -state on; string $sgs[] = getSortedShadingGroups(); int $startSG = `size $sgs`; int $f; for ( $f = 0; $f < `size $sgs` - 1; $f++ ) { // Previous optimization may have deleted this node string $sg1 = ""; while ( $f < `size $sgs` - 1 ) { if ( `objExists $sgs[$f]` ) { $sg1 = $sgs[$f]; break; } $f++; } if ( $sg1 == "" ) break; string $sg2 = $sgs[$f+1]; compareShadingGroups( $sg1, $sg2 ); } $sgs = `ls -type "shadingEngine"`; int $endSG = `size $sgs`; print ( "optimizeShadingGroups removed " + ( $startSG- $endSG ) + " shadingGroups.\n" ); waitCursor -state off; } //=========================================================================== // optimizeMaterials //=========================================================================== // Description: Entry point to optimize Materials. // // Constraints: Will not attempt to merge file textures that could serve to // optimize Materials. Only Materials already sharing a // common file texture node will be merged. // // Parameters: (none) // // Return: (none) // //=========================================================================== global proc optimizeMaterials() { waitCursor -state on; string $materials[] = getSortedMaterials(); int $startCount = `size $materials`; int $f; for ( $f = 0; $f < `size $materials` - 1; $f++ ) { // Previous optimization may have deleted this node string $mat1 = ""; while ( $f < `size $materials` - 1 ) { if ( `objExists $materials[$f]` ) { $mat1 = $materials[$f]; break; } $f++; } if ( $mat1 == "" ) break; string $mat2 = $materials[$f+1]; compareMaterials( $mat1, $mat2 ); } $materials = `ls -materials`; int $endCount = `size $materials`; print ( "optimizeMaterials removed " + ( $startCount - $endCount ) + " materials.\n" ); waitCursor -state off; } //=========================================================================== // optimizeFileTextures //=========================================================================== // Description: Entry point to optimize file textures. // // Constraints: // // Parameters: (none) // // Return: (none) // //=========================================================================== global proc optimizeFileTextures() { waitCursor -state on; string $files[] = getSortedFileTextures(); string $materials[] = `ls -materials`; string $sgs[] = `ls -type "shadingEngine"`; int $startFiles = `size $files`; int $startMaterials = `size $materials`; int $startSG = `size $sgs`; int $f; for ( $f = 0; $f < `size $files` - 1; $f++ ) { // Previous optimization may have deleted this node string $file1 = $files[$f]; $file2 = ""; if ( !`objExists $file1` ) continue; int $g = $f+1; while ( $g < `size $files` - 1 ) { if ( `objExists $files[$g]` ) { $file2 = $files[$g]; break; } $g++; } if ( $file1 != "" && $file2 != "" ) { string $ftn1 = `getAttr( $file1 + ".fileTextureName" )`; string $ftn2 = `getAttr( $file2 + ".fileTextureName" )`; if ( $ftn1 == $ftn2 ) { $isEqual = compareFiles( $file1, $file2 ); } } } $files = `ls -type "file"`; $materials = `ls -materials`; $sgs = `ls -type "shadingEngine"`; int $endFiles = `size $files`; int $endMaterials = `size $materials`; int $endSG = `size $sgs`; print ( "optimizeFileTextures removed: " + ( $startFiles - $endFiles ) + " file textures; " + ( $startMaterials - $endMaterials ) + " materials; " + ( $startSG - $endSG ) + " shadingGroups.\n" ); waitCursor -state off; } //=========================================================================== // optimizeShaders //=========================================================================== // Description: Sorts file textures by their '.fileTextureName' attributes, // and for those whose input file matches compares all input // attributes to see if they can be considered equivalent. // Equivalent file textures are "merged" so one serves the // duties previously served by both. // // Materials and Shading Groups are evaluated and optimized // in similar fashion. // // Constraints: Note that optimizing file textures implies optimization for // the Material connected to the optimized file texture, which // consequently optimizes the Shading Groups connected to // the optimized Material. // // It is not uncommon that the optimizeMaterials() and // optimizeShadingGroups() calls here will yield no additional // results after optimizeFileTextures() has completed its run. // // Parameters: (none) // // Return: (none) // //=========================================================================== global proc optimizeShaders() { optimizeFileTextures(); optimizeMaterials(); optimizeShadingGroups(); } /* source optimizeShaders; optimizeShaders; */