태그 : opengl

OpenGL 버텍스 버퍼 개체(Vertex Buffer Object)의 버퍼 설정을 위한 Tip & Tricks

이 글에서는 캐릭터와 같이 에니메이션 되는 모델을 위해서 버텍스 버퍼 개체를 사용할 때 버텍스 컴포넌트 별로 버텍스 버퍼 개체를 따로 생성함으로써 효율적인 버텍스 버퍼 개체를 사용하고 렌더링 속도도 향상 시킬 수 있는 방법에 대해서 소개한다.

우선 VBO를 사용하기 위해서 VBO를 선언한다.

struct
model
{
    ...
    GLuint vbuf; // buffer to store vertex positions
    GLuint nbuf; // buffer to store vertex normals.
    GLuint tbuf; // buffer to store texture uvs.
   
    size_t vbufsize;
    ...
};

다음으로 버퍼 개체를 만든다.

  glGenBuffersARB(1, &vbuf);
  glGenBuffersARB(1, &tbuf);
  
앞에서 버퍼 개체로 vbuf, nbuf, tbuf 세개의 개체를 정의했는데 실제로는 vbuf와 tbuf 두 개의 버퍼 개체만들 만든 이유는 무엇일까? 그 이유는 normal 값은 vbuf에 같이 저장할 수 있기 때문이다.

다음으로 생성한 tbuf에 텍스쳐 uv 값을 보낸다.

  glBindBufferARB(GL_ARRAY_BUFFER_ARB, tbuf);
  glBufferDataARB(GL_ARRAY_BUFFER_ARB, 2*size, texcoords, GL_STATIC_DRAW_ARB);
  
캐릭터와 같은 모델의 경우에는 텍스쳐 uv를 위한 tbuf는 모델을 읽어 들일 때 미리 버텍스 버퍼 개체에 텍스쳐의 uv 값을 저장했지만 vbuf와 nbuf는 이렇게 하지 않는다. 그 이유는 에니메이션 되는 모델의 경우 매 프레임마다 버텍스의 좌표와 노말값이 바뀌기 때문이다. (버텍스의 좌표가 바뀌므로 노말 역시 같이 변경이 된다) 그렇기 때문에 매 프레임마다 vbuf에는 변경된 버텍스를 전송해 주지만 텍스쳐 좌표의 경우 uv 애니메이션을 하지 않는다면 한번만 설정해 주면 된다. 이렇게 분리하면 보내는 데이터의 양을 줄일 수 있으므로 렌더링시 속도 향상에도 도움이 된다.

  glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbuf);
  glBufferDataARB(GL_ARRAY_BUFFER_ARB, 2*vbufsize, NULL, GL_STREAM_DRAW_ARB);
  vertices = (Vec3D*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY); 
  ...
  for (size_t i=0, i<numvertices; i++)
  {
      //버텍스 좌표 변경
      vertices[i] = v;                    // vertex position
      vertices[i+numvertices] = n; // vertex normal
  }
    
  ...
    
  glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
   
앞에서 설명한 바와 같이 텍스쳐 좌표는 갱신을 하지 않는다.  
   
렌더링은 다음과 같이 한다.

  glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbuf);

  glVertexPointer(3, GL_FLOAT, 0, 0);
  glNormalPointer(GL_FLOAT, 0, GL_BUFFER_OFFSET(vbufsize));
   
  glBindBufferARB(GL_ARRAY_BUFFER_ARB, tbuf);
  glTexCoordPointer(2, GL_FLOAT, 0, 0);

노말값은 버퍼에 버텍스의 위치값을 저장한 다음 저장했으므로 glNormalPointer 호출시 vbufsieze 만큼 오프셋을 설정한 것에 주의한다.

  glDrawRangeElements(GL_TRIANGLES, vertexStart, vertexEnd, indexCount, GL_UNSIGNED_SHORT, indices + indexStart);
 
마지막으로 glDrawRangeElements 함수를 호출해서 렌더링한다.


참고 자료
GPU Gems 2, Optimizing Resource Management with Multi-Streaming, Kurt Pelzer and Oliver Hoeller(Piranha Bytes)

by kimsama | 2007/11/05 22:22 | Development | 트랙백 | 덧글(2)

◀ 이전 페이지다음 페이지 ▶