// =========================================================================== // 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. // =========================================================================== // // makeCollideEffect.mel // // Description: // Interface for creating a collider for an Effects Asset // // Arguments: // None. // // global proc string[] makeCollideEffect(string $effect) // // Description: // // Given a selected list of meshes, collide them with the // Nucleus solver of the specified effect. // If it doesn't have a published solver, perhaps it has a fluid // { // string $selected[] = `ls -sl`; // Get the selected meshes // // string $meshes[] = `listRelatives -ni -s -type "mesh" $selected`; // $meshes = `ls -visible $meshes`; string $meshes[] = `ls -ni -sl -dag -type "mesh"`; int $numMeshes = size($meshes); if( $numMeshes == 0 ){ warning((uiRes("m_makeCollideEffect.kNoMeshSelected"))); return {}; } // so we need to find some potential collision meshes // and we need to find a nucleus system for them to collide with // // 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 $nucleus = getPublishedEffectNode( $effect, "nucleusSolver"); if (size($nucleus) == 0) { warning((uiRes("m_makeCollideEffect.kNoSolverInEffect"))); return {}; } // The selected objects hopefully include a cloth mesh and a potential collision mesh // So we'll go through the selected meshes, set aside the ones that aren't already // downstream of a cloth mesh. We'll also keep track of the nBase nodes for // the ones that ARE cloth, so that we can hook up the collision meshes to their nucleus string $nBase; string $mesh; string $inputMeshes[]; for( $mesh in $meshes ){ $nBase = findTypeInHistory( $mesh, "nCloth", 0, 1 ); if( $nBase == "" ) { $inputMeshes[size($inputMeshes)] = $mesh; } } if( size($inputMeshes) == 0 ){ warning((uiRes("m_makeCollideEffect.kNothingToMakePassive"))); return {}; } // We've found enough things, do the collision setup // string $nRigid; string $newRigidNodes[] = {}; for( $mesh in $inputMeshes ){ // check to see if this mesh is already in collision with the // specified nucleus node $nBase = findTypeInHistory( $mesh, "nRigid", 1, 0 ); int $createNRigid = true; if( $nBase != "" ){ string $acN[] = `listConnections ($nBase + ".currentState" )`; if( size($acN) > 0 && $acN[0] == $nucleus ){ $nRigid = $nBase; int $collide = getAttr( $nRigid + ".collide" ); if( $collide == true ){ string $fmt = (uiRes("m_makeCollideEffect.kAlreadyInSolver")); warning( `format -s $mesh -s $nucleus $fmt`); continue; } else { setAttr( $nRigid + ".collide" ) true; $createNRigid = false; } } else { select -r $nBase; assignNSolver($nucleus); } } string $meshTforms[] = `listTransforms $mesh`; string $tform = $meshTforms[0]; // TODO - handle instances // TODO, move the triangulate downstream from the mesh // $nRigid = `createNode nRigid -parent $tform`; if( $createNRigid ){ $nRigid = `createNode nRigid`; $newRigidNodes[size($newRigidNodes)] = $nRigid; hideParticleAttrs( $nRigid ); setAttr ($nRigid + ".selfCollide") false; connectAttr time1.outTime ($nRigid + ".currentTime"); connectAttr ($mesh + ".worldMesh") ($nRigid + ".inputMesh"); addPassiveToNSystem($nRigid, $nucleus); connectAttr ($nucleus + ".startFrame") ($nRigid +".startFrame"); } setAttr ($mesh + ".quadSplit") 0; string $rigidTforms[] = `listTransforms $nRigid`; setAttr -l true ($rigidTforms[0] + ".translate"); setAttr -l true ($rigidTforms[0] + ".rotate"); setAttr -l true ($rigidTforms[0] + ".scale"); // 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.003; // 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 ){ $newWidth = $thickness; } } if( $newWidth < $minWidth ){ $newWidth = $minWidth; } setAttr ($nRigid + ".thickness") $newWidth; setAttr ($nRigid + ".pushOutRadius") ($newWidth * 4.0); setAttr ($nRigid + ".trappedCheck") true; // // setAttr ($nRigid + ".visibility") 0; } // force update of nucleus node so it resets the collide objects if start frame getAttr ($nucleus + ".forceDynamics" ); select $newRigidNodes; return $newRigidNodes; }