// =========================================================================== // 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. // =========================================================================== // // // // // createNCloth( int $worldSpace ) // // // string array containing all the created nodes // // // This turns all the selected objects into nCloth. The current nucleus node is used or a new one // is created if none yet exist. // // // int $worldSpace if true, then the cache and current positions maintained in worldspace, rather than relative to the object transform // // // polyPlane; // createNCloth false; // global proc string[] createNCloth( int $worldSpace ) // // Description: // // Given a selected list of meshes, clothify them // i.e. for each mesh, create an nCloth node, and an output mesh // leave the resulting nCloth nodes selected. // TODO - what if the mesh is already input into an nObject node? // { string $selected[] = `ls -sl`; // Get the selected meshes // string $meshes[] = `listRelatives -f -ni -s -type "mesh" $selected`; int $numMeshes = size($meshes); if( $numMeshes == 0 ){ warning((uiRes("m_createNCloth.kNoMeshSelected"))); return {}; } // TODO: If you had already selected an nBase or nCloth, we should probably // tell you you're being silly // If there is one selected, we're done // if there's more than one, need to do something // if there's none selected, we could if there exactly one unselected one // but for now, we'll just create a new one // string $nucleuses[] = `ls -type "nucleus" $selected`; string $nucleus = getActiveNucleusNode( false, // selectExisting true ); // createNew // Find the mesh(es) that have no nBase associated with them // and setup an nCloth node for each. // string $nCloth; string $mesh; string $outMeshName = "outputCloth#"; string $newClothNodes[]; for ($mesh in $meshes ){ string $conns[] = `listConnections -sh 1 -type "nBase" $mesh`; if( size($conns) == 0 ){ // This mesh has no nBase associated with it, so connect it // string $meshTforms[] = `listTransforms $mesh`; string $tform = $meshTforms[0]; // TODO - handle instances // $nCloth = `createNode nCloth -parent $tform`; $nCloth = `createNode nCloth`; // Hide the particle attributes from display in the channel box // hideParticleAttrs( $nCloth ); $newClothNodes[size($newClothNodes)] = $nCloth; connectAttr time1.outTime ($nCloth + ".currentTime"); // Check if this mesh is already being used as an input to the // driverPoints attribute of a wrap deformer. // string $wrapPlugs[] = `listConnections -d 1 -p 1 -sh 1 -type "wrap" ($mesh + ".worldMesh")`; connectAttr ($mesh + ".worldMesh") ($nCloth + ".inputMesh"); // Create a mesh node, and hook it up as output // // TODO - need better name for output mesh string $outMesh; if( !$worldSpace ){ $outMesh = `createNode mesh -parent $tform -name ($outMeshName)`; setAttr ($nCloth + ".localSpaceOutput") true; } else { $outMesh = `createNode mesh -name ($outMeshName)`; } string $shadCons[] = `listConnections -d 1 -sh 1 -type "shadingEngine" ($mesh + ".instObjGroups[0]")`; if( size( $shadCons ) > 0 && !`about -batch`){ hyperShade -assign $shadCons[0]; // outMesh should be currently selected } else { sets -add initialShadingGroup $outMesh; } setAttr ($outMesh + ".quadSplit") 0; //match ncloth quad tessellation connectAttr ($nCloth + ".outputMesh") ($outMesh + ".inMesh"); addActiveToNSystem($nCloth, $nucleus); connectAttr ($nucleus + ".startFrame") ($nCloth +".startFrame"); setAttr ($mesh + ".intermediateObject") 1; string $clothTforms[] = `listTransforms $nCloth`; setAttr -l true ($clothTforms[0] + ".translate"); setAttr -l true ($clothTforms[0] + ".rotate"); setAttr -l true ($clothTforms[0] + ".scale"); //setAttr ($mesh + ".visibility") 0; // setAttr ($nCloth + ".visibility") 0; //setAttr ($nCloth + ".intermediateObject") 1; // Try to pick a reasonably good default thickness // float $bbox[] = `exactWorldBoundingBox $mesh`; float $x = ( $bbox[3] - $bbox[0] ); float $y = ( $bbox[4] - $bbox[1] ); float $z = ( $bbox[5] - $bbox[2] ); float $bboxSurfaceArea = 2 * (($x*$y) + ($x*$z) + ($y*$z)); int $numFaces[] = `polyEvaluate -face $mesh`; float $maxRatio = 0.005; // ratio of width to bounding box size; float $minWidth = 0.0001;// min width for precision issues float $objSize = sqrt( $bboxSurfaceArea ); float $newWidth = $objSize * $maxRatio; if( $numFaces[0] > 0 ) { float $estimatedEdgeLength = sqrt($bboxSurfaceArea / $numFaces[0]); float $thickness = 0.13 * $estimatedEdgeLength; if( $thickness > $newWidth ){ setAttr( $nCloth + ".selfCollisionFlag" ) 3; // vertex face } else { $newWidth = $thickness; setAttr( $nCloth + ".selfCollideWidthScale" ) 3; } } if( $newWidth < $minWidth ){ $newWidth = $minWidth; } setAttr ($nCloth + ".thickness") $newWidth; setAttr ($nCloth + ".pushOutRadius") ($newWidth * 4.0); // Now for each wrap deformer that was using the input surface // as an input to the driverPoints attribute, transfer the // connection to the output surface. // if( !`exists transferWrapConns` ){ source "removeNCloth.mel"; } transferWrapConns( $wrapPlugs, $outMesh ); } } // if we're in batch mode, need to force update to properly // initialize the start frame if( `about -batch` ) { for( $cloth in $newClothNodes) { getAttr ($cloth + ".forceDynamics"); } } select $newClothNodes; return $newClothNodes; }