2015年5月20日水曜日

3D変換について

要点だけ抑えてみましょう。3D レンダリング(描画)とは3D っぽくみせることです。
例えば前後に動いている板があなたの前にあるとしましょう。

あなたはどう奥行き感じますか?

奥に行くと小さくなるように見えて、手前に来ると大きくなるように見えるでしょう。
パソコンの中の3D 表現とはまさにそういうことです。

とあるオブジェクトがカメラの前に近づくと大きくみせ、遠ざかると小さくみせるだけです。

え?じゃーどうやって?
この二つの絵をみてみましょう。実はすごくシンプルな考え方なんです。


 



真ん中のモンスターの大きさを変えるだけで、手前に来てるような感じがしますね。
(もちろん比較対象が少なすぎて遠近感があんまり感じられないんですけどw)
で?具体的にどんな変換があったのかみましょうか?

このキャラクターの3Dでの左上座標をみてみましょう。

左はXYZ -0.5, 0.5, 1.0
右はXYZ -0.5, 0.5, 5.0

Z座標が変わっていますね。
でも、これだけじゃよく仕組みがわかりませんね。では四角で囲ってみましょう。
で、それの画面上での左上の点の座標を比較してみましょう。

左のほうはX=243.00 Y=163.00で
右のほうはX=294.00 Y=214.00です。

どうでしょうか?なんかわかりますか?実は3D 描画というのは
「最終的に画面のどの位置にどのサイズで描画するか」を演算する処理を言います。
われわれが見ているパソコンのディスプレイは平面ですね。そこに奥行などありません。
ただ平いだけです。

つまり
3D座標→あらゆる変換用の数学式にかける→画面の2D座標
というシンプルな(変換用の数学式を誘導するのはかなり複雑です)ものです。
Openl GLes系はこの機能がついてませんが、DirectXは親切にすべての機能が揃えてあります。
これをネットで調べてみるとものすごい難しく説明します。(あらゆる数学の式で表現してあるので見るだけで嫌になりますw)

実は3D表現をするだけならその式を全部知る必要はありません。
最近のライブラリは優秀なので、あらかじめデバイスの中に
その機能を備えてあるものがほとんどです。

もちろん、高度なことをやろうとすれば、全部わかる必要はありますが、
「んなことじゃなくてとりあえずやってみたいんだ」って方は
今使っているデバイスでのやり方だけを調べてその関数を使うだけでOKだと思います。

例えば、DirectX9では

D3DXMATRIX World;
D3DXMATRIX Offset;
D3DXMATRIX View;
D3DXMATRIX Persp;
D3DXMatrixIdentity( &World ); //とりあえず、World行列をリセット

D3DXMatrixTranslation( &Offset, 描画したい位置);
D3DXMatrixMultiply( &World, &World, &Offset ); //描画したい位置をセット
D3DXMatrixLookAtLH(
                  &View,
                  &D3DXVECTOR3(カメラ位置),
                  &D3DXVECTOR3(0, 0, 0),
                  &D3DXVECTOR3(カメラが見ている方向)
                  );//カメラをセット
D3DXMatrixPerspectiveFovLH( &Persp, D3DXToRadian(視野角), 画面の横サイズ/画面の縦サイズ, 1.0f, 10000.0f);//視野角をセット

//描画デバイスにオブジェクトの描画位置を教える
描画デバイス->SetTransform(D3DTS_WORLD, &World);
//カメラ情報を教える。
描画デバイス->SetTransform(D3DTS_VIEW, &View);
//視野角情報を教える
描画デバイス->SetTransform(D3DTS_PROJECTION, &Persp);

描画式

上のやつで描画されます。Open GL自体にはD3DXMatrixTranslationとか
D3DXMatrixMultiplyとかD3DXMatrixLookAtLHとかD3DXMatrixPerspectiveFovLHとか
こういう便利な関数がないのですが、使っているデバイス(例えばiOS, Android)の
デバイスライブラリでこの機能があると思いますので、似たような名前か似たような
機能がありましたらそれを上のものに置き換えたら3D描画ができます。
SetTransformとかはデバイス依存の関数なのでこれも変えないといけませんねw

0 件のコメント:

コメントを投稿