0

こんにちは、このチュートリアルhttp://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/を使用して OpenGl を学習しようとして います。1つの三角形で機能する多くのコードを示していますが、これ以上の例はありません. Atm 描画する関数を書こうとしています。線や長方形で、私には難しいので問題があります。再利用可能な関数を書きたい。しかし、私は VBO を理解していません :/ メインループから実行される関数 draw を書きたいです。

class lines{
    public: lines(){
    }
    static void draw(GLuint ve){

        float vertices[] = {-0.5f, -0.5f, 0.5f, 0.5f};
        unsigned int indices[] = {0, 1};

        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(2, GL_FLOAT, 0, vertices);
        glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, indices);
    }
};


    // Ensure we can capture the escape key being pressed below
glfwEnable( GLFW_STICKY_KEYS );

// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);

// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" );


static const GLfloat g_vertex_buffer_data[] = { 
    -0.8f, -1.0f,0.0f,
    0.8f,  -1.0f, 0.0f,
    -0.8f,   1.0f, 0.0f,
    -0.8f, 1.0f, 0.0f,
    0.8f, 1.0f, 0.0f,
    0.8, -1.0f, 0.0f,
};

GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

do{

    // Clear the screen
    glClear( GL_COLOR_BUFFER_BIT );

    // Use our shader
    glUseProgram(programID);

    // 1rst attribute buffer : vertices
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glVertexAttribPointer(
        0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
        3,                  // size
        GL_FLOAT,           // type
        GL_FALSE,           // normalized?
        0,                  // stride
        (void*)0            // array buffer offset
    );

    glDrawArrays(GL_TRIANGLES, 0, 6); 

    glDisableVertexAttribArray(0);
    lines::draw(vertexbuffer);
    // Swap buffers
    glfwSwapBuffers();

} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS &&
       glfwGetWindowParam( GLFW_OPENED ) );
4

1 に答える 1

3

プリミティブを描画するには、OpenGL に頂点のリストとそれらを接続するパターン (線や三角形などを形成するため) を与えます。これを行う最も簡単な方法は、即時モード ( glBegin/ glVertex3f/ glEnd) です。即時モードは非常に遅く、すべての頂点を「頂点配列」(頂点配列オブジェクト (VAO) ではなく、異なります) を介して一度に渡す方がはるかに高速ですg_vertex_buffer_data。頂点配列は、メイン メモリ内の配列へのポインタを に渡すときですglVertexPointer。これは高速ですが、描画するたびに配列全体を GPU に送信します。頂点バッファー オブジェクト (VBO) を使用すると、配列を送信して GPU メモリに格納できます。VBO を使用すると、ドロー コールを送信するだけで済み、データはすでに GPU にあるため、転送がなく、はるかに高速です。glVertexPointerバインドを高速化し、glDraw*Indirect既に GPU メモリにあるパラメーターを使用して描画できるようにするための引数ですが、後でそれらを残しておきます。

ほとんどのチュートリアルは、ハード コードされた頂点から始まりますが、もちろん最終的なアプリケーションの場合、これは実用的ではありません。任意のジオメトリの多くのビットを保存したい。あなたに似たメッシュクラスlinesは非常に一般的です。重要な点は、メッシュには頂点のリストがあるということです。インデックスの配列を追加して、既存の頂点を再参照してプリミティブを形成し、メモリと重複頂点の計算を節約できます。

しかし、今のところ即時モード レンダリングから始めます。

あなたを始めるために、

struct vec3f {
    float x, y, z;
    vec3f(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {}
};

class Mesh {
    std::vector<vec3f> vertices;
public:
    void add(float x, float y, float z)
    {
        vertices.push_back(vec3f(x, y, z));
    }
    void draw()
    {
        glBegin(GL_LINE_STRIP);
        for (size_t i = 0; i < vertices.size(); ++i)
            glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z);
        glEnd();
    }
};

そしてそれを使用するには、

Mesh square;
...
//Lots of add() and push_back is slow. Much faster to use
//dynamic allocation yourself and copy data in bigger blocks,
//but this will do for an example.
square.add(-1,-1,0);
square.add(-1,1,0);
square.add(1,1,0);
square.add(1,-1,0);
square.add(-1,-1,0); //these could also be read from a file
...
line.draw();

std::list<Mesh> lines;このアイデアにより、たとえばグローバルを持つことができます。初期化時、ファイルから、または実行時に一度行を追加できます。次に、描画コードは各要素で draw を呼び出すだけです。後でこのアイデアを拡張して、三角形もサポートすることができます (例: メンバーを作成GL_LINE_STRIPprimitiveます)。stride後で、インデックス、法線 (ここでは、関数のパラメーターを使用してインターリーブ頂点/法線データを検索する必要がありgl*Pointerます)、色/マテリアルなどを追加できます。

VBO の使用に関する質問に進みます。glGenBuffersは、VBO を参照するための一意のハンドルを提供します - 単純に整数です。その VBO を変更または使用するときはいつでも、それをバインドする必要があります。

glBufferData(GL_ARRAY_BUFFER...現在バインドされているオブジェクトの実際の初期化/サイズ変更を行いGL_ARRAY_BUFFER(まだバインドされていない場合)、データ引数が NULL でない場合はデータを転送します。

glVertexAttribPointerは、上記の「頂点配列」のメイン メモリ内の配列を渡していると想定します。そうでないglBindBuffer(GL_ARRAY_BUFFER, vbo)場合は、最後の引数がその VBO へのオフセットになります。あなたが電話した後glVertexAttribPointer

そう、

1. glGenBuffers
2. glBufferData (while the buffer is bound)

これで初期化が完了しました。描画に...

3. glVertexAttribPointer (while the buffer is bound)

それから

4. glDrawArrays

また

4. glDrawElements (while an element array buffer is bound, containing the order in which to draw the vertices)

したがって、メッシュ クラスを拡張するには、少なくともGLuint vertexBuffer;. upload()たぶん、ハンドルを生成して現在のデータをバッファリングする関数を追加します。次に、メイン メモリ内の頂点データがもう必要ないと仮定してvertices.clear()(実際には、 std::vectorの場合はthisを使用) を呼び出すことができます。次に、描画関数を変更して、vbo、call 、unbind をバインドし、 (現在はゼロである可能性があるメンバーからglVertexPointer) をバインドします。glDrawArraysnumVerticesvertices.size()

関連する投稿は次のとおりです。

于 2013-10-24T02:55:20.647 に答える