2008年4月8日火曜日

pv3dのFace3D.renderを理解したい

pv3dではどうやってレンダリングしてるんだろう と調べていたら Face3Dにいきついた。

Face3D.renderに

var a1  :Number  = this._a;
var b1  :Number  = this._b;
var c1  :Number  = this._c;
var d1  :Number  = this._d;
var tx1 :Number = this._tx;
var ty1 :Number = this._ty;

var a2 :Number = x1 - x0;
var b2 :Number = y1 - y0;
var c2 :Number = x2 - x0;
var d2 :Number = y2 - y0;

var matrix :Matrix = _bitmapMatrix;
matrix.a = a1*a2 + b1*c2;
matrix.b = a1*b2 + b1*d2;
matrix.c = c1*a2 + d1*c2;
matrix.d = c1*b2 + d1*d2;
matrix.tx = tx1*a2 + ty1*c2 + x0;
matrix.ty = tx1*b2 + ty1*d2 + y0;

container.beginBitmapFill( texture, matrix, true, material.smooth );

という処理部分がある。

_a,_b,_c,_d,_tx,_ty は Face3D.transformUVであらかじめ計算されている。

x0,x1,x2,y0,y1,y2 は3つの頂点(vertices)のx,y座標。

で、ここは結局なにをしているかというと

     / a1  b1  0 \
M0 = | c1  d1  0 |
     \ tx1 ty1 1 /

     / a2  b2  0 \
M1 = | c2  d2  0 |
     \ x0  y0  1 /

とした場合

M0 * M1

を計算した結果を、beginBitmapFillの引数に渡しているだけだ。

この M0 * M1 は 3つの頂点からなる三角形にビットマップを塗るための 変形を意味しているのだろう。 3つの頂点がobjectのx,y,z座標によって変化することで 三角形は変形する。 その変形に合わせて塗るビットマップを変形するために指定するのが この行列ということだろう。

しかし このM0,M1は 何を意味しているのだろうか。

M0はFace3D.transformUVを見ると uvから行列をつくって それを逆行列に変換している。 つまり M0 * M1 は 実際には なにかしらの行列の逆行列を M1にかけていることになる。

どういうときに逆行列をかけるのか調べると 計算しやすいように 基本的な図形(例えば長方形なら正方形)に戻す というときに使われることがあるようだ。

もしそうならば M0は M1変換を行うための前準備にあたるのかもしれない。 そこで先にM1について考える。

三角形で基本的な図形というと P0(0, 0), P1(0, 1), P2(1, 0) の3点からなる直角二等辺三角形を 考えてみた。

     / a2  b2  0 \
M1 = | c2  d2  0 |
     \ x0  y0  1 /

を詳しくかくと

     / x1 - x0  y1 - y0  0 \
M1 = | x2 - x0  y2 - y0  0 |
     \   x0       y0     1 /

ということになる。 頂点P 3点にこのM1をかけるとどうなるか。

              / x1 - x0  y1 - y0  0 \
< 0  0  1 > * | x2 - x0  y2 - y0  0 |
              \   x0       y0     1 /
= < x0  y0  1 >

              / x1 - x0  y1 - y0  0 \
< 1  0  1 > * | x2 - x0  y2 - y0  0 |
              \   x0       y0     1 /
= < x1-x0+x0  y1-y0+y0  1 >
= < x1  y1  1 >

              / x1 - x0  y1 - y0  0 \
< 1  0  1 > * | x2 - x0  y2 - y0  0 |
              \   x0       y0     1 /
= < x2-x0+x0  y2-y0+y0  1 >
= < x2  y2  1 >

となる。 これはつまり M1は P0(0, 0), P1(0, 1), P2(1, 0) の3点からなる直角二等辺三角形を Q0(x0, y0), Q1(x1, y1) Q2(x2, y2) の任意の3点からなる三角形に変形する行列 ということになる。

では次に M0は任意の三角形を P0(0, 0), P1(0, 1), P2(1, 0) に戻す変形を行っているのだろうか。

M1の逆行列は Face3D.transformUVをみると

         / u1 - u0  v1 - v0  0 \
M0inv =  | u2 - u0  v2 - v0  0 |
         \   u0       v0     1 /

となっている。 (M1と同じ形だ)

u1,u2,u3 は 3つのuv (三角形の3つの頂点のu,v値) の uにbitmap.widthを vにbitmap.heightを それぞれかけたものだ。

var w  :Number = material.bitmap.width;
var h  :Number = material.bitmap.height;

var u0 :Number = uv[0].u * w;
var v0 :Number = uv[0].v * h;
var u1 :Number = uv[1].u * w;
var v1 :Number = uv[1].v * h;
var u2 :Number = uv[2].u * w;
var v2 :Number = uv[2].v * h;

u,vは0から1の値で それにwidth,heightをかけることで bitmapのどの位置とマップをとるかの bitmap上の座標を得ることができる。

で M1にM0invの逆行列をかけているということは 頂点P 3点からなる三角形に M0inv変換を行うと bitmap (厳密にはbitmapを三角形にきりだした部分か?) になる ということを期待していることになる。

ここで例えば 10x10のビットマップがあって それを対角線上に2つに分割し B0(0,0), B1(10,0), B2(0,10) からなる三角形を得た場合

それぞれのuvは B0uv(0,0), B1uv(1,0), B2uv(0,1) になるであろうから これらにwidth,heightをかけて M0invは M1と同じ形をしているので 頂点P 3点からなる直角二等辺三角形を R0(0,0),R1(10,0),R2(0,10) の3点からなる三角形へ変形する行列をあらわしていて この三角形は 切り出したビットマップに一致する。

なるほど。

つまり 逆にいうと uv値というのは 頂点P 3点からなる直角二等辺三角形から もとのビットマップから切り出した三角形へ 復元できるような値を表している ということか。

コメント(0):