CustomRenderTargetその3

DXRuby1.5.22devをWiki(避難所)に置いておいた。しょぼいバグの修正とset_viewportのデフォルト設定追加のみ。あとサンプルの整理。
本格的な3Dにはあんまり興味がないというか難しすぎて付いていけないのだが、初歩的な3Dぐらいはそれなりにやってみたい。ということで球体の描画や3D迷路を追加しておいた。
今回はそれらサンプルの中で最も簡単な立方体のやつについて。

おおまかな構成

クラスは3Dのオブジェクトを表すMaterialと、CustomRenderTargetを継承したRenderTarget3Dとなる。3Dのデータは基本的には頂点の集合体なので頂点バッファを持つが、それをどのように描画するのかというロジックも物体ごとに異なるのでシェーダも一緒に持つことが多い。のでMaterialクラスはそのようになっている。更に1つの物体が複数の部品で構成されてシェーダも違うのが混ざる、ということもあるので、本格的にやるならMaterialをたくさん保持するModelクラスを用意する、みたいな感じになる気がする。
RenderTarget3Dは特別なことはしていないが、このサンプルでは頂点データを座標と色でわけて2つ作ってみているので、2つの頂点バッファを使うようになっている。そういうこともできる。わけたほうがラクというのはよくあるので(他と共有するとか)、こういうことができるのは無駄ではない、かもしれない。

立方体

今回はこんな感じに立方体を作ってみた。毎回この手のやつは作り方に困るが、どうすれば簡単に座標を間違えずに作れるのかはいまだによくわからない。今思いついたのだが正方形を1つ作って回転させるのがラクかもしれない。今度やってみよう。

# 立方体を作る試練
# 四角を構成する頂点を返すメソッド
def make_square(v1, v2, v3)
  [v1.to_a, (v1+v2).to_a, (v1+v3).to_a, (v1+v2).to_a, (v1+v2+v3).to_a, (v1+v3).to_a].flatten
end

# 座標の頂点バッファ
v1 = make_square(Vector.new(-0.5, -0.5, -0.5), Vector.new( 1,  0,  0), Vector.new(0,  1,  0)) + 
     make_square(Vector.new( 0.5, -0.5, -0.5), Vector.new( 0,  0,  1), Vector.new(0,  1,  0)) + 
     make_square(Vector.new( 0.5, -0.5,  0.5), Vector.new(-1,  0,  0), Vector.new(0,  1,  0)) +
     make_square(Vector.new(-0.5, -0.5,  0.5), Vector.new( 0,  0, -1), Vector.new(0,  1,  0)) +
     make_square(Vector.new(-0.5, -0.5, -0.5), Vector.new( 0,  0,  1), Vector.new(1,  0,  0)) +
     make_square(Vector.new( 0.5,  0.5,  0.5), Vector.new(-1,  0,  0), Vector.new(0,  0, -1))

変換行列

Materialが保持するmはワールド座標(姿勢も一緒に持つ)行列だが、ビューとプロジェクションはRenderTarget3Dに持っている。

rt3d.view = Matrix.look_at(Vector.new(0, 0, -4), Vector.new(0, 0, 0), Vector.new(0, 1, 0))
rt3d.proj = Matrix.projection_fov(30.0, Window.width.to_f / Window.height, 3.0, 1000.0)

Matrix.look_atはカメラの位置、視線の先の座標、上方向のそれぞれVectorを渡すと、そのようにビュー変換行列を作ってくれる。Matrix.projection_fovは視野角と画面サイズの縦横比率、Zn、Zfを渡すとプロジェクション変換行列を作ってくれる。便利メソッドである。ただまあ、このへんどう設定すればどういう見た目になるのかは相変わらずよくわからないのでちょっとした物体の描画をするときには毎回試行錯誤する。何かしら世界を構築してその中を歩くとかならまだ想像できるのだが。

Shader

すごく簡単になっているが、とりあえず頂点シェーダでは頂点バッファ2のほうで指定しているD3DDECLUSAGE_COLORの使用方法インデックス0がではCOLOR0として受け取れる。座標はワールド・ビュー・プロジェクション変換して出力する。色はそのまま。とするとピクセルシェーダに色が渡されて、立方体が描画できる。

おしまい

こういうのでモデルデータをしっかり作って頂点シェーダやピクセルシェーダで綺麗に描画するようにごにょごにょするとちょっと昔の3Dゲームぐらいの見た目は実現できる、らしい。
3Dの人などを綺麗に描画しようとするとスキンメッシュとか影とかで大変な難しさになるわけだが、例えばMMDのモデルを描画して動かすなどはできるはずで、まあ、いつかできるとイイデスネ。