// Copyright (C) 1997-2000 Alias|Wavefront, // a division of Silicon Graphics Limited. // // The information in this file is provided for the exclusive use of the // licensees of Alias|Wavefront. Such users have the right to use, modify, // and incorporate this code into other products for purposes authorized // by the Alias|Wavefront license agreement, without fee. // // ALIAS|WAVEFRONT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, // INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO // EVENT SHALL ALIAS|WAVEFRONT BE LIABLE FOR ANY SPECIAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, // DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. // // // Alias|Wavefront Script File // MODIFY THIS AT YOUR OWN RISK // // Creation Date: 16 September 1997 // // // Procedure Name: // copyConvertSolidTx // // Description: // Procedure to execute convertSolidTx using the contents of the // multi-lister highlight list and the selection list. The nodes // downstream of the highlighted texture will be duplicated, and // the surface on the selection list will be added the new // shading group. // // The multi-lister highlight list will be updated to contain the // new nodes on successful completion of the command. // // Input Arguments: // antiAlias - toggle whether anti-aliasing should be done. // bakeLighting - true if the baked lighting is desired. // resX - X resolution of convert solid texture. // resY - Y resolution of convert solid texture. // // Return Value: // None. // proc string plugAttr( string $plug ) { string $buffer[]; tokenize($plug, ".", $buffer); return $buffer[1]; } proc string plugNode( string $plug ) { string $buffer[]; tokenize($plug, ".", $buffer); return $buffer[0]; } proc addLast( string $itemArray[], string $item ) { $itemArray[size($itemArray)] = $item; } proc removeArrayElement( string $element, string $array[] ) { string $tmp[]; for ($item in $array) { if ($element != $item) addLast($tmp, $item); } clear($array); for ($i = 0; $i < size($tmp); $i += 1) $array[$i] = $tmp[$i]; } proc downStreamConnections( string $node, string $result[] ) { string $connections[] = `listConnections -connections true -plugs true -source false -destination true $node`; // Foreach destination (output) connection on node. for ($i = 0; $i < size($connections); $i += 2) { // All message connections are skipped. if (plugAttr($connections[$i]) != "message") { addLast($result, $connections[$i]); addLast($result, $connections[$i+1]); } } } proc downStreamNetwork( string $node, string $result[] ) { // Check if node is already in result. for ($item in $result) { if ($item == $node) return; } addLast($result, $node); // Do a depth first traversal to find the shading group. if (`objectType $node` == "shadingEngine") { if ($node == "initialShadingGroup" || $node == "initialParticleSE") error("Cannot convert a texture connected to "+$node); } else { string $connections[]; downStreamConnections($node, $connections); for ($i = 0; $i < size($connections); $i += 2) { string $dstPlug = $connections[$i + 1]; string $dstNode = plugNode($dstPlug); downStreamNetwork($dstNode, $result); } } } proc addSurfaceToNetwork( string $network[], string $surface ) { for ($item in $network) { if (`objectType $item` == "shadingEngine") { sets -e -forceElement $item $surface; break; } } } proc int countGroupsInNetwork( string $network[] ) { int $count = 0; for ($item in $network) if (`objectType $item` == "shadingEngine") $count += 1; return $count; } proc substituteFileTexture( string $network[], string $oldPlug, string $newFile ) { string $connections[] = `listConnections -plugs true -source false -destination true $oldPlug`; // Foreach output connection on the substituted plug for ($dstPlug in $connections) { string $dstNode = plugNode($dstPlug); // Find the corresponding node in the network. for ($item in $network) { if ($item == $dstNode) { // Break the connection between the network and the // old node, and replace it with a connection to new. disconnectAttr $oldPlug $dstPlug; // The file attribute used for the connection depends // on the number of children in the destination plug. string $attributes[] = `listAttr $oldPlug`; int $count = size($attributes); if ($count == 4) // parent + 3 children connectAttr ($newFile+".outColor") $dstPlug; else if ($count == 1) connectAttr ($newFile+".outAlpha") $dstPlug; } } } } proc substituteNode(string $network[], string $old, string $new ) { string $connections[] = `listConnections -connections true -plugs true -source false -destination true $old`; // Foreach output connection on the substituted node. for ($i = 0; $i < size($connections); $i += 2) { string $srcPlug = $connections[$i]; string $dstPlug = $connections[$i + 1]; string $dstNode = plugNode($dstPlug); // Find the corresponding node in the network. for ($item in $network) { if ($item == $dstNode) { // Break the connection between the network and the // old node, and replace it with a connection to new. disconnectAttr $srcPlug $dstPlug; // Make the new connection instead connectAttr ($new+"."+plugAttr($srcPlug)) $dstPlug; } } } } proc string[] duplicateNetwork( string $network[] ) { string $newNetwork[]; // Are there nodes to duplicate? if (size($network) > 0) { string $duplicateCmd = "duplicate -inputConnections"; // There is currently a bug in duplicate with input connections, // the specified nodes must be sorted by the depth (ie. from texture // to shader to shading group or leaf to root). // // In convert solid, the network was produced by invoking // downstreamNetwork which will produce the a list in the correct // order. for ($node in $network) $duplicateCmd += " " + $node; $newNetwork = `eval($duplicateCmd)`; } return $newNetwork; } proc doConvertTexture( int $antiAlias, int $resX, int $resY, int $shadow, string $surface, string $texture, string $result[] ) { // Get all connections downstream from the texture including // itself. If the texture is a bump node we generate the // connections to reflect the texture connected to the bump. // string $connections[]; string $type = `objectType $texture`; if ($type == "bump2d" || $type == "bump3d") { string $bumpPlug = $texture+".bumpValue"; $connections = `listConnections -plugs true $bumpPlug`; addLast($connections, $bumpPlug); } else { downStreamConnections($texture, $connections); } // Determine the minimum number of nodes to duplicate. // string $network[]; for ($i = 0; $i < size($connections); $i += 2) { string $dstPlug = $connections[$i + 1]; string $downStreamNode = plugNode($dstPlug); string $dstType = `objectType $downStreamNode`; if ($dstType == "bump2d" || $dstType == "bump3d") { downStreamNetwork($downStreamNode, $network); // Remove the bump node from network. removeArrayElement($downStreamNode, $network); } else { downStreamNetwork($downStreamNode, $network); } } if (countGroupsInNetwork($network) > 1) { error($texture+" is connected to more than one shading group"); } string $newNetwork[] = duplicateNetwork($network); addSurfaceToNetwork($newNetwork, $surface); for ($newNode in $newNetwork) addLast($result, $newNode); // Now run convert solid texture on each channel. // for ($i = 0; $i < size($connections); $i += 2) { string $srcPlug = $connections[$i]; string $dstPlug = $connections[$i + 1]; string $downStreamNode = plugNode($dstPlug); string $dstType = `objectType $downStreamNode`; if ($dstType == "bump2d" || $dstType == "bump3d") { // Execute convert solid texture on the surface. string $fileTextures[] = `convertSolidTx -antiAlias $antiAlias -resolutionX $resX -resolutionY $resY -shadows $shadow $surface $srcPlug`; string $newFile = $fileTextures[0]; // there is only one // Connect the file and new bump. string $newBump = `shadingNode -asUtility bump2d`; float $depth = `getAttr ($downStreamNode+".bumpDepth")`; setAttr ($newBump+".bumpDepth") $depth; connectAttr ($newFile+".outAlpha") ($newBump+".bumpValue"); substituteNode($newNetwork, $downStreamNode, $newBump); // Append the new nodes to result. addLast($result, $newFile); addLast($result, $newBump); } else { // Execute convert solid texture on the surface. string $fileTextures[] = `convertSolidTx -antiAlias $antiAlias -resolutionX $resX -resolutionY $resY $surface $srcPlug`; string $newFile = $fileTextures[0]; // there is only one substituteFileTexture($newNetwork, $srcPlug, $newFile); // Append the new nodes to result. addLast($result, $newFile); } } } proc doConvertShader( int $antiAlias, int $resX, int $resY, int $shadow, string $surface, string $shader, string $result[] ) { // Get all nodes downstream and including the shader. // string $network[]; downStreamNetwork($shader, $network); if (countGroupsInNetwork($network) > 1) { error($shader+" is connected to more than one shading group"); } // Get all incoming connections to the shader. Convert solid // texture will be run on each of these channels. // string $connections[]; $connections = `listConnections -destination false -source true -plugs true $shader`; // Get only the unique connections. // string $uniqueConnections[]; for ($item in $connections) { int $found = false; for ($uniqueItem in $uniqueConnections) { if ($item == $uniqueItem) { $found = true; break; } } if (!$found) addLast($uniqueConnections, $item); } string $newNetwork[] = duplicateNetwork($network); addSurfaceToNetwork($newNetwork, $surface); // Execute convert solid on each input for ($texturePlug in $uniqueConnections) { string $textureNode = plugNode($texturePlug); string $textureType = `objectType $textureNode`; if ($textureType == "bump2d" || $textureType == "bump3d") { string $fileTextures[] = `convertSolidTx -antiAlias $antiAlias -resolutionX $resX -resolutionY $resY $surface ($textureNode+".bumpValue")`; string $newFile = $fileTextures[0]; // there is only one string $newBump = `shadingNode -asUtility bump2d`; float $depth = `getAttr ($textureNode+".bumpDepth")`; setAttr ($newBump+".bumpDepth") $depth; connectAttr ($newFile+".outAlpha") ($newBump+".bumpValue"); substituteNode($newNetwork, $textureNode+".outNormal", $newBump); // Append the new nodes to result addLast($result, $newFile); addLast($result, $newBump); } else { string $fileTextures[] = `convertSolidTx -antiAlias $antiAlias -resolutionX $resX -resolutionY $resY -shadows $shadow $surface $texturePlug`; string $newFile = $fileTextures[0]; // there is only one substituteFileTexture($newNetwork, $texturePlug, $newFile); // Append the new nodes to result addLast($result, $newFile); } } // Append the new nodes to result for ($newNode in $newNetwork) addLast($result, $newNode); } proc doConvertBakeLighting( int $antiAlias, int $resX, int $resY, int $shadow, string $surface, string $shadingGroup, string $result[] ) { string $connections[] = `listConnections -plugs true ($shadingGroup+".surfaceShader")`; if (size($connections) != 1) error($shadingGroup+" does not have a surface shader"); string $srcPlug = $connections[0]; // The network contains only the shading group. string $network[]; addLast($network, $shadingGroup); // Execute convert solid texture on the surface. string $fileTextures[] = `convertSolidTx -antiAlias $antiAlias -resolutionX $resX -resolutionY $resY -shadows $shadow $surface $shadingGroup`; string $newFile = $fileTextures[0]; // there is only one string $newNetwork[] = duplicateNetwork($network); addSurfaceToNetwork($newNetwork, $surface); substituteFileTexture($newNetwork, $srcPlug, $newFile); // Append the new nodes to result. addLast($result, $newFile); for ($newNode in $newNetwork) addLast($result, $newNode); } proc getBaseClasses( string $nodeType, string $result[] ) { string $classes[]; string $codedClassification[] = `getClassification $nodeType`; tokenize($codedClassification[0], ":", $classes); for ($class in $classes) { string $buffer[]; tokenize($class, "/", $buffer); addLast($result, $buffer[0]); } } global proc copyConvertSolidTx( int $antiAlias, int $bakeLighting, int $resX, int $resY, int $shadow, int $useMultilisterHighlighted) { string $surfaces[], $node = ""; // Get the surfaces and texture from the selection. // string $selection[] = `ls -showType -selection`; for ($i = 0; $i < size($selection); $i += 2) { string $selectNode = $selection[$i]; string $type = $selection[$i + 1]; if ($type == "nurbsSurface" || $type == "mesh" || $type == "subdiv" || $type == "transform") { addLast($surfaces, $selectNode); } else { string $classes[]; getBaseClasses($type, $classes); for ($class in $classes) { if ($class == "texture" || $class == "utility" || $class == "shader" || $class == "shadingEngine") { if ($node != "") { error("Only one shading node can be converted,"+ " there is more than one selected"); } $node = $selectNode; break; } else { error($selectNode+" is not a shading node"); } } } } if (size($surfaces) == 0) error("No surfaces selected, unable to continue"); // Get the texture from multi-lister if a node has not been specified. // string $currentLister = ""; if ($node == "" && $useMultilisterHighlighted) { string $editors[] = `lsUI -editors`; for ($item in $editors) { if (`listerEditor -exists $item`) { string $highlight[] = `listerEditor -q -highlight $item`; if (size($highlight) == 1) { $node = $highlight[0]; $currentLister = $item; break; } else if (size($highlight) > 1) { error("Only one shading node can be converted,"+ " there is more than one highlighted"); } } } } if ($node == "") { error("Select or highlighted a shading node, unable to continue"); } // Determine the type of node to be converted. // int $isGroup = false; int $isTexture = false; int $isShader = false; string $nodeType = `objectType $node`; if ($nodeType == "shadingEngine") { if (!$bakeLighting) { // The user probably mean't to run this on the shader not // the shading group. Use the node connected to the // surface shader attribute instead. string $connections[]; $connections = `listConnections ($node+".surfaceShader")`; if (size($connections) > 0) { $node = $connections[0]; $nodeType = `objectType $node`; } } } if ($nodeType == "layeredShader") { // The layered shader is special because it may contain other // shader nodes upstream. We will be unable to to convert the // lighting component on these. int $layeredType = `getAttr ($node+".compositingFlag")`; if ($layeredType != 1) { error("Unable to convert "+$node+", re-organize your network"+ " to use a layered texture instead of a layered shader"+ " or use the baked lighting option"); } } string $classes[]; getBaseClasses($nodeType, $classes); for ($class in $classes) { if ($class == "shadingEngine") { $isGroup = true; } else if ($class == "texture" || $class == "utility") { $isTexture = true; } else if ($class == "shader") { $isShader = true; } } if ($bakeLighting && !$isGroup) { error($node+" is not a shading group, convert with baked lighting"+ " can only be done on a shading group"); } if (!$isGroup && !$isTexture && !$isShader) { error($node+" is not a shading node, unable to continue"); } // Do the appropriate convert solid depending on whether its a // texture, shader, or shading group. // string $newNodes[]; for ($surface in $surfaces) { if ($isTexture) { doConvertTexture($antiAlias, $resX, $resY, $shadow, $surface, $node, $newNodes); } else if ($isShader) { doConvertShader($antiAlias, $resX, $resY, $shadow, $surface, $node, $newNodes); } else if ($isGroup) { doConvertBakeLighting($antiAlias, $resX, $resY, $shadow, $surface, $node, $newNodes); } } // Highlight or select the created nodes. // if (size($newNodes) > 0) { // Did we get the node from the multi-lister? if ($currentLister != "") { string $highlightArgs = ""; for ($item in $newNodes) { $highlightArgs += " -highlight " + $item; } listerEditor -e -clearHighlight $currentLister; eval("listerEditor -e"+$highlightArgs+" "+$currentLister); } else { string $selectArgs = ""; for ($item in $newNodes) { $selectArgs += " " + $item; } eval("select"+$selectArgs); } } }