Что такое современный OpenGL эквивалентный glBegin/glEnd

Я строю графический API для OpenGL, который основан на базовом графическом стиле призыва к рисованию. По сути, вместо того, чтобы хранить данные в графическом процессоре и вызывать их, используя их дескриптор, дайте информацию, чтобы нарисовать, каким она должна быть при каждом обновлении. Я знаю, что это медленно, но это просто и для не критичных к производительности приложений. Во всяком случае, есть ли современный эквивалент glBegin / glEnd? Это не обязательно вызов для каждой вершины, но способ, которым я могу отправлять данные каждое обновление, не сохраняя вершины в GPU?

2 ответа

Вы в значительной степени ответили на свой вопрос.

есть ли современный эквивалент glBegin/glEnd? Это не обязательно вызов для каждой вершины, но способ, которым я могу отправлять данные каждое обновление, не сохраняя вершины в GPU?

В принципе нет, современный способ заключается в использовании VAO с VBO (и IBO).

Если вы собираетесь изменить данные в VBO, помните, что вы можете изменить mode параметр в glBufferData.

  • GL_STREAM_DRAW - содержимое хранилища данных будет изменено один раз и использоваться не более нескольких раз.

  • GL_STATIC_DRAW - содержимое хранилища данных будет изменено один раз и использовано много раз.

  • GL_DYNAMIC_DRAW - Содержимое хранилища данных будет неоднократно изменяться и использоваться много раз.

Тогда вместо использования GL_STATIC_DRAWзатем используйте GL_DYNAMIC_DRAW это значительно увеличит FPS по сравнению с использованием GL_STATIC_DRAWОднако это зависит от объема данных и частоты их изменения. Но постарайтесь ограничить его настолько, насколько это возможно, например, не обновляйте данные в буферах, если вам это не нужно.

Вы можете прочитать больше о различных буферах в вики OpenGL, нажав здесь.

Ищите использование VAO / VBO, это то, что вы хотите реализовать.
В коде C/C++ ниже приведен простой пример.
Режим входной переменной - GL_POINYS/TRIANGLES/QUADS/.... (как в glBegin())
Это также единственный вариант с GLSL и профилем ядра для передачи атрибутов (glVertex/glNormal/... неизвестен в ядре в течение некоторого времени)

//------------------------------------------------------------------------------
//--- Open GL VAO example (GLSL) -----------------------------------------------
//------------------------------------------------------------------------------
#ifndef _OpenGL_VAO_example_h
#define _OpenGL_VAO_example_h
//------------------------------------------------------------------------------
GLuint vbo[4]={-1,-1,-1,-1};
GLuint vao[4]={-1,-1,-1,-1};
const float vao_pos[]=
    {
//       x      y     z
     0.75f, 0.75f, 0.0f,
     0.75f,-0.75f, 0.0f,
    -0.75f,-0.75f, 0.0f,
    };
const float vao_col[]=
    {
//      r   g    b
     1.0f,0.0f,0.0f,
     0.0f,1.0f,0.0f,
     0.0f,0.0f,1.0f,
     };
//---------------------------------------------------------------------------
void vao_init()
    {
    glGenVertexArrays(4,vao);
    glGenBuffers(4,vbo);

    glBindVertexArray(vao[0]);
        glBindBuffer(GL_ARRAY_BUFFER,vbo[0]);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vao_pos),vao_pos,GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);

        glBindBuffer(GL_ARRAY_BUFFER,vbo[1]);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vao_col),vao_col,GL_STATIC_DRAW);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,0,0);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    }
//---------------------------------------------------------------------------
void vao_exit()
    {
    glDeleteVertexArrays(4,vao);
    glDeleteBuffers(4,vbo);
    }
//---------------------------------------------------------------------------
void vao_draw(GLuint mode)
    {
    void *p=NULL;
    glBindVertexArray(vao[0]);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glDrawArrays(mode,0,3);
    glBindVertexArray(0);
    }
//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------
//--- end. ---------------------------------------------------------------------
//------------------------------------------------------------------------------

Если вы не хотите использовать GLSL, вы должны вместо этого немного изменить код на что-то вроде этого:

//tetraeder
#define V_SIZ 12
#define I_SIZ 6
GLfloat tet_verts[V_SIZ] = { \
-0.5f, -1.0f, -0.86f, \
-0.5f, -1.0f, 0.86f, \
1.0f, -1.0f, 0.0f, \
0.0f, 1.0f, 0.0f};

GLushort tet_index = {3, 0, 1, 2, 3, 0};


void init_buffers() {
    glGenBuffersARB(1, &vertex_buf);
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertex_buf);
    glBufferDataARB(GL_ARRAY_BUFFER_ARB, V_SIZ*sizeof(GLfloat), tet_verts, GL_STATIC_DRAW_ARB); //upload data

    glGenBuffersARB(1, &index_buf);
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, index_buf);
    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, I_SIZ*sizeof(GLushort), tet_index, GL_STATIC_DRAW_ARB); //upload data

    return;
}

void draw_buffers() {
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertex_buf);
    glVertexPointer(3, GL_FLOAT, 0, 0); //3 is xyz, last 0 ("pointer") is offset in vertex-array

    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, index_buf);

    glEnableClientState(GL_VERTEX_ARRAY);

    //use indexing
    glDrawElements(GL_TRIANGLE_STRIP, I_SIZ, GL_UNSIGNED_SHORT, 0); //last 0 is offset in element-array

    return;
}

void deinit_buffers() {
    glDeleteBuffersARB(1, &vertex_buf);
    glDeleteBuffersARB(1, &index_buf);

    return;
}

PS. я рекомендую не использовать индексацию, как правило, намного медленнее на всех картах, которые я использую, но, конечно, это занимает больше памяти. Кроме того, индексация не очень хорошо реализована на драйверах, иногда глючит (даже на nVidia и, конечно, на ATI, если соблюдены правильные условия)

Другие вопросы по тегам