2011-10-19 5 views
5

저는 OpenGL 프로젝트의 성능을 높이고 고정 기능 렌더링보다 고급 기능을 배우기 위해 VBO를 사용하도록 가르쳐 왔습니다. 그러나 나는보기 흉하지 않은 튜토리얼의 길을 많이 찾지 못했다. 내가 지금까지 찾은 최고의 것들은 Songho's tutorials과 그 것들이 OpenGL.org에있다. 그러나 나는 그것이 무엇인지 정확하게 말할 수는 없지만 어떤 일이 벌어지고 있는지 완전히 이해할 수있는 배경 지식이 빠져있는 것 같다. , 몇 가지 매개 변수의 사용을 저장합니다.VBO를 올바르게 사용하는 법을 배웁니다.

어쨌든 필자는 위조 된 코드를 만들었지 만 적어도 충돌은 발생하지 않지만 기괴한 결과를 초래합니다. 렌더링하고자하는 것은 고정 된 함수를 사용하여 렌더링되며, 갈색과 배경 회색으로되어 있지만 모든 OpenGL 스크린 샷은 마젠타 색을 선호하는 색으로 사용하는 것 같습니다 (아마도 창에 SFML을 사용했기 때문일 수 있습니다).

Target image

내가 무엇을 얻을하지만, 이것이다 : 나는 손실에있어

Actual image

. 여기에 버퍼 오브젝트를 설정하기위한 첫번째, 내가 사용하는 관련 코드입니다 (나는 4~8메가바이트을 할당 this guy's 권고에 따라 많은 양의 메모리를 할당) :

GLuint WorldBuffer; 
GLuint IndexBuffer; 

... 

glGenBuffers(1, &WorldBuffer); 
glBindBuffer(GL_ARRAY_BUFFER, WorldBuffer); 
int SizeInBytes = 1024 * 2048; 
glBufferData(GL_ARRAY_BUFFER, SizeInBytes, NULL, GL_STATIC_DRAW); 

glGenBuffers(1, &IndexBuffer); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer); 
SizeInBytes = 1024 * 2048; 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, SizeInBytes, NULL, GL_STATIC_DRAW); 

그런 다음 버퍼로 데이터를 업로드합니다. CreateVertexArray()는 전달 된 위치의 벡터를 정점 데이터로 채 웁니다. 각 정점은 위치에 대해 3 개의 부동 소수점을 제공하고 일반적인 경우에는 3 개의 부동 소수점을 제공합니다 (다양한 자습서에 대해 가장 혼란스러운 것 중 하나는 실제 형식을 저장하고 전송해야하는 형식입니다 에서 정점 데이터, 이것은 괜찮은 근사처럼 보였다) : 그 후

std::vector<float>* VertArray = new std::vector<float>; 
pWorld->CreateVertexArray(VertArray); 
unsigned short Indice = 0; 
for (int i = 0; i < VertArray->size(); ++i) 
{ 
    std::cout << (*VertArray)[i] << std::endl; 
    glBufferSubData(GL_ARRAY_BUFFER, i * sizeof(float), sizeof(float), &((*VertArray)[i])); 
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, i * sizeof(unsigned short), sizeof(unsigned short), &(Indice)); 
    ++Indice; 
} 
delete VertArray; 
Indice -= 1; 

, 게임 루프에서, 나는이 코드를 사용합니다

glBindBuffer(GL_ARRAY_BUFFER, WorldBuffer);   
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);  

    glEnableClientState(GL_VERTEX_ARRAY);   
    glVertexPointer(3, GL_FLOAT, 0, 0); 
    glNormalPointer(GL_FLOAT, 0, 0); 

    glDrawElements(GL_TRIANGLES, Indice, GL_UNSIGNED_SHORT, 0); 

    glDisableClientState(GL_VERTEX_ARRAY); 

    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

