// =========================================================================== // 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. // =========================================================================== // // Assign File Textures to selected surface // proc int findShapeIndex( string $surfaceArray[], string $shapeName ) // // Description: // For a given shape name find and returns its index in the // global active surface array // { int $shapeIdx; int $numbSurfaces = size( $surfaceArray ); for ( $shapeIdx = 0; $shapeIdx < $numbSurfaces; $shapeIdx++ ) { string $longName = $surfaceArray[$shapeIdx]; if ( $longName == $shapeName ) return $shapeIdx; } return -1; } proc string[] uniqueNodeList( string $nodes[] ) // // Description: // Returns a unique list of nodes. Eliminate // all the dublicates. // { string $uniqueNodes[]; int $nodeIndx = 0; for ( $node in $nodes ) { int $found = 0; for ($uNode in $uniqueNodes ) { if ( $node == $uNode ) { $found = 1; break; } } // Add it to the list. if ( $found == 0 ) { $uniqueNodes[$nodeIndx] = $node; $nodeIndx ++; } } return $uniqueNodes; } proc string[] findConnectedShapes( string $shadingEngine ) // // Description: // Returns a list of shape names assigned to a given // shading engine node // { string $shadingPlug = $shadingEngine + ".dagSetMembers"; string $tmpTransNodes[] = `listConnections -s true $shadingPlug`; string $transNodes[] = uniqueNodeList( $tmpTransNodes ); string $shapeNodes[]; int $idx = 0; for ( $trans in $transNodes ) { string $shapes[] = `listRelatives -shapes -pa $trans`; for ( $shape in $shapes ) { // Skip intermediate objects. int $intermediate = `getAttr ($shape + ".intermediateObject")`; if ( $intermediate ) continue; // Add it to the list. $shapeNodes[$idx] = $shape; $idx ++; } } return $shapeNodes; } proc string getMaterialInfoNode( string $messagePlug ) // // Description: // Returns a materialInfo connected through a given message plug // { string $connections[] = `listConnections $messagePlug`; for ( $item in $connections ) { if ( `objectType $item` == "materialInfo" ) return $item; } return ""; } global proc string [] getShadingEngines( string $shape ) // // Description: // Returns a unique list of shading engines for // a given shape. // { // Get all the shading engines. string $shadingEngs[] = `listConnections -d true -t "shadingEngine" $shape`; // Eliminte the dublicates. string $uniqueEngs[] = uniqueNodeList( $shadingEngs ); return $uniqueEngs; } proc string createShadingEngine( string $shape ) // // Description: // Creates a shading engine for a given shape. It is // assumed that the shape does not have a shading engine // assign to it. It returns the shading network // connections. // { string $group = `sets -renderable true -empty`; string $material = `shadingNode -asShader blinn`; string $shadingGroupName = "blinnSG" + $group; rename $group $shadingGroupName; surfaceShaderList -add $shadingGroupName $material; sets -e -forceElement $shadingGroupName $shape; // Return the shading engine connections. string $sEng[] = `listConnections -d true -t "shadingEngine" $shape`; return $sEng[0]; } proc string createFileTextureNode() // // Description: // Creates and returns a file texture node // { // Create a new texture and placement nodes. $cmd = "shadingNode -asTexture " + "file"; string $texture = `eval $cmd`; string $place2d = `shadingNode -asUtility place2dTexture`; // Connect them together fileTexturePlacementConnect( $texture, $place2d ); // we need to make the connection the the filter ourselves. connectAttr ($place2d + ".outUV") ($texture + ".uv"); connectAttr ($place2d + ".outUvFilterSize") ($texture + ".uvFilterSize"); // Return a newly created file texture node. return $texture; } proc int findShapeInSwitchNode( string $shape, string $switchNode ) // // Description: // This function returns an index to the surface int // the switch node if the surface is already connected // to that switch node. Otherwise -1 is returned. // { string $nType = `nodeType $shape`; string $switchPlug = $switchNode + ".input"; string $shapes[]; if ( $nType == "mesh" ) { $shapes = `listConnections -sh 1 -type "mesh" $switchPlug`; } else if ( $nType == "nurbsSurface" ) { $shapes = `listConnections -sh 1 -type "nurbsSurface" $switchPlug`; } else if ( $nType == "subdiv" ) { $shapes = `listConnections -sh 1 -type "subdiv" $switchPlug`; } else { return -1; } int $idx; int $num = size( $shapes ); for ($idx = 0; $idx < $num; $idx++ ) { if ( $shape == $shapes[$idx] ) return $idx; } return -1; } proc string createSwitchNode( string $materialPlug ) // // Description: // Create a switch node and connect it to the materialPlug // { string $switchNode; string $dataType = `getAttr -type $materialPlug`; if ( ( $dataType == "float3") || ( $dataType == "double3") ){ float $color[] = `getAttr $materialPlug`; $switchNode = `shadingNode -asUtility tripleShadingSwitch`; setAttr ($switchNode + ".default") $color[0] $color[1] $color[2]; } else if ( ( $dataType == "float" )|| ( $dataType == "double") ) { float $color = `getAttr $materialPlug`; $switchNode = `shadingNode -asUtility singleShadingSwitch`; setAttr ($switchNode + ".default") $color; } else { error ( (uiRes("m_art3dPaintAssignFileTextures.kUnexpectedAttrType1"))+$dataType ); } // Connect a newly created switch node to the material attribute. connectAttr -f ($switchNode + ".output") $materialPlug; return $switchNode; } proc createMultiFileTexture( string $switchShapes[], string $shadingEng, string $materialAttr ) // // Description: // Creates a switch node and file textures for all shapes // int switchShapes array for the specified attributes and // connectes them properly. // { string $materialConn[] = `listConnections ($shadingEng + ".surfaceShader")`; string $material = $materialConn[0]; string $materialPlug = $material + "." + $materialAttr; string $shaderSG[]; if ( "normalCamera" == $materialAttr ) { string $textures[] = `listConnections $materialPlug`; string $bumpNode; if ( size( $textures ) > 0 ) { string $node = $textures[0]; string $nType = `nodeType $node`; if ( $nType == "bump2d" ) { $bumpNode = $textures[0]; } else { $bumpNode = `shadingNode -asUtility bump2d`; connectAttr -f ($bumpNode + ".outNormal") $materialPlug; } } else { // This is a bump map, so first create bump2d utility node // and connect it to the shader and the texture. $bumpNode = `shadingNode -asUtility bump2d`; connectAttr -f ($bumpNode + ".outNormal") $materialPlug; } // Reassign a material plug. $materialPlug = $bumpNode + ".bumpValue"; } else if ( "displacement" == $materialAttr ) { if( $material == defaultShaderName() ) { $shaderSG = `listConnections ($material + ".outColor")`; if( size( $shaderSG ) == 2 ) { $materialPlug = ($shaderSG[1] + ".displacementShader"); } else if( size( $shaderSG ) == 1 ) // new { $materialPlug = ($shaderSG[0] + ".displacementShader"); // new } else { $msg = "Cannot paint with " + $material + ", shader has multiple shader groups"; warning $msg; } } else { $shaderSG = `listConnections ($material + ".outColor")`; // Note: If size of ShaderGroup is zero, new Shader Group is created if( size( $shaderSG ) == 1 ) { $materialPlug = ($shaderSG[0] + ".displacementShader"); } else if( size( $shaderSG ) > 1 ) { // There are multiple shading group connected with same attribute. $msg = "Cannot paint with " + $material + ", shader has multiple shader groups"; warning $msg; return; } } string $textures[] = `listConnections $materialPlug`; string $dispNode; if ( size( $textures ) > 0 ) { string $node = $textures[0]; string $nType = `nodeType $node`; if ( $nType == "displacementShader" ) { $dispNode = $textures[0]; } else { $dispNode = `shadingNode -asUtility displacementShader`; connectAttr -f ($dispNode + ".displacement") $materialPlug; } } else { // This is a displacement map, so first create displacement Shader utility node // and connect it to the shader and the texture. $dispNode = `shadingNode -asUtility displacementShader`; connectAttr -f ($dispNode + ".displacement") $materialPlug; } // Reassign a material plug. $materialPlug = $dispNode + ".displacement"; } // Proceede only if either nothing is connected to the specified // material attribute or there is already a switch node. string $fileTextureName = ""; string $existingTexture; string $textureAttr; string $switchNodeAttr; string $switchNode; string $textures[] = `listConnections -d off -s on $materialPlug`; if ( size( $textures ) > 0 ) { // There is already a node connected to this attribute // - check if this is a switch node and if not, return. string $node = $textures[0]; string $nType = `nodeType $node`; if ( $nType == "file" ) { // Store the file texture name. string $fileTextureNamePlug = $textures[0] + ".fileTextureName"; $fileTextureName = `getAttr $fileTextureNamePlug`; // Create a switch node and connected to the material node. $switchNode = createSwitchNode( $materialPlug ); $existingTexture = $textures[0]; } else { // We assume here that this is a switch node. $switchNode = $textures[0]; } } else { $switchNode = createSwitchNode( $materialPlug ); } // Get the names of the attributes for the switch node // and the file texture node. string $nType = `nodeType $switchNode`; if ( $nType == "tripleShadingSwitch" ) { $switchNodeAttr = "inTriple"; $textureAttr = "outColor"; } else if ( $nType == "singleShadingSwitch" ) { $switchNodeAttr = "inSingle"; $textureAttr = "outAlpha"; } else { // This is neither a switch nor a file texture node so return. warning((uiRes("m_art3dPaintAssignFileTextures.kNoSwitchNodeConnectedToPaintAttr"))); return; } // Find out how many surfaces are connected to the switch node. string $tmpSwitchPlug = $switchNode + ".input"; string $tmpSwitchConn[] = `listConnections $tmpSwitchPlug`; int $nextMultiIndex = size( $tmpSwitchConn )/2; // Connect the first surface to the existing texture. int $startIdx = 0; if ( $existingTexture != "" ) { string $shape = $switchShapes[0]; string $shapePlug = $shape + ".instObjGroups[0]"; int $srfIdx = findShapeInSwitchNode( $shape, $switchNode ); if ( $srfIdx == -1 ) { string $switchNodeSurfacePlug = $switchNode+".input[" +$nextMultiIndex +"].inShape"; string $switchNodeTexturePlug = $switchNode + ".input[" + $nextMultiIndex + "]." + $switchNodeAttr; string $texture = $existingTexture; string $texturePlug = $texture + "." + $textureAttr; // Connect shape and texture to the switch node. connectAttr -f $shapePlug $switchNodeSurfacePlug; connectAttr -f $texturePlug $switchNodeTexturePlug; if( $textureAttr == "outAlpha" ) { setAttr ($texture + ".alphaIsLuminance") true ; } // Increase the indices. $startIdx ++; $nextMultiIndex ++; } } // Now finally, create file textures for each of the // surfaces and assign pairs (shape+texture) to the // switch node. int $idx; int $switchShapeSize = size( $switchShapes ); for ($idx = $startIdx; $idx<$switchShapeSize; $idx++ ) { // Get the shape and its plug. string $shape = $switchShapes[$idx]; string $shapePlug = $shape + ".instObjGroups[0]"; // We need to check if this surface is already // connected to the switch node. int $srfIdx = findShapeInSwitchNode( $shape, $switchNode ); if ( $srfIdx != -1 ) continue; // Get the switch node plugs. string $switchNodeSurfacePlug = $switchNode+".input[" + $nextMultiIndex +"].inShape"; string $switchNodeTexturePlug = $switchNode + ".input[" + $nextMultiIndex + "]." + $switchNodeAttr; // Create a file texture node and get its plug. string $texture = createFileTextureNode(); string $texturePlug = $texture + "." + $textureAttr; // If the file texture name is not empty, then set // the name of the file texture to that name. if ( $fileTextureName != "" ) { setAttr -type "string" ($texture + ".fileTextureName") $fileTextureName; } // Connect shape and texture to the switch node. connectAttr -f $shapePlug $switchNodeSurfacePlug; connectAttr -f $texturePlug $switchNodeTexturePlug; if( $textureAttr == "outAlpha" ) { setAttr ($texture + ".alphaIsLuminance") true ; } // Increase the indices. $nextMultiIndex ++; } } proc createSingleFileTexture( string $shape, string $shadingEng, string $materialAttr ) // // Description: // Creates a file texture node for a given shape and connects it // to the specified attribute on the material (shader) node // { // Get the material node string $textureAttr = ""; string $materialConn[] = `listConnections ($shadingEng + ".surfaceShader")`; string $material = $materialConn[0]; string $msg = $shadingEng + " cannot paint the current attribute because there is a non-file texture connected."; // Proceede only if nothing is no file texture node connected. string $textures[]; string $dispShadingGroupShader; string $shaderSG[]; if( $materialAttr == "displacement" ) { if( $material == defaultShaderName() ) { $shaderSG = `listConnections ($material + ".outColor")`; if( size( $shaderSG ) == 2 ) { $dispShadingGroupShader = ($shaderSG[1] + ".displacementShader"); } else if( size( $shaderSG ) == 1 ) { $dispShadingGroupShader = ($shaderSG[0] + ".displacementShader"); } else { $msg = " Cannot paint with " + $material + ", shader has multiple shader groups"; warning $msg; return; } } else { $shaderSG = `listConnections ($material + ".outColor")`; // Note: If size of ShaderGroup is zero, new Shader Group is created if( size( $shaderSG ) == 1 ) { $dispShadingGroupShader = ($shaderSG[0] + ".displacementShader"); } else if( size( $shaderSG ) > 1 ) { // There are multiple shading group connected with same attribute. $msg = " Cannot paint with " + $material + ", shader has multiple shader groups"; warning $msg; return; } } $textures = `listConnections ($dispShadingGroupShader)`; } else { $textures = `listConnections ($material + "." + $materialAttr)`; } if ( "normalCamera" == $materialAttr ) { string $bumpNode = ""; if ( size( $textures ) > 0 ) { string $nType = `nodeType $textures[0]`; if ( $nType == "bump2d" ) { // There is already a bymp node connected. $bumpNode = $textures[0]; // Check if there is also a file texture node there. string $bumpConns[] = `listConnections ($bumpNode + ".bumpValue")`; if ( size( $bumpConns ) > 0 ) { $nType = `nodeType $bumpConns[0]`; if ( $nType != "file" ) { // Print a warning if there is anything else connected. warning $msg; } return; } } else { // There only node allowed here is bump node. $msg = $shadingEng + " cannot paint the current attribute because there is a no bump node connected."; warning $msg; return; } } // If there is not bump node, create it and // connect it to the shader. if ( $bumpNode == "" ) { $bumpNode = `shadingNode -asUtility bump2d`; connectAttr ($bumpNode + ".outNormal") ($material + "." + $materialAttr); } // Finally, create a file texture node and connect it to the bump node. string $texture = createFileTextureNode(); connectAttr ($texture + ".outAlpha") ($bumpNode + ".bumpValue"); setAttr ($texture + ".alphaIsLuminance") true ; } else if ( "displacement" == $materialAttr ) { string $dispNode = ""; if ( size( $textures ) > 0 ) { string $nType = `nodeType $textures[0]`; if ( $nType == "displacementShader" ) { // There is already a disp node connected. $dispNode = $textures[0]; // Check if there is also a file texture node there. string $dispConns[] = `listConnections ($dispNode + ".displacement")`; if ( size( $dispConns ) > 0 ) { $nType = `nodeType $dispConns[0]`; if ( $nType != "file" ) { // Print a warning if there is anything else connected. warning $msg; } return; } } else { // There only node allowed here is disp node. $msg = $shadingEng + " cannot paint the current attribute because there is a no displacement node connected."; warning $msg; return; } } // If there is not disp node, create it and // connect it to the shader. if ( $dispNode == "" ) { $dispNode = `shadingNode -asUtility displacementShader`; connectAttr ($dispNode + ".displacement") ($dispShadingGroupShader); } // Finally, create a file texture node and connect it to the bump node. string $texture = createFileTextureNode(); connectAttr ($texture + ".outAlpha") ($dispNode + ".displacement"); setAttr ($texture + ".alphaIsLuminance") true ; } else { // Check if there is already a node connected to the attribute. if ( size( $textures ) > 0 ) { string $nType = `nodeType $textures[0]`; if ( $nType != "file" ) { // Print a warning if there is no file texture node connected. warning $msg; } return; } // Create a file texture node. string $texture = createFileTextureNode(); // Get the texture attribute name (plug). string $materialPlug = $material + "." + $materialAttr; string $dataType = `getAttr -type $materialPlug`; if ( ( $dataType == "float3") || ( $dataType == "double3") ){ $textureAttr = "outColor"; } else if ( ( $dataType == "float" ) || ( $dataType == "double" ) ) { $textureAttr = "outAlpha"; setAttr ($texture + ".alphaIsLuminance") true ; } else { error ( (uiRes("m_art3dPaintAssignFileTextures.kUnexpectedAttrType2"))+$dataType ); } // Make the specified by the user connection. connectAttr ($texture + "." + $textureAttr) ($material + "." + $materialAttr); } } proc setChannelColorValues(string $shadingEng, string $channel) { float $colors[4]; string $shaders[] = `listConnections ($shadingEng + ".surfaceShader")`; string $gAttributeSelected = $shaders[0] + "." + $channel ; if($channel == "displacement") { $gAttributeSelected = $shadingEng + ".displacementShader" ; } string $variableType = `getAttr -type $gAttributeSelected `; string $cmd = "getAttr " + $gAttributeSelected; // We are already overwriting the values of displacement and normal camera. if($variableType != "" && $channel != "displacement" && $channel != "normalCamera") { if(($variableType == "float") || ($variableType == "double") ){ float $colorVal = eval($cmd); $colors[0] = $colors[1] = $colors[2] = $colorVal ; }else{ float $colorVals[3] = eval($cmd); $colors[0] = $colorVals[0] ; $colors[1] = $colorVals[1] ; $colors[2] = $colorVals[2] ; } } // The optionVar is identified as "shader.displacement" so that // while quering for the color we have the proper shader there. if($channel == "displacement") { $gAttributeSelected = $shaders[0] + "." + $channel ; } if($channel == "normalCamera") { $colors[0] = $colors[1] = $colors[2] = 0.5 ; } else if ($channel == "displacement") { $colors[0] = $colors[1] = $colors[2] = 0.0 ; } $colors[3] = 1.0; $gAttributeSelected = "art" + $gAttributeSelected; optionVar -clearArray $gAttributeSelected; optionVar -floatValueAppend $gAttributeSelected $colors[0] -floatValueAppend $gAttributeSelected $colors[1] -floatValueAppend $gAttributeSelected $colors[2] -floatValueAppend $gAttributeSelected $colors[3]; } global proc art3dPaintAssignFileTextures( string $materialAttr ) // // Description: // Traverse the selection list, and if necessary create file textures // for all surfaces which are on the list. The user specifies a material // node attribute to which the connection with the file texture needs to // exist. If the file texture on this attribute already exists, nothing // is done, otherwise a file texture node with a dummy texture is created // and connected to the shape node. Paint tool has to allocate a physical // image for the file texture and change the name into a proper one. // { // Get the active surfaces from the paint color context // and initialize the global tables. string $activeSrfArray[]; string $srfNames = eval("art3dPaintCtx -q -shapenames `currentCtx`"); if ( size( $srfNames ) == 0 ) return; int $numbActiveSrf = `tokenize $srfNames $activeSrfArray`; int $surfaceHasTexture[]; for ( $idx = 0; $idx < $numbActiveSrf; $idx++ ) { $surfaceHasTexture[$idx] = 0; } int $shapeAttr = eval( "art3dPaintCtx -q -shapeattr `currentCtx`"); if( $shapeAttr ) { for ( $idx = 0; $idx < $numbActiveSrf; $idx++ ) { // Get the surface. string $shape = $activeSrfArray[$idx]; if ( $shape == "" ) continue; if ( $surfaceHasTexture[$idx] == 1 ) continue; // bail if the attr doesn't exist string $attr = $shape + "." + $materialAttr; string $cmd = "objExists " + $attr; if ( eval($cmd) == 0 ) continue; // bail if there is already a connection. $cmd = "listConnections -s 1 -d 0 " + $attr; $textures = eval( $cmd ); if ( size( $textures ) > 0 ) { string $nType = `nodeType $textures[0]`; if ( $nType != "file" ) { // Print a warning if there is no file texture node connected. string $msg = $shape + " cannot paint the current attribute because there is a non-file texture connected."; warning $msg; } continue; } string $texture = createFileTextureNode(); // determine if its a 3 or 1 channel attr $srcAttr = "outColor"; $cmd = "getAttr -type " + $attr; $type = eval( $cmd ); float $colors[4]; if( $type == "float" || $type == "double" ) { $srcAttr = "outAlpha"; float $colorVal = eval( "getAttr " + $attr ); $colors[0] = $colors[1] = $colors[2] = $colorVal ; } else { float $colorVals[3] = eval( "getAttr " + $attr ); $colors[0] = $colorVals[0] ; $colors[1] = $colorVals[1] ; $colors[2] = $colorVals[2] ; } // set this optionVar, which seems to be used to fill the default color of the texture // to the current value of the attribute. $colors[3] = 1.0; $attr = "art" + $attr; optionVar -clearArray $attr; optionVar -floatValueAppend $attr$colors[0] -floatValueAppend $attr $colors[1] -floatValueAppend $attr $colors[2] -floatValueAppend $attr $colors[3]; // connect file to shape $cmd = "connectAttr " + $texture + "." + $srcAttr + " " + $shape + "." + $materialAttr; eval($cmd); $surfaceHasTexture[$idx] = 1; } } else { // Now generate file textures. for ( $idx = 0; $idx < $numbActiveSrf; $idx++ ) { // Get the surface. string $shape = $activeSrfArray[$idx]; if ( $shape == "" ) continue; if ( $surfaceHasTexture[$idx] == 1 ) continue; // Find the shading engine ( if it does not exist, create one ). string $sEng[] = getShadingEngines( $shape ); int $sEngSize = size( $sEng ); if ( $sEngSize == 0 ) { $sEng[0] = createShadingEngine( $shape ); $sEngSize = 1; } for ( $sIdx = 0; $sIdx < $sEngSize; $sIdx++ ) { // Get the shading engine. string $shadingEng = $sEng[$sIdx]; // Store the color values before connections are made setChannelColorValues($shadingEng, $materialAttr); // Find out how many surfaces are connected to this shading engine // and if there is more than one, then we need a switch node. string $tmpShapes[] = findConnectedShapes( $shadingEng ); int $tmpNumShapes = size( $tmpShapes ); if ( $tmpNumShapes > 1 ) { // Eliminate all the shapes which are not selected. string $switchShapes[]; int $ii = 0; for ( $shapeName in $tmpShapes ) { int $shapeIdx = findShapeIndex( $activeSrfArray, $shapeName ); if ( $shapeIdx == -1 ) continue; // Add surface to the list. $switchShapes[$ii] = $shapeName; // Mark the surface so we don't try to create // a texture node again for it. $surfaceHasTexture[$shapeIdx] = 1; $ii ++; } // Create a switch node. createMultiFileTexture( $switchShapes, $shadingEng, $materialAttr ); } else { // Create a single texture. createSingleFileTexture( $shape, $shadingEng, $materialAttr ); // Mark the surface. $surfaceHasTexture[$idx] = 1; } } } } }