車輪リグ考察。
前回、フレーム単位で移動距離から回転角を求める方法を試しました。
大旨よさげだったのですが、しかし、どうもうまくいかない場合がありました。
車輪がスライドした場合です。
進行方向ではない向きの移動も回転計算に含んでいるのが原因です。
移動ベクトルから、進行方向のベクトルのみ抽出できれば良いのですが・・・。
要約すると。
はて、どうしたものか。でいろいろ調べた結果、”内積”使うと良いのでは、と。
内積についてはこちらのサイトを参考にしました。
難しい話はそちらに任せるとして、
前回の考え方に、この内積を組み込んだものをMayaで実装しました。(pymel)
import pymel.core as pm #車輪オブジェクト作成 oObj = pm.polyCylinder(n="Wheel_GEO", r=5, h=1,sz=1)[0] oObj.rotate.set(90,0,0) #回転制御用グループ作成 oRot = pm.group(n="Rot") #コントローラ作成 配置 oCtr = pm.curve( d=1, p=[(-5, 6, -2.5), (0, 6,-2.5), (0 ,6 ,-5), (7 ,6 ,0), (0 ,6 ,5), (0, 6 ,2.5), (-5, 6 ,2.5), (-5, 6 ,-2.5)], k=[ 0,1,2,3,4,5,6,7] ,n="CTR") pm.makeIdentity( apply=True ) #TOPグループ作成 oTOP = pm.group(n="TOP") pm.parent(oRot, oCtr) #Directionコントローラ oDir = pm.curve( d=1, p=[( -0.6, 0 , -1 ), (-0.6, 0, 1), (1.2, 0, 0), (-0.6, 0 ,-1)], k=[ 0,1,2,3] ,n="Dir") oDir.translate.set(10,0,0) pm.parent(oDir, oTOP) #コンストレイン pm.parentConstraint("CTR", "Dir", mo=True) #距離は測るヤツ oStartNull = pm.spaceLocator( p=(0, 0, 0)) pm.hide() oEndNull = pm.spaceLocator( p=(0, 5, 0)) pm.hide() oDst = pm.distanceDimension( oStartNull, oEndNull) pm.hide() pm.parent(oStartNull, oEndNull, oDst, oObj) #expression 実装 expName = "Wheel_SampleEXP04" exp = "//1フレーム前の位置(global変数)n" exp += "global vector $oldPos = <<0>>;;nn" exp += "//初期化n" exp += "int $frm = frame;n" exp += "float $rot = 0;n" exp += "int $dir = 1;nn" exp += "//1フレームあたりの移動距離n" exp += "float $dx = `getAttr -time $frm CTR.tx` - `getAttr -time ($frm-1) CTR.tx`;n" exp += "float $dz = `getAttr -time $frm CTR.tz` - `getAttr -time ($frm-1) CTR.tz`;n" exp += "//進行方向ベクトルn" exp += "float $dx2 = `getAttr -time $frm CTR.tx` - `getAttr -time $frm Dir.tx`;n" exp += "float $dz2 = `getAttr -time $frm CTR.tz` - `getAttr -time $frm Dir.tz`;n" exp += "//正規化n" exp += "vector $unitDir = `unit<<$dx2, 0 ,$dz2>>`;n" exp += "//内積使って距離を算出n" exp += "float $distance = dot(<<$dx, 0,$dz>> , $unitDir);n" exp += "//車輪の半径を取得n" exp += "$r = distanceDimensionShape1.distance;nn" exp += "//移動に応じた回転角を計算n" exp += "$rot = rad_to_deg($distance / $r) * $dir;n" exp += "Rot.rotateZ += $rot;n" pm.expression(string = exp, name = expName) pm.cycleCheck( e=0)
内積使った場合、進行方向の判定がいらなくなりました。
動かしてみました。
うまくいきそうです。
前進、後退、方向転換も問題なし。
進行方向以外の移動では回転もしません。
モーションパス使っても、ちゃんと動くみたいです。
これ以上、探ってアラが見つかったら大変なので、ここで止めておきます。
(一連の車輪リグの内容はMayaでサンプル作成していますが、他の3DCGソフトでも考え方がそのまま流用できるはずです。極端な話、Nuke等のコンポジットソフトでも作れるかと)
軽い気持ちで始めた車輪リグでしたが、内積まで使うハメになるとは。
みんなどうやってるんだろう?
もっと簡単な方法ないものか?
詳しい方、教えてくれる奇特な方、大歓迎です。
内積 参考URL
http://marupeke296.com/COL_Basic_No1_InnerAndOuterProduct.html
コメント