今天给动画组写一个mirror pose工具。目前动画在进行layout制作,为了加快摆pose速度,快速mirrorPose还是很重要的。
思路:
1.mirror类别:单向/双向。单向是只从A—>B或者B—>A,双向为A<—>B互换。
2.mirrorPose需要mirror的部分为:头,手,身体,脚。分别需要mirror的属性为(暂时没有拉伸):
头:rx,ry,rz
身体:rx,ry,rz。
手/脚:(FK)rx,ry,rz;(IK)tx,ty,tz,rx,ry,rz。
3.互换过程归纳:
头:只需要将ry=>-ry,rz=>-rz
身体:只需要将ry=>-ry,rz=>-rz
手:(FK)rx=>rx,ry=>ry,rz=>rz ; (IK)tx=-tx,ty=-ty,tz=-tz
扫描二维码关注公众号,回复:
3581485 查看本文章
脚:(FK)rx=>rx,ry=>ry,rz=>rz ; (IK)tx=-tx,ty=ty,tz=tz
(测试了半天才发现手和脚的绑定不一致,坑爹!)
4.核心算法:
最麻烦的是手和脚的mirror。A、B之间属性互换正常思路为:A=>C,B=>A,C=>B。但是这样执行效率较低,所以决定再加一个D。
需要写的函数为:
- 从A读取(rx,ry,rz)数据存入内存(C)。
- 从B读取(rx,ry,rz)数据存入内存(D)。
- 从A读取(tx,ty,tz)数据存入内存(C')。
- 从B读取(tx,ty,tz)数据存入内存(D')。
- 将C给B
- 将D给A
- 将C'给B
- 将D'给A
5.UI
先将UI写出来:
代码为:
global proc phoenixMirrorPoseUI() { if (`window -q -ex phoenixMirrorPoseWindow`) deleteUI phoenixMirrorPoseWindow; //Main Window window -title "DH_phonenix_mirrorPoseTool" -maximizeButton false -sizeable false -w 340 -h 160 phoenixMirrorPoseWindow; //Main Column Layout columnLayout -cw 500 -adjustableColumn 1; separator -w 400 -h 15; radioButtonGrp -numberOfRadioButtons 3 -label "镜像类别:" -labelArray3 "A-->B" "B-->A" "A<-->B" -select 1 -columnWidth4 50 80 80 80 -columnAlign4 "left" "left" "left" "left" customChannelRadioButtonGrp; separator -w 400 -h 15; checkBoxGrp -numberOfCheckBoxes 4 -label "镜像部分:" -labelArray4 "头" "手" "身体" "脚" -valueArray4 1 1 1 1 -columnWidth5 55 80 80 80 80 -columnAlign4 "left" "left" "left" "left" flipTranslateCheckBoxGrp; separator -w 400 -h 15; columnLayout -columnAlign "left"; text " "; rowLayout -nc 2; text " "; button -align "right" -w 150 -backgroundColor 0.1 0.5 0.1 -highlightColor 1 1 1 -label "Apply" -c ("apply"); showWindow phoenixMirrorPoseWindow; } phoenixMirrorPoseUI
6.函数:
看起来很多,但是实际上各个函数之间只有名称的差别。
- 从A读取参数(rx,ry,rz):
global proc QA_attr_r(){ string $selCon[]=`ls -sl`; global vector $tempValueR_C[]; clear $tempValueR_C; int $i; for($eachCrv in $selCon) { float $buffer[] = `getAttr ($eachCrv+".r")`; $tempValueR_C[$i] = <<$buffer[0],$buffer[1],$buffer[2]>>; $i++; } print $tempValueR_C; };
- 从B读取参数(rx,ry,rz):
global proc QB_attr_r(){ string $selCon[]=`ls -sl`; global vector $tempValueR_D[]; clear $tempValueR_D; int $i; for($eachCrv in $selCon) { float $buffer[] = `getAttr ($eachCrv+".r")`; $tempValueR_D[$i] = <<$buffer[0],$buffer[1],$buffer[2]>>; $i++; } print $tempValueR_D; };
- 从A读取参数(tx,ty,tz):
global proc QA_attr_t(){ string $selCon[]=`ls -sl`; global vector $tempValueT_C[]; clear $tempValueT_C; int $i; for($eachCrv in $selCon) { float $buffer[] = `getAttr ($eachCrv+".t")`; $tempValueT_C[$i] = <<$buffer[0],$buffer[1],$buffer[2]>>; $i++; } print $tempValueT_C; };
- 从B读取参数(tx,ty,tz):
global proc QB_attr_t(){ string $selCon[]=`ls -sl`; global vector $tempValueT_D[]; clear $tempValueT_D; int $i; for($eachCrv in $selCon) { float $buffer[] = `getAttr ($eachCrv+".t")`; $tempValueT_D[$i] = <<$buffer[0],$buffer[1],$buffer[2]>>; $i++; } print $tempValueT_D; };
- 将C给B
global proc RC_2_B(){ string $selCon[]=`ls -sl`; global vector $tempValueR_C[]; int $i; for($eachValue in $tempValueR_C) { setAttr ($selCon[$i]+".r") ($eachValue.x) ($eachValue.y) ($eachValue.z) ; $i++; } }
- 将D给A
global proc RD_2_A(){ string $selCon[]=`ls -sl`; global vector $tempValueR_D[]; int $i; for($eachValue in $tempValueR_D) { setAttr ($selCon[$i]+".r") ($eachValue.x) ($eachValue.y) ($eachValue.z) ; $i++; } }
- 将C'给B
global proc TC_2_B(){ string $selCon[]=`ls -sl`; global vector $tempValueT_C[]; int $i; for($eachValue in $tempValueT_C) { setAttr ($selCon[$i]+".t") ($eachValue.x) ($eachValue.y) ($eachValue.z) ; $i++; } }
- 将D'给A
7.各个部分的镜像函数global proc TD_2_A(){ string $selCon[]=`ls -sl`; global vector $tempValueT_D[]; int $i; for($eachValue in $tempValueT_D) { setAttr ($selCon[$i]+".t") ($eachValue.x) ($eachValue.y) ($eachValue.z) ; $i++; } }
首先确定所选择的角色名字:global proc string GetSelNa(string $selCon){ string $selA[]; clear $selA; tokenize $selCon ":" $selA; if($selA[0] == "") print "please select a subject with a \":\""; return $selA[0]; }
mirrorR:global proc mirror_R(){ string $selCon[]=`ls -sl`; for($eachCon in $selCon) { float $tempR[] = `getAttr ($eachCon+".r")`; setAttr ($eachCon+".r") $tempR[0] (-$tempR[1]) (-$tempR[2]); } }
mirrorT:
global proc mirror_T(){ string $selCon[]=`ls -sl`; for($eachCon in $selCon) { float $tempT[] = `getAttr ($eachCon+".t")`; setAttr ($eachCon+".t") (-$tempR[0]) (-$tempR[1]) (-$tempR[2]); } }
头:global proc phoenix_headMirror(){ string $selA[] = `ls -sl`; string $charName = `GetSelNa $selA[0]`; string $headName = ($charName+":"+"Head_Ctrl"); string $neckName = ($charName+":"+"NeckFK_Ctrl"); select -r $headName $neckName; mirror_R; }
身体:
手:global proc phoenix_bodyMirror(){ string $selA[] = `ls -sl`; string $charName = `GetSelNa $selA[0]`; string $AuxilName = ($charName+":"+"ChestAuxil_Ctrl"); string $chestName = ($charName+":"+"ChestFK_Ctrl"); string $splineName = ($charName+":"+"SplineFK_Ctrl"); string $rootIKName = ($charName+":"+"RootIK_Ctrl"); string $rootName = ($charName+":"+"Root_Ctrl"); select -r $AuxilName $chestName $splineName $rootIKName $rootName; mirror_R; }
脚:global proc phoenix_bodyMirror(){ string $selA[] = `ls -sl`; string $charName = `GetSelNa $selA[0]`; string $AuxilName = ($charName+":"+"ChestAuxil_Ctrl"); string $chestName = ($charName+":"+"ChestFK_Ctrl"); string $splineName = ($charName+":"+"SplineFK_Ctrl"); string $rootIKName = ($charName+":"+"RootIK_Ctrl"); string $rootName = ($charName+":"+"Root_Ctrl"); select -r $AuxilName $chestName $splineName $rootIKName $rootName; mirror_R; } global proc phoenix_handMirror(){ string $selA[] = `ls -sl`; string $charName = `GetSelNa $selA[0]`; string $IKFKSWConNameLft = $charName+":"+"L_WristSwitch_Ctrl"; string $IKFKSWConNameRgt = $charName+":"+"R_WristSwitch_Ctrl"; float $IKOrFK_temp1 = `getAttr $IKFKSWConNameLft+".ikfkBlend"`; float $IKOrFK_temp2 = `getAttr $IKFKSWConNameRgt+".ikfkBlend"`; if($IKOrFK_temp1!=$IKOrFK_temp2) {error "建议先使用IKFK无缝切换工具切换到同一状态再使用本工具!";} else if($IKOrFK_temp1==0) { int $mirrorStyle=`radioButtonGrp -q -select customChannelRadioButtonGrp`; if($mirrorStyle==1){ select -r ($charName+":"+"L_Scapula_Ctrl") ($charName+":"+"L_ShoulderFK_Ctrl") ($charName+":"+"L_ElbowFK_Ctrl") ($charName+":"+"L_WristFK_Ctrl") ; QA_attr_r; select -r ($charName+":"+"R_Scapula_Ctrl") ($charName+":"+"R_ShoulderFK_Ctrl") ($charName+":"+"R_ElbowFK_Ctrl") ($charName+":"+"R_WristFK_Ctrl") ; RC_2_B; } else if($mirrorStyle==2){ select -r ($charName+":"+"R_Scapula_Ctrl") ($charName+":"+"R_ShoulderFK_Ctrl") ($charName+":"+"R_ElbowFK_Ctrl") ($charName+":"+"R_WristFK_Ctrl") ; QA_attr_r; select -r ($charName+":"+"L_Scapula_Ctrl") ($charName+":"+"L_ShoulderFK_Ctrl") ($charName+":"+"L_ElbowFK_Ctrl") ($charName+":"+"L_WristFK_Ctrl") ; RC_2_B; } else{ select -r ($charName+":"+"L_Scapula_Ctrl") ($charName+":"+"L_ShoulderFK_Ctrl") ($charName+":"+"L_ElbowFK_Ctrl") ($charName+":"+"L_WristFK_Ctrl") ; QA_attr_r; select -r ($charName+":"+"R_Scapula_Ctrl") ($charName+":"+"R_ShoulderFK_Ctrl") ($charName+":"+"R_ElbowFK_Ctrl") ($charName+":"+"R_WristFK_Ctrl") ; QB_attr_r; RC_2_B; select -r ($charName+":"+"L_Scapula_Ctrl") ($charName+":"+"L_ShoulderFK_Ctrl") ($charName+":"+"L_ElbowFK_Ctrl") ($charName+":"+"L_WristFK_Ctrl") ; RD_2_A;} } else { int $mirrorStyle=`radioButtonGrp -q -select customChannelRadioButtonGrp`; if($mirrorStyle==1){ select -r ($charName+":"+"L_WristIKPole_Ctrl") ($charName+":"+"L_WristIK_Ctrl"); QA_attr_t; select -r ($charName+":"+"L_WristIK_Ctrl"); QA_attr_r; select -r ($charName+":"+"R_WristIKPole_Ctrl") ($charName+":"+"R_WristIK_Ctrl"); TC_2_B; mirror_T; select -r ($charName+":"+"R_WristIK_Ctrl"); RC_2_B; } if($mirrorStyle==2){ select -r ($charName+":"+"R_WristIKPole_Ctrl") ($charName+":"+"R_WristIK_Ctrl"); QA_attr_t; select -r ($charName+":"+"R_WristIK_Ctrl"); QA_attr_r; select -r ($charName+":"+"L_WristIKPole_Ctrl") ($charName+":"+"L_WristIK_Ctrl"); TC_2_B; mirror_T; select -r ($charName+":"+"L_WristIK_Ctrl"); RC_2_B; } else{ select -r ($charName+":"+"L_WristIKPole_Ctrl") ($charName+":"+"L_WristIK_Ctrl"); QA_attr_t; select -r ($charName+":"+"L_WristIK_Ctrl"); QA_attr_r; select -r ($charName+":"+"R_WristIKPole_Ctrl") ($charName+":"+"R_WristIK_Ctrl"); QB_attr_t; TC_2_B; mirror_T; select -r ($charName+":"+"R_WristIK_Ctrl"); QB_attr_r; RC_2_B; select -r ($charName+":"+"L_WristIKPole_Ctrl") ($charName+":"+"L_WristIK_Ctrl"); TD_2_A; mirror_T; select -r ($charName+":"+"L_WristIK_Ctrl"); RD_2_A; } } }
global proc phoenix_footMirror(){ string $selA[] = `ls -sl`; string $charName = `GetSelNa $selA[0]`; string $IKFKSWConNameLft = $charName+":"+"L_AnkleSwitch_Ctrl"; string $IKFKSWConNameRgt = $charName+":"+"R_AnkleSwitch_Ctrl"; float $IKOrFK_temp1 = `getAttr ($IKFKSWConNameLft+".ikfkBlend")`; float $IKOrFK_temp2 = `getAttr ($IKFKSWConNameRgt+".ikfkBlend")`; if($IKOrFK_temp1!=$IKOrFK_temp2) {error "建议先使用IKFK无缝切换工具切换到同一状态再使用本工具!";} else if($IKOrFK_temp1==0) { int $mirrorStyle=`radioButtonGrp -q -select customChannelRadioButtonGrp`; if($mirrorStyle==1){ select -r ($charName+":"+"L_HipFK_Ctrl") ($charName+":"+"L_KneeFK_Ctrl") ($charName+":"+"L_AnkleFK_Ctrl") ; QA_attr_r; select -r ($charName+":"+"R_Scapula_Ctrl") ($charName+":"+"R_HipFK_Ctrl") ($charName+":"+"R_KneeFK_Ctrl") ($charName+":"+"R_AnkleFK_Ctrl") ; RC_2_B; } else if($mirrorStyle==2){ select -r ($charName+":"+"R_HipFK_Ctrl") ($charName+":"+"R_KneeFK_Ctrl") ($charName+":"+"R_AnkleFK_Ctrl") ; QA_attr_r; select -r ($charName+":"+"L_Scapula_Ctrl") ($charName+":"+"L_HipFK_Ctrl") ($charName+":"+"L_KneeFK_Ctrl") ($charName+":"+"L_AnkleFK_Ctrl") ; RC_2_B; } else{ select -r ($charName+":"+"L_HipFK_Ctrl") ($charName+":"+"L_KneeFK_Ctrl") ($charName+":"+"L_AnkleFK_Ctrl") ; QA_attr_r; select -r ($charName+":"+"R_HipFK_Ctrl") ($charName+":"+"R_KneeFK_Ctrl") ($charName+":"+"R_AnkleFK_Ctrl") ; QB_attr_r; RC_2_B; select -r ($charName+":"+"L_HipFK_Ctrl") ($charName+":"+"L_KneeFK_Ctrl") ($charName+":"+"L_AnkleFK_Ctrl") ; RD_2_A;} } else { int $mirrorStyle=`radioButtonGrp -q -select customChannelRadioButtonGrp`; if($mirrorStyle==1){ select -r ($charName+":"+"L_AnkleIKPole_Ctrl") ($charName+":"+"L_AnkleIK_Ctrl"); QA_attr_t; select -r ($charName+":"+"L_AnkleIK_Ctrl"); QA_attr_r; select -r ($charName+":"+"R_AnkleIKPole_Ctrl") ($charName+":"+"R_AnkleIK_Ctrl"); TC_2_B; //mirror_T; float $tempFootTxL = `getAttr ($charName+":"+"R_AnkleIK_Ctrl"+".tx")`; setAttr ($charName+":"+"R_AnkleIK_Ctrl"+".tx") (-$tempFootTxL); select -r ($charName+":"+"R_AnkleIK_Ctrl"); RC_2_B; } if($mirrorStyle==2){ select -r ($charName+":"+"R_AnkleIKPole_Ctrl") ($charName+":"+"R_AnkleIK_Ctrl"); QA_attr_t; select -r ($charName+":"+"R_AnkleIK_Ctrl"); QA_attr_r; select -r ($charName+":"+"L_AnkleIKPole_Ctrl") ($charName+":"+"L_AnkleIK_Ctrl"); TC_2_B; //mirror_T; float $tempFootTxR = `getAttr ($charName+":"+"L_AnkleIK_Ctrl"+".tx")`; setAttr ($charName+":"+"L_AnkleIK_Ctrl"+".tx") (-$tempFootTxR); select -r ($charName+":"+"L_AnkleIK_Ctrl"); RC_2_B; } else{ select -r ($charName+":"+"L_AnkleIKPole_Ctrl") ($charName+":"+"L_AnkleIK_Ctrl"); QA_attr_t; select -r ($charName+":"+"L_AnkleIK_Ctrl"); QA_attr_r; select -r ($charName+":"+"R_AnkleIKPole_Ctrl") ($charName+":"+"R_AnkleIK_Ctrl"); QB_attr_t; TC_2_B; //mirror_T; float $tempFootTxR = `getAttr ($charName+":"+"R_AnkleIK_Ctrl"+".tx")`; setAttr ($charName+":"+"R_AnkleIK_Ctrl"+".tx") (-$tempFootTxR); select -r ($charName+":"+"R_AnkleIK_Ctrl"); QB_attr_r; RC_2_B; select -r ($charName+":"+"L_AnkleIKPole_Ctrl") ($charName+":"+"L_AnkleIK_Ctrl"); TD_2_A; //mirror_T; float $tempFootTxL = `getAttr ($charName+":"+"L_AnkleIK_Ctrl"+".tx")`; setAttr ($charName+":"+"L_AnkleIK_Ctrl"+".tx") (-$tempFootTxL); select -r ($charName+":"+"L_AnkleIK_Ctrl"); RD_2_A; } } }
7.主函数:先写个切换模式:
global proc mirrorMode(int $mode) { if($mode==0){ phoenix_headMirror; } else if($mode==1){ phoenix_handMirror; } else if($mode==2){ phoenix_bodyMirror; } else if($mode==3){ phoenix_footMirror; } }
然后是Apply:
global proc apply(){ int $partsOfMirror[] = `checkBoxGrp -q -valueArray4 flipTranslateCheckBoxGrp`; int $i=0; for($i=0;$i<4;$i++){ if($partsOfMirror[$i]==1) {mirrorMode $i;} else{} } print "success!"; }
Done!!!