내가 완전히 정직거야 - 아니에요을 물론 나는 glVertexPointer()glNormalPointer()의 세 번째 매개 변수가 무엇인지 이해해야합니다 (스트라이드는 by 그러나 Songho은 값 사이에 0 바이트의 오프셋을 사용합니다 (what?) 또는 둘 중 마지막 매개 변수는 무엇입니까? 초기 값은 0이라고합니다. 하지만 그것은 포인터가되어야합니다. 배열의 첫 번째 좌표/표준 값을 얻기 위해 널 포인터를 전달하는 것은 이상하게 보입니다. This guyBUFFER_OFFSET(0)BUFFER_OFFSET(12)을 사용합니다. 그러나이를 시도 할 때 BUFFER_OFFSET()이 정의되지 않았다고 말합니다.

플러스, glDrawElements()의 마지막 매개 변수는 주소가 있어야하지만, 다시 배경을 제외하고 내가 대신 0의 &IndexBuffer를 사용하는 경우, Songho 0의 주소를 사용하여, 나는 아무것도 전혀 제공하지 않고 빈 화면을 얻을 .

나를 계몽 할 수 있습니까? 아니면 적어도이 사실을 알 수 있도록 도와 줄 수 있습니까? 감사!

답변

7

초기 값은 0이라고합니다. 하지만 그것은 포인터가되어야합니다.

문맥 (OpenGL을 의미하지는 않음)이 중요합니다. gl * Pointer 함수 중 하나가 GL_ARRAY_BUFFER에 바인드 된 버퍼 객체없이 호출되면 클라이언트 프로세스 주소 공간에 대한 포인터입니다. 버퍼 객체가 GL_ARRAY_BUFFER에 바인드 된 경우 현재 바인드 된 버퍼 객체에 대한 오프셋입니다 (가상 포트 공간을 형성하는 BO가 gl * Pointer의 매개 변수가 해당 서버 측 주소 공간에 대한 포인터가 될 수 있습니다).

이제 RAII 패턴에 대해 알아의이 코드

std::vector<float>* VertArray = new std::vector<float>; 

당신은 정말 STL 컨테이너를 혼합하지해야하며 new 살펴보기로하자.

pWorld->CreateVertexArray(VertArray); 

나중에 VertexArray를 삭제하여 매달린 포인터를 남기므로 문제가 발생합니다. 안좋다.

unsigned short Indice = 0; 
for (int i = 0; i < VertArray->size(); ++i) 
{ 
    std::cout << (*VertArray)[i] << std::endl; 
    glBufferSubData(GL_ARRAY_BUFFER, i * sizeof(float), sizeof(float), &((*VertArray)[i])); 

개별 데이터 요소가 아닌 glBufferSubData와 함께 대량의 데이터 일괄 처리를 제출해야합니다.

glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, i * sizeof(unsigned short), sizeof(unsigned short), &(Indice)); 

GL_ELEMENT_ARRAY_BUFFER에 색인 만 증가시켜 정점을 열거합니다. 왜? glDrawElements의 glDrawArrays 인스턴스를 사용하는 추가 작업없이이 작업을 수행 할 수 있습니다.

++Indice; 
} 
delete VertArray; 

당신은 VertArray를 삭제하므로 매달린 포인터가 유지됩니다.

Indice -= 1; 

왜 루프 카운터를 사용하지 않았습니까? i?

어떻게 해결할 수 있습니까? 이렇게 :

std::vector<float> VertexArray; 
pWorld->LoadVertexArray(VertexArray); // World::LoadVertexArray(std::vector<float> &); 

glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*VertexArray->size(), &VertexArray[0]); 

그리고 glDrawArrays; 물론 정점을 열거하지 않고면 → 정점 인덱스 목록이있는 경우에는 glDrawElements를 사용해야합니다. 방금이 게시물을보고 마지막 매개 변수의 오프셋 (offset)에 대해 알고 들어

+0

비평과 설명에 감사드립니다! 이번에는 더 많은 성공과 이해로 코드를 수정 해 드리겠습니다. – GarrickW

4

각 정점에 glBufferSubData을 호출하지 마십시오. 그것은 VBO의 요점을 놓친다. 버텍스 데이터의 커다란 버퍼를 생성 한 다음, 한 번에 OpenGL에 전달해야합니다. 그 포인터 VBO 데이터를 기준으로 VBOs 사용시

http://www.opengl.org/sdk/docs/man/xhtml/glVertexPointer.xml 읽기. 그래서 보통 0 또는 작은 오프셋 값입니다.

stride = 0은 데이터가 단단히 채워지고 OpenGL이 다른 매개 변수로 stride을 계산할 수 있음을 의미합니다.

나는 일반적으로 다음과 같이 VBO를 사용

struct Vertex 
{ 
    vec3f position; 
    vec3f normal; 
}; 

Vertex[size] data; 

... 

glBufferData(GL_ARRAY_BUFFER, size*sizeof(Vertex), data, GL_STATIC_DRAW); 

... 

glVertexPointer(3,GL_FLOAT,sizeof(Vertex),offsetof(Vertex,position)); 
glNormalPointer(3,GL_FLOAT,sizeof(Vertex),offsetof(Vertex,normal)); 

그냥 정점 데이터의 하나의 덩어리를 전달합니다. 매크로를 사용하여 데이터 포장 방법을 설명하려면 gl*Pointer을 사용하십시오.

+0

그래서 스트라이드가 0이 나는 ​​경우, 다음, 각각 같은 배열에서 서로 옆에 좌표 포장 한 의미 나는 올바르게 이해한다. std :: vector 을 Vertex []처럼 쉽게 사용할 수 있습니까? – GarrickW

+0

당신은 할 수 있어야한다 @GarrickW에, 예 : '표준 : : 벡터 < T > a 및' '.....' 'glBufferData (GL_ARRAY_BUFFER,는 sizeof (T) * a.size(), A [0 ], GL_STATIC_DRAW); ' – zeboidlund

관련 문제