2014年04月23日

コマンドとクエリ上でのワールド座標系とローカル座標系について modo701 SP4

ACSのリグに限らずアイテムはいろいろペアレントされるから、ペアレントしている親座標系で表わされる変換チャンネルの座標値だけではそれがシーン上のどこにいてどっちを向いているのか全くわからない。401まではその位置のままペアレントを解除して座標値や回転角度を取得するとかするのが手っ取り早かったんだけど、501からはアイテムの位置や回転の座標系が親座標とワールド座標の両方で出来るようになっていたようだ。たまにちゃんと調べないと効率の悪いことしちゃってるよねw

これがそのコマンド。「mode」パラメータで「local」と「world」が切り替えられる。

item.setPosition <x:distance> <y:distance> <z:distance> <mode:{local|world}>
item.setRotation <x:angle> <y:angle> <z:angle> <mode:{local|world}>

アイテムの位置や回転角度を調べる場合も、

query sceneservice item.pos ? アイテムID
query sceneservice item.rot ? アイテムID

の場合は親座標系の位置と回転角度で、

query sceneservice item.worldpos ? アイテムID
query sceneservice item.worldrot ? アイテムID

としてやれば、ワールド座標系での位置と回転が得られる。

ただ、ワールド座標での回転については単純な角度じゃなくて3X3の変換行列になる。これがどんなもんなのか調べてみたらアイテムとペアレントしている親アイテムなどの回転変換を相殺する変換行列になっていた。つまりこの変換を使うとアイテムの回転角度を[0,0,0]にした上でペアレントを解除した時と同じ位置に頂点が移動する(ただし移動は含まない)。

例えば下の画像のように3つのアイテムをペアレントした場合、

fig01

mesh019の各頂点のローカル座標値に対して「item.worldpos」クエリで得られたワールド座標系の位置を差し引いてから「item.worldrot」クエリで得られた変換行列で変換すると、mesh019をペアレントから外して、アイテム座標を[0,0,0]、回転を[0,0,0]にした場合と同じ位置にメッシュが移動する。

#python
import sys
import math
import lx

def mmul(M,v):
 x = M[0]*v[0]+M[1]*v[1]+M[2]*v[2]
 y = M[3]*v[0]+M[4]*v[1]+M[5]*v[2]
 z = M[6]*v[0]+M[7]*v[1]+M[8]*v[2]
 return [x,y,z]

def vsub(v1,v2):
 x = v1[0]-v2[0]
 y = v1[1]-v2[1]
 z = v1[2]-v2[2]
 return [x,y,z]

M = lx.eval('query sceneservice item.worldRot ? mesh019')
iwpos = lx.eval('query sceneservice item.worldPos ? mesh019')
lx.eval('select.type item')
lx.eval('select.item mesh019')
lx.eval('select.type vertex')

main = lx.eval('query layerservice layer.index ? main')
verts = lx.evalN('query layerservice verts ? all')

for v in verts:
 pos = lx.eval('query layerservice vert.pos ? %s' % v)
 wpos = mmul(M,vsub(pos,iwpos))
 lx.eval('select.element %s vertex set %s' % (main,v))
 lx.eval('vert.set x %s' % wpos[0])
 lx.eval('vert.set y %s' % wpos[1])
 lx.eval('vert.set z %s' % wpos[2])

これが変換後。「mesh019」のアイテムはペアレントしたままで座標値や回転角度もそのままだ。

fig02

このように「item.worldrot」クエリで得られる変換行列はペアレントやアイテム回転による変換をキャンセルするように働く。

だから当然逆行列をとれば、その逆も可能だ。下の画像はペアレントされていないアイテム「mesh123」を追加したところ。これはワールド座標系原点に回転角度[0,0,0]で配置されている。

fig03

このアイテムの各頂点に対して「mwsh019」からクエリした回転行列の逆行列で回転させてから「mwsh019」からクエリしたアイテムのワールド座標値を加算するプログラムが下記だ。

#python
import sys
import math
import lx

def det33(M):
 return M[0]*M[4]*M[8]+M[3]*M[7]*M[2]+M[6]*M[1]*M[5]-M[0]*M[7]*M[5]-M[6]*M[4]*M[2]-M[3]*M[1]*M[8]

def invM33(M):
 invM = []
 det = det33(M)
 if det==0.0:return None
 invM.append((M[4]*M[8]-M[5]*M[7])/det)
 invM.append((M[2]*M[7]-M[1]*M[8])/det)
 invM.append((M[1]*M[5]-M[2]*M[4])/det)
 invM.append((M[5]*M[6]-M[3]*M[8])/det)
 invM.append((M[0]*M[8]-M[2]*M[6])/det)
 invM.append((M[2]*M[3]-M[0]*M[5])/det)
 invM.append((M[3]*M[7]-M[4]*M[6])/det)
 invM.append((M[1]*M[6]-M[0]*M[7])/det)
 invM.append((M[0]*M[4]-M[1]*M[3])/det)
 return invM

def mmul(M,v):
 x = M[0]*v[0]+M[1]*v[1]+M[2]*v[2]
 y = M[3]*v[0]+M[4]*v[1]+M[5]*v[2]
 z = M[6]*v[0]+M[7]*v[1]+M[8]*v[2]
 return [x,y,z]

def vadd(v1,v2):
 x = v1[0]+v2[0]
 y = v1[1]+v2[1]
 z = v1[2]+v2[2]
 return [x,y,z]

def vsub(v1,v2):
 x = v1[0]-v2[0]
 y = v1[1]-v2[1]
 z = v1[2]-v2[2]
 return [x,y,z]

M = lx.eval('query sceneservice item.worldRot ? mesh019')
iwpos = lx.eval('query sceneservice item.worldPos ? mesh019')
invM = invM33(M)
lx.eval('select.type item')
lx.eval('select.item mesh123')
lx.eval('select.type vertex')

main = lx.eval('query layerservice layer.index ? main')
verts = lx.evalN('query layerservice verts ? all')

for v in verts:
 pos = lx.eval('query layerservice vert.pos ? %s' % v)
 wpos = vadd(mmul(invM,pos),iwpos)
 lx.eval('select.element %s vertex set %s' % (main,v))
 lx.eval('vert.set x %s' % wpos[0])
 lx.eval('vert.set y %s' % wpos[1])
 lx.eval('vert.set z %s' % wpos[2])

そしてこれが実行結果。mesh019とmesh123が重なっているのがわかる。

fig04

以上のように「item.worldrot」で得られる9つの値が回転行列だってのはわかったけど、「item.rot」で3つの回転角度が得られるのに対してこれは回転行列というのはちょっと使いにくいね。もしアイテムのワールド回転角度が欲しかったら「その場でアンペアレント」でペアレントを解除してから「item.rot」でクエリし、また「その場でペアレント」で戻すとかしちゃうのが手っ取り早いのかな。

それではまた次回。

modo701ブログ目次



take_z_ultima at 11:30│Comments(0)TrackBack(0)modo | CG

トラックバックURL

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 

Archives