OpenGL 정점 캐시 객체
VBO를 사용하지 않으면glVertexPointer/glNormalPointer로 정점 데이터를 지정합니다. 이때 정점 데이터는 시스템 메모리에 저장되며, 매번 렌더링할 때마다 데이터를 시스템 메모리에서 메모리로 복사하여 적지 않은 시간을 소모합니다.
실제로 많은 복사는 불필요하다. 예를 들어 정적 대상의 정점 데이터는 변하지 않는다. 만약에 그것들을 메모리에 넣을 수 있다면 매번 렌더링할 때마다 복사 조작을 하지 않아도 적지 않은 시간을 절약할 수 있다.
1. 확장 확인
GL_ARB_vertex_buffer_object, OpenGL의 확장, 즉 VBO입니다.
이 확장을 사용하려면 먼저 현재 OpenGL 버전에서 이 확장이 지원되는지 확인해야 합니다.함수는 다음과 같습니다. 임의의 확장을 검사할 수 있으며, 파라미터는 확장자의 문자열입니다.
int CheckExtension(char *extName)
{
char *p = (char *)glGetString(GL_EXTENSIONS);
char *end;
int extNameLen = (int)strlen(extName);
end = p + strlen(p);
while (p < end) {
int n = (int)strcspn(p, " ");
if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
return TRUE;
}
p += (n + 1);
}
return FALSE;
}
그런 다음 CheckExtension을 호출하여 확장이 있는지 확인합니다. 확장자는 GL 입니다.ARB_vertex_buffer_object.확장이 존재하면, wglGetProcAddress를 호출해서 각각 필요한 확장 함수의 바늘을 가져옵니다.예를 들면 glGenBuffers, glBindBuffer입니다.
이 함수가 확장 라이브러리에 있다는 것을 나타내기 위해glGenBuffersaRB라는 이름을 사용하는 경우도 있습니다.구 버전의 OpenGL에서 흔히 볼 수 있듯이 새 버전의 OpenGL은glGenBuffers를 사용하여 이렇게 ARB를 제거하면 된다.
if(CheckExtension("GL_ARB_vertex_buffer_object"))
{
glGenBuffers = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
glBindBuffer = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
glBufferData = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
glBufferSubData = (PFNGLBUFFERSUBDATAARBPROC) wglGetProcAddress("glBufferSubDataARB");
glDeleteBuffers = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress("glDeleteBuffersARB");
}
else
{
cout<<"ERROR: GL_ARB_vertex_buffer_object extension was not found"<<endl;
return FALSE;
}
2. 정점 캐시 객체 작성
VBO를 설정하려면 다음 세 단계가 필요합니다.
세 함수의 소개는 다음과 같다.
void glGenBuffers(GLsizei n, GLuint* ids)
캐시 대상을 만들고 캐시 대상의 식별자를 되돌려줍니다.
void glBindBuffer(GLenum target, GLuint id)
캐시 대상을 만들면 사용할 수 있도록 캐시 대상을 연결해야 합니다.귀속, 즉 현재 어떤 캐시 대상을 사용할 것인지 지정합니다.
target - 캐시 대상이 저장할 데이터 형식입니다. 두 가지 값만 있습니다: GLARRAY_BUFFER, GLELEMENT_ARRAY_BUFFER.교점 좌표, 텍스쳐 좌표, 수직 벡터, 색상 배열 등과 같은 교점 관련 속성의 경우 GLARRAY_BUFFER;GL 을 사용하는 색인 배열ELEMENT_ARRAY_glDrawElements()에서 사용할 수 있도록 BUFFER
id - 캐시된 객체의 ID입니다.
void glBufferData(GLenum target, GLsizei size, const void* data, GLenum usage)
캐시 개체에 데이터를 복제합니다.
GL_STATIC_DRAW
GL_STATIC_READ
GL_STATIC_COPY
GL_DYNAMIC_DRAW
GL_DYNAMIC_READ
GL_DYNAMIC_COPY
GL_STREAM_DRAW
GL_STREAM_READ
GL_STREAM_COPY
이전 버전의 OpenGL은 ARB를 추가하여 GL처럼 변합니다.STATIC_DRAW_ARB의 형식입니다.
Draw는 VBO에만 유용합니다.Copy와 Read는 PBO(픽셀 캐시 객체) 및 FBO(프레임 캐시 객체)에만 의미가 있습니다.
VBO 메모리 관리자는 태그에 따라 적절한 저장 위치를 선택합니다.
void glBufferSubData(GLenum target, GLint offset, GLsizei size, void* data)
glBufferData () 와 마찬가지로 캐시 대상에 데이터를 복사하는 데 사용됩니다.이것은 오프셋으로 존재하는 캐시에 데이터를 복사할 수 있습니다.
void glDeleteBuffers(GLsizei n, const GLuint* ids)
하나 이상의 캐시 객체를 제거합니다.
3. 정점 캐시와 인덱스 캐시 사용
다음과 같은 데이터가 있습니다.
GLfloat vertexs[] = { 0.0f, 0.0f, 0.0f, 0.2f, 0.0f, 0.0f,
-0.2f, 0.0f, 0.0f, 0.0f, 0.2f, 0.0f,
0.0f, -0.2f, 0.0f, 0.0f, 0.0f, 0.2f,
0.0f, 0.0f, -0.2f};
GLubyte indexs[] = {0,1,2,3,4,5,6};
캐시 대상을 생성하고 데이터를 복사합니다.
GLuint vboVertexId;
GLuint vboIndexId;
glGenBuffers(1, &vboVertexId);
glBindBuffer(GL_ARRAY_BUFFER, vboVertexId);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs), vertexs, GL_STATIC_DRAW);
glGenBuffers(1, &vboIndexId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexs), indexs, GL_STATIC_DRAW);
그리고 사용할 때 아래 코드를 넣으세요.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_INDEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vboVertexId);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexId);
glIndexPointer(GL_UNSIGNED_BYTE, 0, 0);
... //
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_INDEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
캐시된 객체를 사용하는 방법은 다음과 같습니다.
//1.
glBegin(GL_POINTS);
glArrayElement(0);
glArrayElement(1);
glArrayElement(2);
glArrayElement(5);
glEnd();
//2.
glDrawElements(GL_POINTS, 7, GL_UNSIGNED_BYTE, 0);
//3.
glDrawArrays(GL_POINTS,0,7);
4. 서로 다른 유형의 데이터를 캐시 개체로 복사
glBufferSubData () 를 사용하면 몇 개의 데이터를 캐시 대상에 복사할 수 있습니다.예를 들어 다음과 같은 데이터가 있습니다.
GLfloat vertexs[] = {0.0f, 0.0f, 0.0f, 0.2f, 0.0f, 0.0f,
-0.2f, 0.0f, 0.0f, 0.0f, 0.2f, 0.0f,
0.0f, -0.2f, 0.0f, 0.0f, 0.0f, 0.2f,
0.0f, 0.0f, -0.2f};
GLfloat colors[] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f,
0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f};
현재, 두 개의 그룹을 같은 캐시 대상에 저장하려면, 정점 그룹은 앞에 있고, 색 그룹은 뒤에 있습니다.코드는 다음과 같습니다.
glGenBuffers(1, &vboVertexId);
glBindBuffer(GL_ARRAY_BUFFER, vboVertexId);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs)+sizeof(colors), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertexs) , vertexs); // ,
glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertexs), sizeof(colors), colors);
캐시 대상을 만든 후 glVertexPointer와 glColorPointer로 해당하는 포인터 위치를 지정해야 합니다.그러나 glColorPointer의 마지막 매개변수 때문에 포인터 유형이어야 합니다.다음 코드를 보십시오.glColorPointer의 마지막 매개 변수는 편향량으로 색 그룹의 위치를 표시합니다.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_INDEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vboVertexId);
glVertexPointer(3, GL_FLOAT, 0, 0);
glColorPointer(3,GL_FLOAT,0,(void*)sizeof(vertexs)); //
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexId);
glIndexPointer(GL_UNSIGNED_BYTE, 0, 0);
glDrawArrays(GL_POINTS,0,7);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_INDEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
5. 캐시된 객체 수정
VBO는 목록을 표시하는 것보다 캐시 객체의 데이터를 읽고 수정할 수 있다는 장점이 큽니다.가장 간단한 방법은 VBO에 데이터가 있지만 glBuffer Data () 와glBuffer SubData () 를 다시 복사하는 것이다. 이 경우 프로그램은 클라이언트 (CPU) 와 장치 (GPU) 두 개의 데이터를 저장해야 한다.
다른 방법은 캐시 대상을 클라이언트에 비추고 바늘을 통해 데이터를 수정하는 것이다.
void* glMapBuffer(GLenum target, GLenum access)
현재 연결된 캐시 대상을 클라이언트에 비추고glMapBuffer는 캐시 대상을 가리키는 바늘을 되돌려줍니다.OpenGL이 지원되지 않으면 NULL로 돌아갑니다.
만약 OpenGL이 캐시 대상을 조작하고 있다면, 이 함수는 OpenGL이 처리될 때까지 성공하지 못할 것입니다.기다림을 피하기 위해 glBindBuffer(GL ARRAY BUFFER, 0)를 사용하여 캐시 객체의 적용을 중지하고 glMapBuffer를 호출할 수 있습니다.
GLboolean glUnmapBuffer(GLenum target)
데이터를 수정한 후에 데이터를 장치 측에 반영합니다.
사용 방법은 다음과 같은 코드를 보십시오.
glBindBuffer(GL_ARRAY_BUFFER, vboVertexId);
GLfloat* ptr = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
if(ptr)
{
ptr[0] = 0.2f; ptr[1] = 0.2f; ptr[2] = 0.2f;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
참고 자료
[1] GL 정보ARB_vertex_buffer_object 확장
[2] OpenGL Vertex Buffer Object (VBO)
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Common Lisp에서 GPU 벡터 기반 글꼴 렌더링그때 조금만 쓴 문자열 드로잉 라이브러리의 소개입니다. 브라우저의 렌더링 엔진을 만드는데 있어서, 취급하기 쉬운 묘화 백엔드가 필요했다. Gecko는 Cairo를 사용하는 것처럼 보였습니다 (과거의 이야기?) 그래서...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.