// =========================================================================== // 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. // =========================================================================== // // // // // // nClothVertexEditor // // // None. // // // This opens an editor that allows one to easily edit per vertex nCloth values by selecting // vertices and editing values directly with a slider, rather than by using the // paint tool. After running this a small window // should appear. Select vertices on an nCloth then set the desired vertex attribute // in the window. The slider will show the current value for those vertices which // you can then change. If desired one can also randomize the values using the // randomization slider. // // Tip: drag the string "nClothVertexEditor" onto the shelf so that in future you can // simply click on the shelf button to bring up the editor. // // Example Use: Create a poly plane, make it nCloth, then type nClothVertexEditor. // Select a couple of cvs, set the attribute to "inputAttract" and the value to 1.0. // The cloth should fall except for the selected cvs, which are now attracting to // input mesh. This is similar to a transform constraint. Select some more cvs, // make the attribute "wrinkle" and edit the slider value to displace the rest // position of the cvs. Note how with wrinkle selected the slider range goes from // -1 to 1. This makes it possible to displace on both sides of the surface. // You can select a large block of cvs and increase the randomization to make // the surface lumpy. Note that depending on the size of you mesh you may need // to also adjust the wrinkleMapScale on the nCloth node to set the min/max wrinkle // displacement. // // The values one can set range from 0-1 for all attributes except wrinkle, which goes // from -1 to 1. The per vertex values are multipliers of the same named attributes on // the nCloth node. Thus for more stretch resistance per vertex than 1.0 increase // the stretchResistance attribute on the nCloth node. // // // // None. // // // nClothVertexEditor; // global int $gNCVEditSelectJob = 0; global int $gNCVEditChangeJob = 0; proc float getAverageAttrVal( int $validSelection[], int $allSame[] ) { float $val = 0; string $attr = `optionMenuGrp -q -v ncveAttrOptionMenu`; string $perVertAttr; if( $attr == "Input Attract" ){ $attr = "inputMeshAttract"; $perVertAttr = "inputAttractPerVertex"; } else { $attr = tolower($attr); $perVertAttr = ($attr + "PerVertex"); } if( $attr == "mass" ){ $attr = "pointMass"; } else if( $attr == "stretch" || $attr == "bend" || $attr == "deform" ){ $attr = ($attr + "Resistance"); } string $sel[] = `ls -sl -flatten`; $sel = stringArrayRemoveDuplicates( $sel ); int $numSel = size( $sel ); $validSelection[0] = false; $allSame[0] = true; string $obj; for( $obj in $sel ){ if( nodeType( $obj ) != "mesh"){ return( $val ); } } string $selectedObjects[] = `ls -sl -visible -ni -o -dag -type mesh`; $selectedObjects = stringArrayRemoveDuplicates( $selectedObjects ); int $numObjects = size( $selectedObjects ); string $nClothObjects[], $buffer[]; int $sameVal = true; float $lastVal = -1; int $totalSamples = 0; float $totalVal = 0.0; for( $obj in $selectedObjects ){ string $partObj = findTypeInHistory( $obj, "nParticle", 1,1 ); if( $partObj == "" ){ return $val; } if( !`attributeExists $perVertAttr $partObj` ){ return $val; } string $tforms[] = listTransforms( $obj ); string $objTform = $tforms[0]; int $numVerts[] = `polyEvaluate -v $obj`; float $vals[] = getAttr ($partObj + "."+$perVertAttr); int $numVals = size($vals); if( $numVals == 0 ){ // use the node value float $curVal = 0.0; if( $attr != "wrinkle" ){ $curVal = getAttr ($partObj + "."+$attr); } if( $curVal > 0 ){ $curVal = 1.0; } if( $lastVal != -1 && $lastVal != $curVal){ $sameVal = false; } $lastVal = $curVal; $totalVal += $curVal * $numVerts[0]; $totalSamples += $numVerts[0]; } else if( $numVals == $numVerts[0] ){ string $comp; for( $comp in $sel ){ if( startsWith( $comp, $objTform + ".vtx[" ) || startsWith( $comp, $obj + ".vtx[" ) ){ int $numTokens = `tokenize $comp "[]" $buffer`; if( $numTokens == 2 ){ int $compInd = $buffer[1]; if( $compInd < $numVerts[0] ){ float $curVal = $vals[$compInd]; if( $lastVal != -1 && $lastVal != $curVal){ $sameVal = false; } $lastVal = $curVal; $totalVal += $curVal; $totalSamples++; } } } } } } if( $totalSamples > 0 ){ $val = $totalVal/(float)$totalSamples; $validSelection[0] = true; } $allSame[0] = $sameVal; return $val; } proc setAttrVal( float $val) { string $attr = `optionMenuGrp -q -v ncveAttrOptionMenu`; string $perVertAttr, $mapType; if( $attr == "Input Attract" ){ $attr = "inputMeshAttract"; $perVertAttr = "inputAttractPerVertex"; $mapType = "inputAttractMapType"; } else { $attr = tolower($attr); $perVertAttr = ($attr + "PerVertex"); $mapType = ($attr + "MapType"); } if( $attr == "mass" ){ $attr = "pointMass"; } else if( $attr == "stretch" || $attr == "bend" || $attr == "deform" ){ $attr = ($attr + "Resistance"); } string $sel[] = `ls -sl -flatten`; $sel = stringArrayRemoveDuplicates( $sel ); int $numSel = size( $sel ); $validSelection[0] = false; $allSame[0] = true; string $obj; for( $obj in $sel ){ if( nodeType( $obj ) != "mesh"){ return; } } float $random = `floatSliderGrp -q -v ncveRandomizationSlider`; string $selectedObjects[] = `ls -sl -visible -ni -o -dag -type mesh`; $selectedObjects = stringArrayRemoveDuplicates( $selectedObjects ); int $numObjects = size( $selectedObjects ); string $nClothObjects[], $buffer[]; for( $obj in $selectedObjects ){ string $partObj = findTypeInHistory( $obj, "nParticle", 1,1 ); if( $partObj == "" ){ return; } if( !`attributeExists $perVertAttr $partObj` ){ return; } setAttr ($partObj + "." + $mapType) 1; string $tforms[] = listTransforms( $obj ); string $objTform = $tforms[0]; int $numVerts[] = `polyEvaluate -v $obj`; float $vals[] = getAttr ($partObj + "."+$perVertAttr); int $numVals = size($vals); if( $numVals == 0 ){ float $initVal = 0.0; if( $attr != "wrinkle" ){ $initVal = 1.0; float $curVal = getAttr ($partObj + "."+$attr); if( $curVal == 0.0 ){ if( $attr == "inputMeshAttract" ){ setAttr( $partObj + "." + $attr ) 1.3; } else { setAttr( $partObj + "." + $attr ) 1.0; } $initVal = 0; } } $numVals = $numVerts[0]; int $i; for( $i = 0; $i < $numVals; $i++ ){ $vals[$i] = $initVal; } } if( $numVals == $numVerts[0] ){ string $comp; for( $comp in $sel ){ if( startsWith( $comp, $objTform + ".vtx[" ) || startsWith( $comp, $obj + ".vtx[" ) ){ int $numTokens = `tokenize $comp "[]" $buffer`; if( $numTokens == 2 ){ int $compInd = $buffer[1]; if( $compInd < $numVerts[0] ){ if( $random > 0 ){ float $rval; if( $attr == "wrinkle" ){ $rval = $val - 2.0 * rand($val * $random ); } else { $rval = $val - rand( $val * $random ); if( $rval < 0 ){ $rval = 0; } } $vals[$compInd] = $rval; } else { $vals[$compInd] = $val; } } } } } } else { continue; } string $c = ("setAttr "+ $partObj +"."+ $perVertAttr +" -type \"doubleArray\" "+ $numVals); for( $i= 0; $i < $numVals; $i++ ){ $c += (" " + $vals[$i]); } eval $c; } } global proc nCVEditSetSliderRange() { string $attr = `optionMenuGrp -q -v ncveAttrOptionMenu`; float $min = 0.0; if( $attr == "Wrinkle" ){ $min = -1.0; } floatSliderGrp -e -min $min ncveValueSlider; } global proc nCVEditUpdate() { int $validSelection[1], $allSame[1]; string $attr = `optionMenuGrp -q -v ncveAttrOptionMenu`; float $val = getAverageAttrVal( $validSelection, $allSame ); text -e -m (!$validSelection[0]) ncveNothingSelected; text -e -m ($validSelection[0]&&!$allSame[0]) ncveValueRange; floatSliderGrp -e -en ($validSelection[0]) ncveValueSlider; floatSliderGrp -e -v $val ncveValueSlider; floatSliderGrp -e -en ($validSelection[0]&& ($val != 0)) ncveRandomizationSlider; floatSliderGrp -e -l $attr ncveValueSlider; } global proc nCVEditKillScriptJobs() { global int $gNCVEditSelectJob; global int $gNCVEditChangeJob; scriptJob -kill $gNCVEditSelectJob; scriptJob -kill $gNCVEditChangeJob; $gNCVEditSelectJob = 0; $gNCVEditChangeJob = 0; } global proc ncveUpdateAttribute() { int $optionSel = `optionMenuGrp -q -sl ncveAttrOptionMenu`; optionVar -intValue nClothVertexEditAttr $optionSel; nCVEditSetSliderRange(); nCVEditUpdate(); } global proc ncveNewValue() { float $val = `floatSliderGrp -q -v ncveValueSlider`; setAttrVal( $val ); nCVEditUpdate(); } global proc nClothVertexEditor() { global int $gNCVEditSelectJob; global int $gNCVEditChangeJob; if ( !`window -ex ncveWin` ) { window -rtf 1 -title (uiRes("m_nClothVertexEditor.kClothVertexEditor")) // -in _L10N(kWinIconName, "ncveWin") -wh 380 150 -menuBar 1 -s 1 ncveWin; scrollLayout ncveScroll; columnLayout ncveCol; int $optionSel = 1; if( !`optionVar -exists nClothVertexEditAttr` ){ optionVar -intValue nClothVertexEditAttr $optionSel; } else { $optionSel = `optionVar -q nClothVertexEditAttr`; } optionMenuGrp -l " Vertex Attribute" -cc "ncveUpdateAttribute" -cw 1 100 ncveAttrOptionMenu; menuItem -l "Thickness"; menuItem -l "Bounce"; menuItem -l "Friction"; menuItem -l "Mass"; menuItem -l "Stretch"; menuItem -l "Bend"; menuItem -l "Wrinkle"; menuItem -l "Rigidity"; menuItem -l "Deform"; menuItem -l "Input Attract"; optionMenuGrp -e -sl $optionSel ncveAttrOptionMenu; floatSliderGrp -label (uiRes("m_nClothVertexEditor.kValue")) -field 1 -cw 1 100 -min 0 -max 1 -cc "ncveNewValue" -pre 4 ncveValueSlider; floatSliderGrp -label (uiRes("m_nClothVertexEditor.kRandomization")) -field 1 -cw 1 100 -min 0 -cc "ncveNewValue" -v 0 -max 1 -pre 4 ncveRandomizationSlider; text -label (uiRes("m_nClothVertexEditor.kNothingSelected")) ncveNothingSelected; text -label (uiRes("m_nClothVertexEditor.kSelectionRange")) ncveValueRange; $gNCVEditSelectJob = `scriptJob -conditionTrue "SomethingSelected" "nCVEditUpdate"`; $gNCVEditChangeJob = `scriptJob -event "SelectionChanged" "nCVEditUpdate"`; scriptJob -runOnce true -uiDeleted ncveWin nCVEditKillScriptJobs; nCVEditSetSliderRange(); nCVEditUpdate(); } showWindow ncveWin; }