2011-06-29 8 views
2

OpenTKを使用してC#でモデルを描画するためにVBOを使用しようとしています。私のオンライン調査では、私はインターリーブされたデータ構造のサイズは32バイトの倍数を作ることをお勧めしている多くの場所で読んで、私は次のことをアップコード化:VBOs Cでインターリーブされた頂点を使用する

[Serializable] 
[StructLayout(LayoutKind.Sequential)] 
public struct Byte4 
{ 

    public byte R, G, B, A; 

    public Byte4(byte[] input) 
    { 
     R = input[0]; 
     G = input[1]; 
     B = input[2]; 
     A = input[3]; 
    } 

    public uint ToUInt32() 
    { 
     byte[] temp = new byte[] { this.R, this.G, this.B, this.A }; 
     return BitConverter.ToUInt32(temp, 0); 
    } 
} 

[Serializable] 
[StructLayout(LayoutKind.Sequential)] 
public struct VertexInterleaved 
{ 
    // data section is exactly 36 bytes long??? - need padding to get multiple of 32? 
    public Vector3 vertex; // Vertex 
    public Vector3 normal; // Normal Vector 
    public Vector2 textureCoord; // First Texture Coordinates 
    public Byte4 rgbaColor; // RGBA value of this vertex 
    //public byte[] padding; 

    public static int VertexStride() 
    { 
     // if I'm using the padding I have to add the appropriate size to this... 
     return (8 * sizeof(float) + 4 * sizeof(byte)); 
    } 
} 

public class VertexBufferObject 
{ 
    private uint[] _VBOid; 

    private int _vertexStride; 
    private int _totalIndices; 
    private int _totalVertices; 

    public VertexBufferObject() 
    { 
     _VBOid = new uint[2]; 
     GL.GenBuffers(2, _VBOid); 
    } 

    public bool DeleteVBO() 
    { 
     GL.DeleteBuffers(2, _VBOid); 
    } 

    private void BindBuffers() 
    { 
     GL.BindBuffer(BufferTarget.ArrayBuffer, _VBOid[0]); 
     GL.BindBuffer(BufferTarget.ElementArrayBuffer, _VBOid[1]); 
    } 

    private void ReleaseBuffers() 
    { 
     GL.BindBuffer(BufferTarget.ArrayBuffer, 0); 
     GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); 
    } 


    public void BufferMeshData(Mesh3DCollection mesh3Ds) 
    { 
     _vertexStride = VertexInterleaved.VertexStride(); 

     _totalIndices = mesh3Ds.TotalIndices(); 
     _totalVertices = mesh3Ds.TotalVertices(); 

     VertexInterleaved[] vboVertices = new VertexInterleaved[_totalVertices]; 
     uint[] vboIndices = new uint[_totalIndices]; 

     int vertexCounter = 0; 
     int indexCounter = 0; 

     foreach (Mesh3D m in mesh3Ds) 
     { 
      foreach (VertexInterleaved v in m.vertices) 
      { 
       vboVertices[vertexCounter] = v; 
       vertexCounter++; 
      } 

      foreach (uint i in m.indices) 
      { 
       vboIndices[indexCounter] = i; 
       indexCounter++; 
      } 
     } 

     BindBuffers(); 

     GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr) (_totalIndices * sizeof(uint)), vboIndices, BufferUsageHint.StaticDraw); 
     GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(_totalVertices * _vertexStride), vboVertices, BufferUsageHint.StaticDraw); 

     ReleaseBuffers(); 
    } 

    public void RenderVBO() 
    { 
     GL.EnableClientState(ArrayCap.VertexArray); 
     GL.EnableClientState(ArrayCap.NormalArray); 
     GL.EnableClientState(ArrayCap.ColorArray); 

     BindBuffers(); 

     GL.VertexPointer(3, VertexPointerType.Float, _vertexStride, (IntPtr) (0)); 
     GL.NormalPointer(NormalPointerType.Float, _vertexStride, (IntPtr) (3 * sizeof(float))); 
     GL.TexCoordPointer(2, TexCoordPointerType.Float, _vertexStride, (IntPtr) (6 * sizeof(float))); 
     GL.ColorPointer(4, ColorPointerType.Byte, _vertexStride, (IntPtr) (8 * sizeof(float))); 

     GL.DrawElements(BeginMode.Quads, numIndices, DrawElementsType.UnsignedInt, startLocation); 

     ReleaseBuffers(); 

     GL.DisableClientState(ArrayCap.VertexArray); 
     GL.DisableClientState(ArrayCap.NormalArray); 
     GL.DisableClientState(ArrayCap.ColorArray); 
    { 

} 

固有の質問:

1.)インターリーブされた頂点データ構造体は構造体かクラスであるべきですか?これは、VBOやメモリフットプリントに関する限り、違いがありますか? (私は構造体を使用することに決めましたが、間違っていると感じました。なぜなら、頂点はメモリに入れば変更されないためです)。0126サイズは32バイトですか? (つまり、正しいサイズを強制するために "ダミー"パディングメンバが必要ですか?)私がオンラインで見つけたすべての例はC++で書かれていましたので、特に同じアイデアや動機がC#に引き継がれるかどうかに関心があります。

3.) [Serializable] [StructLayout(LayoutKind.Sequential)] は本当に必要ですか?私はこれを私がオンラインで見つけた例からコピーしました...

答えて

1

1.)構造内のデータが定期的に変更される場合は、クラスを使用することをお勧めします。これはメモリへの参照ですロケーション。それはかなり静的な場合、私はこれが想像しているように、それは値の型である構造体を使用する方が良いです。

2)私は32 バイト -aligned境界にインターリーブされた頂点データのブロックを揃えることは、パフォーマンスの向上、優れたキャッシュラインの一貫性を持っていることを聞いたことがあるが、私はすべての性能向上の良い例を見ていません。

3.)はい、それは、型のフィールドがソースコードで宣言されているのと同じ順序でメモリに配置されることを指定します。インタリーブされたデータにとっては明らかに重要です。

+0

私は同じことを読んでいました。私のコードはパディングの有無にかかわらず同じように動作するので、何か間違ったことをしたり、どこかでポイントを紛失したりする恐れがありました。私が誤って "ビット"とタイプしたことを私に警告してくれてありがとう。 – seveland

関連する問題