パッとしないことばっかりしていますが、これも基礎アレも基礎です。今回は立方体を作ります。
立体をつくためには線を集めていては時間がかかりすぎます。と言うわけで三角形を組み合わせて作ります。
それではまず三角形で四角形を作ります。簡単ですね、三角形を二つ繋げるだけです。今回は「TriangleList」を利用します。そうすると、四角形を作るためにいくつ頂点が必要になるでしょうか?三角形を二つ繋げるので・・・6つですね。
立方体には四角形の面が全部で6つあります。6*6=36です。ずいぶん多いですね。
と、36個とか言いながら立方体に頂点は8つしかありません。同じ点を何回も利用しているのですね。効率悪いですよね。でも、効率をよくするのは次回に任せて今回は効率の悪い方法で行きます。
今回はサイズ「2」の立方体を作ります。端の座標は「X,Y,Z」で「-1と1」です。
今回利用する頂点の形式は「CustomVertex.PositionOnly」です。つまり位置情報だけです。
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.PositionOnly),36, device_ , 0, CustomVertex.PositionOnly.Format, Pool.Managed); //頂点データの配列を作成 CustomVertex.PositionOnly[] verts = new CustomVertex.PositionOnly[36]; //頂点データ verts[0].Position =new Vector3(-1, 1,-1); verts[1].Position =new Vector3( 1,-1,-1); verts[2].Position =new Vector3(-1,-1,-1); verts[3].Position =new Vector3(-1, 1,-1); verts[4].Position =new Vector3( 1, 1,-1); verts[5].Position =new Vector3( 1,-1,-1); verts[6].Position =new Vector3(-1, 1, 1); verts[7].Position =new Vector3(-1,-1, 1); verts[8].Position =new Vector3( 1,-1, 1); verts[9].Position =new Vector3(-1, 1, 1); verts[10].Position =new Vector3( 1,-1, 1); verts[11].Position =new Vector3( 1, 1, 1); verts[12].Position =new Vector3(-1, 1,-1); verts[13].Position =new Vector3(-1,-1,-1); verts[14].Position =new Vector3(-1,-1, 1); verts[15].Position =new Vector3(-1, 1,-1); verts[16].Position =new Vector3(-1,-1, 1); verts[17].Position =new Vector3(-1, 1, 1); verts[18].Position =new Vector3( 1, 1,-1); verts[19].Position =new Vector3( 1,-1, 1); verts[20].Position =new Vector3( 1,-1,-1); verts[21].Position =new Vector3( 1, 1,-1); verts[22].Position =new Vector3( 1, 1, 1); verts[23].Position =new Vector3( 1,-1, 1); verts[24].Position =new Vector3( 1,-1,-1); verts[25].Position =new Vector3(-1,-1, 1); verts[26].Position =new Vector3(-1,-1,-1); verts[27].Position =new Vector3( 1,-1,-1); verts[28].Position =new Vector3( 1,-1, 1); verts[29].Position =new Vector3(-1,-1, 1); verts[30].Position =new Vector3( 1, 1,-1); verts[31].Position =new Vector3(-1, 1,-1); verts[32].Position =new Vector3(-1, 1,1); verts[33].Position =new Vector3( 1, 1,-1); verts[34].Position =new Vector3(-1, 1, 1); verts[35].Position =new Vector3( 1, 1, 1); //バッファをロック GraphicsStream stm = vertexBuffer_.Lock(0,0,0); //頂点データをバッファに書き込み stm.Write(verts); //バッファのロックを解除 vertexBuffer_.Unlock(); } public void Render() { if(device_==null)return; if(this.WindowState ==FormWindowState.Minimized)return; device_.Transform.World = Matrix.RotationY(Environment.TickCount /300f) * Matrix.RotationX(Environment.TickCount /400f); //device_.RenderState.CullMode = Cull.None; //カメラの設定を行う device_.Transform.View = Matrix.LookAtLH( new Vector3( 5.0f, 5.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_.RenderState.Lighting=false; device_.Clear(ClearFlags.Target,Color.Blue,1.0f,0); device_.BeginScene(); device_.SetStreamSource(0,vertexBuffer_,0); device_.VertexFormat = CustomVertex.PositionOnly.Format; device_.DrawPrimitives(PrimitiveType.TriangleList,0,12); 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("Diret3Dの初期化に失敗しました。" ,"初期化の失敗"); return; } dxform.Show(); while(dxform.Created) { dxform.Render(); Application.DoEvents(); } } } } }
手打ちだとめんどくさいですが座標の関係がよく分かりますよ。カリングが行われるので、見たときに時計回りになるように座標を設定します。
カメラとワールド変換の場所がちょこっといじってあります。カメラは斜めから原点を見るような設定です。ワールド変換は「X,Y」の二軸がグルグルと回るようになっています。実行してみるとよく分かります。
このコードでは同じ頂点が沢山あります。Direct3Dではこれらを1つにまとめる機能があります。次回はその紹介です。
これが出来た方は、ぜひ前回の変更を施してみてください。