なんだかちょっとごたごたですが、いよいよ本当の3Dに取りかかります。もちろん最初は3角形です。
using System; using System.Drawing; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace Project2 { /// <summary> /// md3d2 の概要の説明です。 /// </summary> public class md3d2:Form { public md3d2():base() { //最小サイズを設定 this.MinimumSize=new Size(80,60); //ウィンドウの名前(かっこいいのを付けてあげてください) this.Text ="Direct3D-My"; } private Device device_; private PresentParameters presentParam_; /// <summary> /// Direct3Dの初期化を行います。 /// </summary> /// <returns>初期化が成功したかどうか</returns> public bool DXInitialize() { try { //プレゼンテーションパラメータを作成 presentParam_ = new PresentParameters(); //ウィンドウモード presentParam_.Windowed =true; //スワップエフェクトを設定。 presentParam_.SwapEffect = SwapEffect.Discard; //デバイスを作成 device_ = new Device(0,DeviceType.Hardware,this ,CreateFlags.HardwareVertexProcessing,presentParam_); creatVertex(); //初期化成功 return true; } catch { //初期化失敗 return false; } } /// <summary> /// 頂点バッファ /// </summary> private VertexBuffer vertexBuffer_; /// <summary> /// 頂点バッファ作成関数 /// </summary> private void creatVertex() { //頂点バッファ領域を確保 vertexBuffer_ = new VertexBuffer( typeof(CustomVertex.PositionColored),3, device_ , 0, CustomVertex.PositionColored.Format, Pool.Managed); //バッファをロック GraphicsStream stm = vertexBuffer_.Lock(0,0,0); //頂点データの配列を作成 CustomVertex.PositionColored[] verts = new CustomVertex.PositionColored[3]; //頂点データ verts[0].Position =new Vector3(0,2.0f,0); verts[0].Color = System.Drawing.Color.LightPink.ToArgb(); verts[1].Position =new Vector3(1.0f,0,0); verts[1].Color = System.Drawing.Color.Aqua.ToArgb(); verts[2].Position =new Vector3(-1.0f,0,0); verts[2].Color = System.Drawing.Color.Brown.ToArgb(); //頂点データをバッファに書き込み stm.Write(verts); //バッファのロックを解除 vertexBuffer_.Unlock(); } public void Render() { if(device_==null)return; if(this.WindowState ==FormWindowState.Minimized)return; //カメラの設定を行う device_.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f, 0.0f,-5.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3( 0.0f, 1.0f, 0.0f ) ); device_.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, (float)this.ClientSize.Width / (float)this.ClientSize.Height, 3.0f, 15.0f); device_.Clear(ClearFlags.Target,Color.Blue,1.0f,0); device_.BeginScene(); device_.SetStreamSource(0,vertexBuffer_,0); device_.VertexFormat = CustomVertex.PositionColored.Format; device_.DrawPrimitives(PrimitiveType.TriangleList,0,1); device_.EndScene(); try { //更新 device_.Present(); } catch(DeviceLostException) { resetDevice(); } } /// <summary> /// デバイスのリセットを行う /// </summary> private void resetDevice() { int result; if(!device_.CheckCooperativeLevel(out result)) { if(result ==(int)ResultCode.DeviceLost) { //ちょっと待つ System.Threading.Thread.Sleep(10); } else if(result ==(int)ResultCode.DeviceNotReset) { device_.Reset(presentParam_); } } } } /// <summary> /// エントリクラス /// </summary> class Program { public static void Main() { using(md3d2 dxform =new md3d2()) { if(!dxform.DXInitialize()) { MessageBox.Show("Direct3Dの初期化に失敗しました。" ,"初期化の失敗"); return; } dxform.Show(); while(dxform.Created) { dxform.Render(); Application.DoEvents(); } } } } }
3Dには視点が必要と前に言いましたが、とうとうカメラが出て参りました。カメラの設定はわりと決まり切っています。(でも、本格的なってくればカメラも頻繁に動かしますよ)とりあえずカメラの部分だけ抜き出します。
//カメラの設定を行う device_.Transform.View = Matrix.LookAtLH( new Vector3( 0.0f, 0.0f,-5.0f ), new Vector3( 0.0f, 0.0f, 0.0f ), new Vector3( 0.0f, 1.0f, 0.0f ) ); device_.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, (float)this.ClientSize.Width / (float)this.ClientSize.Height, 3.0f, 15.0f);
こういうとき図を書けば分かり易いのでしょうけどとりあえず言葉だけで説明します。
public static Matrix LookAtLH( Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector );
この関数名前のまんまです。カメラのポジション、見ている点、どちらの方向がカメラの上方向であるかをそれぞれセットします。「Vector3」というのは浮動小数点(Single型)が三つ並んでいるだけです。三つあるときは左から「X,Y,Z」です。とりあえず、これによって作られた物をしかるべき所に代入する事によって一つ目の作業は完了です。
public static Matrix PerspectiveFovLH( float fieldOfViewY, float aspectRatio, float znearPlane, float zfarPlane );
こちらはさっきよりも難しいかもしれません。1つ1つ説明していきましょう。
横方向の視野の広さです。見える範囲の角度を表す数値でラジアンを利用します。(ラジアンが分からない方。π=180°と言う事です)狭いほど物が大きく見えます。
アスペクト比です。つまり縦横の比率です。「横÷縦」で計算します。
前方投影面までの距離です。
後方投影面までの距離です。
前方投影面と、後方投影面について説明します。現実世界では奥行きに限界はありません。ですが、パソコンでの処理では無限のものを扱うことは出来ません。そのため、見える限界を設定します。つまり、見える範囲は「前方投影面と後方投影面に挟まれ、視野の広さに応じた領域内」ということになります。
これでカメラについては一通り終わりです。図が無くても分かりましたか?
今回は本物の3Dという事で3次元空間上に頂点を置きます。(ついでなので色も付けます)そのために今回利用する頂点形式は「PositionColored」です。(まんまな名前です)必要な数値はPositionとColorの二つです。Positionには今回利用した「Vector3」を利用します。
前回行ったデバイス消失のコードも付け加えてあります。
なんか失敗ましたね。色が付いていません。
というわけでキレイに表示するためにはもう一手間。下の一行をカメラの設定の次に加えてください。
device_.RenderState.Lighting=false;
これで出来たと思います。この設定はライトをオフにする設定です。今回はライトを設定していないので設定した色の通りに表示してもらうための設定です。ライトについては後々説明します。
そういうわけで次回は回転させてみようと思います。
2006-4-15 頂点数が「6」になっていたので「3」に修正