2011-07-23 10 views
4

OpenTKを使用して独自のエンジンを作成しています(基本的にC#用のOpenGLバインディング、gl *はGL *になります)。それぞれに数千の頂点があります。したがって、私は自分自身のカスタム頂点フォーマットが必要です。浮動小数点数を持つVec3は単純にあまりにも多くのスペースを占有するためです。私がやりたいことは、このレイアウトで私自身の頂点フォーマットを作成することですOpenGLを使用してカスタム頂点フォーマットを作成するには

を(私はここで頂点の数百万人について話している):ここで

Byte 0: Position X 
Byte 1: Position Y 
Byte 2: Position Z 
Byte 3: Texture Coordinate X 

Byte 4: Color R 
Byte 5: Color G 
Byte 6: Color B 
Byte 7: Texture Coordinate Y 

は、頂点のためのC#のコードは次のとおりです。

public struct SmallBlockVertex 
{ 
    public byte PositionX; 
    public byte PositionY; 
    public byte PositionZ; 
    public byte TextureX; 

    public byte ColorR; 
    public byte ColorG; 
    public byte ColorB; 
    public byte TextureY; 
} 

私は32^3のユニークな位置が必要なので、各軸の位置としてのバイトは十分です。

私は自分の頂点シェーダを作成しました。これは2つのvec4をそれぞれのバイトセットごとに入力として受け取ります。 マイ頂点シェーダはこれです:

attribute vec4 pos_data; 
attribute vec4 col_data; 

uniform mat4 projection_mat; 
uniform mat4 view_mat; 
uniform mat4 world_mat; 

void main() 
{ 
    vec4 position = pos_data * vec4(1.0, 1.0, 1.0, 0.0); 

    gl_Position = projection_mat * view_mat * world_mat * position; 
} 

問題を試してみて、単離するために、私はできるだけ私の頂点シェーダが同じくらい簡単行いました。 シェーダをコンパイルするためのコードは、即時モードの描画でテストされています。動作しているので、それはできません。

ここでは、頂点バッファを設定し、データで充填し、属性へのポインタを設定する私の関数です。

public void SetData<VertexType>(VertexType[] vertices, int vertexSize) where VertexType : struct 
    { 
     GL.GenVertexArrays(1, out ArrayID); 
     GL.BindVertexArray(ArrayID); 
     GL.GenBuffers(1, out ID); 
     GL.BindBuffer(BufferTarget.ArrayBuffer, ID); 

     GL.BufferData<VertexType>(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * vertexSize), vertices, BufferUsageHint.StaticDraw); 

     GL.VertexAttribPointer(Shaders.PositionDataID, 4, VertexAttribPointerType.UnsignedByte, false, 4, 0); 
     GL.VertexAttribPointer(Shaders.ColorDataID, 4, VertexAttribPointerType.UnsignedByte, false, 4, 4); 
    } 

私が理解から、これが正しい手順ですへ: 頂点配列オブジェクトを生成し、それが頂点バッファを生成し、それがデータで頂点バッファを満たす バインド バインド属性ポインタ

を設定

シェーダ。*データIDは、シェーダのコンパイルと使用後にこのコードで設定されます。

PositionDataID = GL.GetAttribLocation(shaderProgram, "pos_data"); 
ColorDataID = GL.GetAttribLocation(shaderProgram, "col_data"); 

そして、これは私のレンダリング機能である:

void Render() 
{ 
    GL.UseProgram(Shaders.ChunkShaderProgram); 

    Matrix4 view = Constants.Engine_Physics.Player.ViewMatrix; 
    GL.UniformMatrix4(Shaders.ViewMatrixID, false, ref view); 

    //GL.Enable(EnableCap.DepthTest); 
    //GL.Enable(EnableCap.CullFace); 
    GL.EnableClientState(ArrayCap.VertexArray); 
    { 
      Matrix4 world = Matrix4.CreateTranslation(offset.Position); 
      GL.UniformMatrix4(Shaders.WorldMatrixID, false, ref world); 

      GL.BindVertexArray(ArrayID); 
      GL.BindBuffer(OpenTK.Graphics.OpenGL.BufferTarget.ArrayBuffer, ID); 

      GL.DrawArrays(OpenTK.Graphics.OpenGL.BeginMode.Quads, 0, Count/4); 
    } 
    //GL.Disable(EnableCap.DepthTest); 
    //GL.Disable(EnableCap.CullFace); 
    GL.DisableClientState(ArrayCap.VertexArray); 
    GL.Flush(); 
} 

は誰もが私に(しゃれが意図していない)いくつかのポインタを与えるように親切にすることはできますか?私は間違った順序でこれをやっているのですか、あるいは私が呼び出す必要のある機能がありますか?

私はウェブ全体を検索しましたが、カスタム頂点を実装する方法を説明する良いチュートリアルまたはガイドは見つかりませんでした。 これ以上の情報が必要な場合は、そう言います。

+0

