2014-10-04 13 views
0

를 사용하는 DisplayList가에서 변환 나는 다음과 같은 전역 변수가 : 내 glutDisplayFunc에서, 내가 전화는 OpenGL - VBO

glEnableClientState(GL_VERTEX_ARRAY); // vertex array 
glVertexPointer(3, GL_FLOAT, 0, &vertexCoords[0]); 

modelList = glGenLists(1); // generate display list 
glNewList(modelList, GL_COMPILE); 
for (unsigned int i = 0; i < faces.size(); i++) { 
    glBegin(GL_TRIANGLE_STRIP); 
    for (vector<unsigned int>::iterator it = faces[i].begin(); 
      it != faces[i].end(); it++) 
     glArrayElement(*it - 1); 
    glEnd(); 
} 
glEndList(); // End display list. 

:

내 초기화에서

vector<vector<unsigned int> > faces; 
vector<float> vertexCoords; 
unsigned int modelList; 

을이 코드가

glCallList(modelList); // Execute display list. 

DisplayList 대신 VBO를 사용하고 싶습니다. 이 코드를 어떻게 변환 할 수 있습니까? 미리 감사드립니다.

답변

1

운이 좋다. 프로그램의 구조는 이미 모든 것을 갖추고 있습니다. 우리는 짜증나는 1 기반 인덱싱을 해결할 수도 있습니다.

첫째는 VBO 만들기 :

GLuint vbo_id; 
GLuint eabo_id; /* EIB = Element Array Buffer */ 
size_t eabo_n_elements; 

void make_vbo() 
{ 
    GLuint genbuf_ids; 
    glGenBuffers(2, genbuf_ids); 

    vbo_id = genbuf_ids[0]; 
    eabo_id = genbuf_ids[1]; 

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id); 

데이터에 대한 공간을 할당 사본을 정점 데이터 버퍼로. 여러분의 정점 요소 인덱스 배열이 1만큼 이동 되었기 때문에 하나의 정점을 더 할당하고 오프셋을 사용하여 그 정점에 데이터를 복사합니다 (GL_ARB_draw_elements_base_vertex 확장을 사용할 수도 있지만이 방법으로 보여 드리겠습니다 :

glBufferData(
     GL_ARRAY_BUFFER, 
     (vertexCoords.size() + 3)*sizeof(vertexCoords[0]), 
     NULL, 
     GL_STATIC_DRAW); 

    glBufferSubData(
     GL_ARRAY_BUFFER, 
     sizeof(vertexCoords[0])*3, /* offset by 1 vertex */ 
     (vertexCoords.size())*sizeof(vertexCoords[0], 
     &vertexCoords[0]); 

    glBindBuffer(GL_ARRAY_BUFFER, 0); 

요소 배열 버퍼와 동일하지만 두 개의 벡터를 서로 쌓아서 ... 매우 효율적이지는 않습니다. 먼저이 버퍼를 풀어 보겠습니다.하지만 다시 버퍼를 할당하십시오. 각 서브 그래프는 다른 길이를 가질 수 있기 때문에 (특정 프리미티브 드로잉 모드에 사용되는 경우 모두 동일한 크기 여야하지만) 먼저 C++ 11 기능 을 사용하여 일부 요소를 저장하는 요소의 총 개수를 결정합니다. 그래서 iterator를 사용할 수 있도록), 나중에 우리는 num을 알아야한다. BER 그들을 그리는 :

eabo_n_elements = 0; 
    for(auto i = faces.begin(); i != faces.end(); i++) { 
     eabo_n_elements += i.size(); 
    } 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eabo_id); 
    glBufferData(
     GL_ELEMENT_ARRAY_BUFFER, 
     sizeof(faces[0][0]) * eabo_n_elements, 
     NULL, 
     GL_STATIC_DRAW); 

를 펴고 복사 얼굴 데이터를 EAB

size_t offset = 0; 
    for(auto i = faces.begin(); i != faces.end(); i++) { 
     size_t const len = i.size() * sizeof(i[0]); 
     glBufferSubData(
      GL_ELEMENT_ARRAY_BUFFER, 
      offset, 
      len, 
      &i[0]); 
     offset += len; 
    } 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
} 

에 이제 우리는 그것을 그릴 수 있습니다. 기술적으로 우리는 VAO (OpenGL-4를 가지고 있어야 함)를 사용할 수 있지만, 그렇게 해 둡시다. VBO 그리기는 클라이언트 측 정점 배열에서 그리는 것과 매우 유사합니다. 이제 고정 기능 파이프 라인을 사용하고 있음을 나타내는 glVertexPointer을 사용했습니다. 우리는 그것을 사용할 수 있습니다. 그러나 VBO는 OpenGL-3에서만 OpenGL 핵심 기능이되었습니다 (이전에는 확장 기능으로 오랫동안 사용할 수있었습니다). 따라서 glVertexAttribPointer과 일치하는 셰이더가 추가되었습니다. 전환을 가능한 한 작게 유지하려면 glVertexPointer의 사용을 재활용하십시오. 주요 차이점은 우리가 glVertexPointer 호출하기 전에 VBO 바인딩 데이터 파라미터에 오프셋 integer-cast-to-a-pointer (which actually may invoke UB for anything other than 0) 전달하는 것이있다 :

void draw_vbo() 
{ 
    glEnableClientState(GL_VERTEX_ARRAY); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id); 
    glVertexPointer(3, GL_FLOAT, 0, (void*)0); 

VBO는 정점 어레이 액세스에 "연결"되어 일단을, 우리는 바인딩을 해제 할 수있다 . 데이터는 여전히 VBO에서 가져올 수 있습니다.

glBindBuffer(GL_ARRAY_BUFFER, 0); 

마지막으로 그리기 호출을합니다. 버텍스 데이터를 VBO로 복사 할 때 1 요소 오프셋을 적용했음을 기억하십시오. 따라서 우리는 단지면 정점 요소 인덱스를 통과합니다. VBO : Bind와 같은 패턴으로 포인터에 대한 정수 오프셋을 캐스팅하여 glDrawElements에 전달합니다.

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eabo_id); 
    glDrawElements(GL_TRIANGLE_STRIP, eabo_n_elements, GL_UNSIGNED_INT, (void*)0); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
}