使い方は動画を見てください。
最近使ってるわけでもないのでツールの
エラーとかも対応しかねますので自己責任でお試しください。
仕様としてはnearestPointOnMeshを使って
UV座標 ⇔ ワールド座標 を行き来してjointを配置していくものだったと思います。
※ペイントエフェクトのような規則正しいUVを使わないとうまくいかなかった気がします。
jointはIKスプラインの仕込み、hairの仕込みなどが選択できたと思います。
TYGrassesSetUpTool();
global proc TYGrassesSetUpTool(){
//同じウインドウが存在する場合は削除
if(`window -exists TYGrassesSetUpToolWindow`){
deleteUI TYGrassesSetUpToolWindow;
}
//ウインドウの作成
window -t "草花セットアップツール" -w 250 TYGrassesSetUpToolWindow;
string $windowRootLayout =`columnLayout -adj true`;
string $stepTabs =`tabLayout -imw 5 -imh 5`;
//STEP1
string $step1 =`columnLayout -adj true`;
text -fn "boldLabelFont" -bgc 0.18 0.18 0.18
-l "\n ターゲットメッシュのUV座標を基に\n等間隔でジョイントを配置しします\n";
columnLayout;
text -l "\n ① 配置させるジョイントの数と半径を指定します\n";
intFieldGrp -l "ジョイント " -v1 10 -el "個" jointQuantityField;
floatFieldGrp -l "半径 " -v1 0.01 -pre 3 jointRadiusField;
text -l "\n ② 配置させるUVマップの名前を指定します\n";
rowLayout -nc 2;
text -l " ";
textField -tx "map1" UVmapNameField;
setParent..;
text -l "\n ③ 配置させるUV座標を指定します\n";
floatFieldGrp -l "U座標位置の割合 " -v1 50.0 -el "%" -pre 2
-ann "V座標上に一列で配置するときのU座標位置の割合です" uPerPositionField;
text -l "\n ④ バインドするか指定します\n";
rowLayout -nc 3;
text -l " ";
radioCollection bindSelectField;
radioButton -l "バインドする" -sl -w 100 bindSelectTrue;
radioButton -l "バインドしない" -w 100 bindSelectFalse;
setParent..;
text -l "\n ⑤ ヘアシステムとカーブを作成するか指定します\n";
rowLayout -nc 3;
text -l " ";
radioCollection makeRigSelectField;
radioButton -l "作成する" -sl -w 100
-onc "text -e -en true nucleusText;\
radioButton -e -en true makeNsysSelectTrue;\
radioButton -e -en true makeNsysSelectFalse;"
makeRigSelectTrue;
radioButton -l "作成しない" -w 100
-onc "text -e -en false nucleusText;\
radioButton -e -en false makeNsysSelectTrue;\
radioButton -e -en false makeNsysSelectFalse;"
makeRigSelectFalse;
setParent..;
text -l "\n ヘアシステムにnucleusを接続するか指定します\n" nucleusText;
rowLayout -nc 3;
text -l " ";
radioCollection makeNsysSelectField;
radioButton -l "接続する" -sl -w 100 makeNsysSelectTrue;
radioButton -l "接続しない" -w 100 makeNsysSelectFalse;
setParent..;
text -l "\n ⑥ meshノードを選択し、作成を実行します\n";
setParent..;
button -l "作成" -c "TYGrassesSetUp(\
`intFieldGrp -q -v1 jointQuantityField`\
,`floatFieldGrp -q -v1 jointRadiusField`\
,`textField -q -tx UVmapNameField`\
,`floatFieldGrp -q -v1 uPerPositionField`\
,`radioCollection -q -sl bindSelectField`\
,`radioCollection -q -sl makeRigSelectField`\
,`radioCollection -q -sl makeNsysSelectField`)";
setParent..;
//STEP2
string $step2 =`columnLayout -adj true`;
text -fn "boldLabelFont" -bgc 0.18 0.18 0.18
-l "\n バインドされたソースメッシュを基に\nジョイントを配置しバインドやnHair等を実行します\n";
columnLayout;
text -l "\n ① 配置させるジョイントの半径を指定します\n";
floatFieldGrp -l "半径 " -v1 0.01 -pre 3 jointCopyRadiusField;
text -l "\n ② 配置させるUVマップの名前を指定します\n";
rowLayout -nc 2;
text -l " ";
textField -tx "map1" UVmapCopyNameField;
setParent..;
text -l "\n ③ バインドするか指定します\n";
rowLayout -nc 3;
text -l " ";
radioCollection bindCopySelectField;
radioButton -l "バインドする" -sl -w 100 bindCopySelectTrue;
radioButton -l "バインドしない" -w 100 bindCopySelectFalse;
setParent..;
text -l "\n ③ ヘアシステムを継承し作成するか指定します\n";
rowLayout -nc 3;
text -l " ";
radioCollection succeedNsysSelectField;
radioButton -l "継承し作成する" -sl -w 100
-onc "textField -e -en true hairSystemShapeNameField;\
text -e -en true succeedHairSysText;"
succeedNsysSelectTrue;
radioButton -l "作成しない" -w 100
-onc "textField -e -en false hairSystemShapeNameField;\
text -e -en false succeedHairSysText;"
succeedNsysSelectFalse;
setParent..;
text -l "\n 継承するhairSystemShapeの名前を指定します\n" succeedHairSysText;
rowLayout -nc 2;
text -l " ";
textField -tx "hairSystemShape1" hairSystemShapeNameField;
setParent..;
setParent..;
button -l "実行" -c "TYGrassesSetUpCopy(\
`floatFieldGrp -q -v1 jointCopyRadiusField`\
,`textField -q -tx UVmapCopyNameField`\
,`radioCollection -q -sl bindCopySelectField`\
,`radioCollection -q -sl succeedNsysSelectField`\
,`textField -q -tx hairSystemShapeNameField`)";
setParent..;
//タブレイアウトにペアレント
tabLayout -e -tl $step1 "STEP1" -tl $step2 "STEP2" $stepTabs;
setParent..;
button -l "閉じる" -c "deleteUI TYGrassesSetUpToolWindow";
setParent..;
showWindow;
}
global proc TYGrassesSetUp(int $jointQuantity, float $jointRadius, string $UVmapName,
float $uPerPosition, string $bindSelect, string $makeRigSelect, string $makeNsysSelect){
pickWalk -d down;
//選択されたオブジェクトのチェック
string $targetMesh[] = `ls -sl -typ mesh`;
if(`objExists $targetMesh[0]`){
if(`objExists $targetMesh[1]`){
error "複数選択されています。一度に作成できるベースセットアップは一つのみです。";
}
else;
}
else error "メッシュが選択されていません。";
//uvSetの名前のチェック
int $flag = 0;
if(catch(size(`getAttr -s ($targetMesh[0] + ".uvSet[*].uvSetName")`))){
if(`getAttr ($targetMesh[0] + ".uvSet[0].uvSetName")` == $UVmapName){
$flag = 1;
}
else;
}
else{
string $uvSetNameList[] = `getAttr ($targetMesh[0] + ".uvSet[*].uvSetName")`;
int $j;
for($j=0;$j<=(size($uvSetNameList)) && $flag!=1;$j++){
if($uvSetNameList[$j] == $UVmapName){
$flag = 1;
}
else;
}
}
//指定した値のチェック
if($jointQuantity <= 1 || $jointRadius <= 0 || $flag == 0){
error "入力値が不正です。";
}
else;
//transformノードの取得
string $targetTransform[] = `pickWalk -d up`;
//ジョイントの配置
int $i;
string $jointList[];
for($i=1;$i<=$jointQuantity;$i++){
select -cl;
string $jointName = `joint -rad $jointRadius -n "TYGrassBaceJoint"`;
//階層化
$jointList[($i - 1)] = $jointName;
if($i!=1){
parent $jointName $jointList[($i - 2)];
}
//UV座標を基にジョイントを配置
string $constName[] = `pointOnPolyConstraint $targetMesh[0] $jointName`;
int $k,$UVmapNumber,$nFlag = 0;
for($k=0;$nFlag!=1;$k++){
string $selectUVmapName = `getAttr ($targetMesh[0] + ".uvSet[" + $k + "].uvSetName")`;
if($selectUVmapName == $UVmapName){
$UVmapNumber = $k;
$nFlag = 1;
}
else;
}
connectAttr -f ($targetMesh[0] + ".uvSet[" + $UVmapNumber + "].uvSetName")
($constName[0] + ".target[0].targetUVSetName");
float $uvSize[] = `polyEvaluate -b2 -ae -uvs $UVmapName $targetMesh[0]`;
float $uPosition = ($uvSize[1] - $uvSize[0]) * $uPerPosition * 0.01 + $uvSize[0];
float $vPosition = ($uvSize[3] - $uvSize[2]) / ($jointQuantity - 1)
* ($i - 1) + $uvSize[2];
setAttr ($constName[0] + "." + $targetTransform[0] + "U0") $uPosition;
setAttr ($constName[0] + "." + $targetTransform[0] + "V0") $vPosition;
setAttr ($constName[0] + ".offsetRotateX") -90;
setAttr ($constName[0] + ".offsetRotateY") 90;
delete $constName[0];
//回転値をジョイントの方向へ移行させ0にする
float $jointRotateValue[] = `getAttr ($jointName + ".rotate")`;
joint -e -o $jointRotateValue[0] $jointRotateValue[1] $jointRotateValue[2] $jointName;
setAttr ($jointName + ".rotate") 0 0 0;
}
//バインドの実行
if($bindSelect == "bindSelectTrue"){
select $targetMesh[0] $jointList;
SmoothBindSkin;
}
else;
//nHairの作成
if($makeRigSelect == "makeRigSelectTrue"){
//ikHandleの作成
string $ikHandleName[] = `ikHandle -sj $jointList[0]
-ee $jointList[($jointQuantity -1)] -sol ikSplineSolver -scv false`;
select $ikHandleName[2];
//assignHairSystemのプロシージャから引用
string $sel[] = `ls -sl`;
string $hsys = `createNode hairSystem`;
connectAttr time1.outTime (".currentTime");
string $inCurveName[] = `ls -dag -type nurbsCurve $sel`;
attachCurvesToHairSystem( $hsys, $inCurveName, false );
//作成したものを変数に代入
select $hsys;
convertHairSelection( "follicles" );
pickWalk -d down;
select `listConnections -s false -t "nurbsCurve"`;
string $outCurveShapeName[] = `pickWalk -d down`;
select $inCurveName[0];
string $inCurveShapeName[] = `pickWalk -d down`;
//ikをhiarカーブに添わせる
disconnectAttr ($inCurveShapeName[0] + ".worldSpace[0]") ($ikHandleName[0] + ".inCurve");
connectAttr ($outCurveShapeName[0] + ".worldSpace[0]") ($ikHandleName[0] + ".inCurve");
//hairのアトリビュート設定
setAttr ($hsys + ".bendResistance") 50;
setAttr ($hsys + ".startCurveAttract") 0.1;
setAttr ($hsys + ".selfCollide") 1;
setAttr ($hsys + ".selfCollideWidthScale") 0.1;
//nucleusの接続
if($makeNsysSelect == "makeNsysSelectTrue"){
string $nucleusName = `createNode nucleus`;
connectAttr time1.outTime (".currentTime");
connectAttr ($hsys + ".currentState") ($nucleusName + ".inputActive[0]");
connectAttr ($hsys + ".startState") ($nucleusName + ".inputActiveStart[0]");
connectAttr ($nucleusName + ".outputObjects[0]") ($hsys + ".nextState");
connectAttr ($nucleusName + ".startFrame") ($hsys + ".startFrame");
setAttr ($hsys + ".active") 1;
}
}
}
global proc TYGrassesSetUpCopy(float $jointCopyRadius, string $UVmapCopyName
, string $bindCopySelect, string $succeedNsysSelect, string $hairSystemShapeName){
pickWalk -d down;
string $meshList[] = `ls -sl `;
//uvSetの名前のチェック
int $k,$flag = 0;;
for($k=1;$k<size($meshList);$k++){
if(catch(size(`getAttr -s ($meshList[$k] + ".uvSet[*].uvSetName")`))){
if(`getAttr ($meshList[$k] + ".uvSet[0].uvSetName")` == $UVmapCopyName){
$flag = 1;
}
else;
}
else{
string $uvSetNameList[] = `getAttr ($meshList[$k] + ".uvSet[*].uvSetName")`;
int $j;
for($j=0;$j<=(size($uvSetNameList)) && $flag!=1;$j++){
if($uvSetNameList[$j] == $UVmapCopyName){
$flag = 1;
}
else;
}
}
}
if(`objExists $hairSystemShapeName`){
if(`nodeType $hairSystemShapeName` != "hairSystem"){
$flag = 0;
}
else;
}
else{
$flag = 0;
}
//指定した値のチェック
if($flag == 0){
error "入力値が不正です。";
}
else;
//nearestPointOnMeshの作成
loadPlugin -qt "nearestPointOnMesh.mll";
string $nPOM = `createNode "nearestPointOnMesh"`;
string $checker[] = `spaceLocator`;
connectAttr ($checker[0] + ".translate") ($nPOM + ".inPosition");
connectAttr ($meshList[0] + ".worldMesh[0]") ($nPOM + ".inMesh");
//メッシュからジョイントを取得
string $jointList[] =`skinCluster -q -inf $meshList[0]`;
//ソースメッシュにバインドされたジョイントのソースメッシュ上UV位置を取得
float $uPosition[],$vPosition[];
for($jointName in $jointList){
float $jointPosition[] = `xform -q -ws -t $jointName`;
move -rpr $jointPosition[0] $jointPosition[1] $jointPosition[2] $checker[0];
$uPosition[`size($uPosition)`] = `getAttr ($nPOM + ".parameterU")`;
$vPosition[`size($vPosition)`] = `getAttr ($nPOM + ".parameterV")`;
}
delete $nPOM $checker[0];
//ジョイントの配置
int $i;
string $ikHandleList[],$jointCopyList[];
for($i=1;$i<size($meshList);$i++){
float $uvboundingBox[] = `polyEvaluate -b2 -ae -uvs $UVmapCopyName $meshList[$i]`;
string $jointName[] = {};
for($j=0;$j<`size($jointList)`;$j++){
//ソースのバウンディングボックス内にジョイントがあった場合ターゲットも作成(誤差0.0001)
if(($uvboundingBox[3] + 0.0001) > $vPosition[$j]){
select -cl;
$jointName[$j] = `joint -rad $jointCopyRadius -n "TYGrassBaceJoint"`;
string $constName[] = `pointOnPolyConstraint $meshList[$i] $jointName[$j]`;
//指定したuvマップが何番目の配列にあるか確認
int $l,$UVmapNumber,$nFlag = 0;
for($l=0;$nFlag!=1;$l++){
string $selectUVmapName = `getAttr ($meshList[$i] +
".uvSet[" + $l + "].uvSetName")`;
if($selectUVmapName == $UVmapCopyName){
$UVmapNumber = $k;
$nFlag = 1;
}
else;
}
connectAttr -f ($meshList[$i] + ".uvSet[" + $UVmapNumber + "].uvSetName")
($constName[0] + ".target[0].targetUVSetName");
select $meshList[$i];
string $transformMesh[] = `pickWalk -d up`;
setAttr ($constName[0] + "." + $transformMesh[0] + "U0") $uPosition[$j];
setAttr ($constName[0] + "." + $transformMesh[0] + "V0") $vPosition[$j];
setAttr ($constName[0] + ".offsetRotateX") -90;
setAttr ($constName[0] + ".offsetRotateY") 90;
delete $constName[0];
//ソースを参考に階層化
select $jointList[$j];
int $m,$num = 0;
string $sourceParentJoint[] =`pickWalk -d up`;
if($jointList[$j] != $sourceParentJoint[0]){
for($m=0;$m<size($jointList);$m++){
if($jointList[$m] == $sourceParentJoint[0]){
$num = $m;
}
}
parent $jointName[$j] $jointName[$num];
}
}
}
$jointCopyList[size($jointCopyList)] = $jointName[0];
//バインドの実行
if($bindCopySelect == "bindCopySelectTrue"){
select $meshList[$i] $jointName[0];
SmoothBindSkin;
}
else;
//ikHandleの作成
if($succeedNsysSelect == "succeedNsysSelectTrue"){
string $ikHandleName[] = `ikHandle -sj $jointName[0]
-ee $jointName[(size($jointName) - 1)] -sol ikSplineSolver -scv false`;
$ikHandleList[size($ikHandleList)] = $ikHandleName[0];
//assignHairSystemから一部引用
string $curves[] = `ls -dag -type nurbsCurve $ikHandleName[2]`;
attachCurvesToHairSystem( $hairSystemShapeName, $curves, false );
//hairSystemShapeから正しいfollicleshapeを取得
select $hairSystemShapeName;
convertHairSelection( "follicles" );
string $follicleShapeList[] = `pickWalk -d down`;
string $trueFollicleShape;
for($follicleShapeName in $follicleShapeList){
string $plugList[] = `listConnections -d false $follicleShapeName`;
for($plugName in $plugList){
if($plugName == $ikHandleName[2]){
$trueFollicleShape = $follicleShapeName;
}
else;
}
}
//follicleshapeの中から作られたカーブを取得
select $trueFollicleShape;
select `listConnections -s false -t "nurbsCurve"`;
string $outCurveName[] = `pickWalk -d down`;
//curveShapeを取得
select $ikHandleName[2];
string $inCurveName[] = `pickWalk -d down`;
//ikをhiarカーブに添わせる
disconnectAttr ($inCurveName[0] + ".worldSpace[0]") ($ikHandleName[0] + ".inCurve");
connectAttr ($outCurveName[0] + ".worldSpace[0]") ($ikHandleName[0] + ".inCurve");
}
else;
}
group -n "TYGrassesIkHandleGp" $ikHandleList;
group -n "TYGrassesJointGp" $jointCopyList;
select -cl;
}
久しぶりにMELのツールを見るとpythonのほうが
書きやすい感じがしますね。(慣れかな?)
最近はOpenMayaとかPySideと戯れているのでそういうのもあるんでしょうけど。
んーbloggerってtextファイルアップロードできないのかなー