だから...実行するとどうなりますか?いずれにせよ、あなたがすべきことは、システムを動作させる状態にすることです。フロートデータで動作させる方法を知っているなら、それを使用してください。ちょうどそれを働かせてください。 stuffのレンダリングが正しく行われると、データをゆっくりと最適化できます。各ステップで、それが機能することを確認します。その後、あなたが壊れたポイントにヒットすると、何がうまくいかなかったのかが分かります。 –

+0

私はそれを実行しても何も起こりません。つまり、_runs_ですが、何も表示されません。浮動小数点データだけを使って試してみることにしますが、問題は、私自身の頂点フォーマット(つまりタイトル)を得るために何をすべきか分かりません。それは多くのことがうまくいかない、大きくて重要な一歩です(小さなステップに分けることはできません)。基本的には試行錯誤です。どのように知っていれば、私のコード内のエラーを見つけることができますか? – Azzi777

答えて

8

独自の頂点フォーマットを作成することはあまりありません。それはすべてglVertexAttribPointerコールで行われます。まず、ストライドパラメータとして4を使用していますが、頂点構造は8バイト幅であるため、頂点の先頭から次の8バイトがあるため、ストライドは8でなければなりません(両方の呼び出しでもちろんです) )。オフセットは正しいですが、確実にそれらが[0,1]の範囲にあるように、正規化されたフラグをtrueに設定する必要があります(これは頂点位置)。

次に、シェーダでカスタム頂点属性を使用する場合、廃止予定の固定機能配列(gl...ClienStateのもの)を有効にしないでください。代わりに、

GL.EnableVertexAttribArray(Shaders.PositionDataID); 
GL.EnableVertexAttribArray(Shaders.ColorDataID); 

と対応する​​コールを使用する必要があります。

count/4は、glDrawArraysコールで何を意味しますか。最後のパラメータはプリミティブではなく頂点の数を指定することに注意してください。しかし、おそらくそれはこのように意図されています。

これらの実際のエラーに加えて、シェーダでそれをデコードする必要があるような複雑な頂点フォーマットは使用しないでください。これは、ストライドとオフセットのパラメータがglVertexAttribPointerのものです。たとえば、あなたの頂点データビットを再定義:

public struct SmallBlockVertex 
{ 
    public byte PositionX; 
    public byte PositionY; 
    public byte PositionZ; 
    public byte ColorR; 
    public byte ColorG; 
    public byte ColorB; 
    public byte TextureX; 
    public byte TextureY; 
} 

、その後、あなただけの

GL.VertexAttribPointer(Shaders.PositionDataID, 3, VertexAttribPointerType.UnsignedByte, false, 8, 0); 
GL.VertexAttribPointer(Shaders.ColorDataID, 3, VertexAttribPointerType.UnsignedByte, true, 8, 3); 
GL.VertexAttribPointer(Shaders.TexCoordDataID, 2, VertexAttribPointerType.UnsignedByte, true, 8, 6); 

を使用することができますし、シェーダにあなたは

attribute vec3 pos_data; 
attribute vec3 col_data; 
attribute vec2 tex_data; 

を持っていて、解凍する必要はありません位置からのテクスチャ座標と自分自身の色。

あなたのスペース要件では、頂点の位置にバイトを使用することが本当に必要かどうかは、位置データの精度が極端に制限されるため、実際に考える必要があります。たぶん、ショーツや半精度の浮きが良い妥協であろう。

レンダリングメソッドでglBindBufferを呼び出す必要はありません。これはglVertexAttribPointerにのみ必要で、glBindVertexArrayでアクティブになるVAOに保存されます。また、通常はglFlushを呼び出さないでください。これは、バッファがスワップされたときにOSによって行われるためです(ダブルバッファリングを使用すると仮定します)。

最後に、ご使用のハードウェアが、使用しているすべての機能(VBOやVAOなど)をサポートしていることを確認してください。

EDIT:あなたは(VAOを作成し、結合した後、もちろん)SetData方法で

GL.EnableVertexAttribArray(Shaders.PositionDataID); 
GL.EnableVertexAttribArray(Shaders.ColorDataID); 

を呼び出すとすることができるようが実際の配列の有効フラグはまた、VAOに格納されていますレンダリング機能でVAOをglBindVertexArrayでバインドすると有効になります。ああ、私はちょうど別のエラーを見た。レンダリング機能でVAOをバインドすると、属性配列の有効フラグはVAOの状態によって上書きされ、VAOの作成後に有効にしなかったため、無効になります。だから、あなたが言ったようにそれをしなければならないでしょう、SetDataメソッドで配列を有効にします。実際にあなたのケースではあなたはラッキーであるかもしれませんし、レンダー機能でアレイを有効にしたとき(VAIOはglBindVertexArray(0)を呼び出していないので)、VAOは依然としてバインドされていますが、それにはカウントしないでください。

+0

本当に詳細な返信をありがとうございます。これは_lot_!私は明日それを見て戻って報告します。なぜなら、各頂点が32 * 32 * 32のサイズのチャンクの一部であり、整数の位置だけを表示する必要があるからです。次に、頂点を変換行列でオフセットします。 – Azzi777

+0

@ Azzi777 [OK]を、この場合、バイトは良い考えかもしれません。 –

+0

@ Azzi777更新された私の答え、別の可能性のある問題が見つかりました。 –