イメージとしては配列の「添え字」です。立方体の場合で言えば、8つの頂点をどの順番で三角形の描画に利用するかを指示するためのものです。具体的なソースコードを載せましょう。
private void creatVertex() { //頂点バッファ領域を確保 vertexBuffer_ = new VertexBuffer(typeof(CustomVertex.PositionOnly), 8, device_, 0, CustomVertex.PositionOnly.Format, Pool.Managed); //頂点データの配列を作成 CustomVertex.PositionOnly[] verts = new CustomVertex.PositionOnly[8]; //頂点データ 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); //バッファをロック GraphicsStream stm = vertexBuffer_.Lock(0,0,0); //頂点データをバッファに書き込み stm.Write(verts); //バッファのロックを解除 vertexBuffer_.Unlock(); //インデックスバッファ領域を確保 indexBuffer_ = new IndexBuffer(typeof(Int16), 36,device_,0,Pool.Managed); //インデックスデータの配列を作成 Int16 []indexData ={2,1,0,1,2,3, 5,6,4,6,5,7, 0,1,4,5,4,1, 6,3,2,7,3,6, 4,2,0,2,4,6, 1,3,5,7,5,3, }; indexBuffer_.SetData(indexData,0,0); }
座標のデータが8つ。その8つの中のどれをどの順に使うかをインデックスで指定しています。図を描くと分かり易いです。え?載せてくれないのかって?大丈夫あなたなら自分で出来ます。
public IndexBuffer( Type typeIndexType, int numberIndices, Device device, Usage usage, Pool pool );
「typeIndexType」は型を指定します。大抵は「Int16」か「Int32」でしょう。「numberIndices」はインデックスの数です。何個の入れ物を作るかの方ですので、くれぐれもサイズと勘違いしないでください。「Device」よりあとは適当に設定してください。(usage=0,pool=Managedで良いと思います)
public void SetData( object data, int lockAtOffset, LockFlags flags );
「data」はインデックス配列を渡してください。「lockAtOffset」と「flags」は0でいいです。
描画の所で最初にすることはインデックスをデバイスにセットすることです。DeviceのIndicesにインデックスバッファをセットしてください。もちろん頂点データのセットも忘れないでください。
それが終わったら描画を行います。インデックスを使用した場合はDrawPrimitiveではなくDrawIndexedPrimitivesを使用します。
public void DrawIndexedPrimitives( PrimitiveType primitiveType, int baseVertex, int minVertexIndex, int numVertices, int startIndex, int primCount );
難しそうですけど半分はオフセットです。
「baseVertex」は頂点データ側のオフセット。
「startIndex」はインデックスバッファ側のオフセット。
「minVertexIndex」はインデックスバッファの中に含まれる最小の頂点インデックスです。
「numVertices」はこの呼び出しの間に使われる頂点の数です。baseVertex+minVertexIndexから始まります。
「primCount」は描画するプリミティブの数です。
めんどくさそうですが、実際に使うと分かります。
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 IndexBuffer indexBuffer_; /// <summary> /// 頂点バッファ作成関数 /// </summary> private void creatVertex() { //頂点バッファ領域を確保 vertexBuffer_ = new VertexBuffer( typeof(CustomVertex.PositionOnly),8, device_ , 0, CustomVertex.PositionOnly.Format, Pool.Managed); //頂点データの配列を作成 CustomVertex.PositionOnly[] verts = new CustomVertex.PositionOnly[8]; //頂点データ 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); //バッファをロック GraphicsStream stm = vertexBuffer_.Lock(0,0,0); //頂点データをバッファに書き込み stm.Write(verts); //バッファのロックを解除 vertexBuffer_.Unlock(); //インデックスバッファ領域を確保 indexBuffer_ = new IndexBuffer( typeof(Int16), 36,device_,0,Pool.Managed); //インデックスデータの配列を作成 Int16 []indexData ={2,1,0,1,2,3, 5,6,4,6,5,7, 0,1,4,5,4,1, 6,3,2,7,3,6, 4,2,0,2,4,6, 1,3,5,7,5,3, }; indexBuffer_.SetData(indexData,0,0); } 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_.Indices =indexBuffer_; device_.VertexFormat = CustomVertex.PositionOnly.Format; device_.DrawIndexedPrimitives( PrimitiveType.TriangleList,0,0,8,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("Direct3Dの初期化に失敗しました。" ,"初期化の失敗"); return; } dxform.Show(); while(dxform.Created) { dxform.Render(); Application.DoEvents(); } } } } }
ここまでの知識を応用すると円柱や三角錐なども作れます。(もちろん他の3Dオブジェクトを作る事も可能です。めんどくさいですが)
次回は光(光源とオブジェクト)について説明します。