OpenGL : VBO를 지정하지 않고 VAO를 사용할 수 있습니까


12

모든 튜토리얼에서 VAO (Vertex Array Objects)에 대해 찾을 수 있으며 정점 속성을 구성하고 VBO (Vertex Buffer Object)를 바인딩하여 VAO를 사용하는 방법을 보여줍니다. 그러나 각 버퍼가 동일한 데이터 패턴 (정점, uv, 색상 등)을 사용하는 고정 셰이더와 함께 VBO 세트에 대해 구성되는 VAO를 만들고 싶습니다. 그래서 하나의 쉐이더를 사용하여 그릴 여러 VBO에 대해 하나의 VAO를 만들고 싶습니다.

나는 이것에 대한 데모를 찾을 수 없었기 때문에 시도해보기로 결정했다. 그러나 glDrawArray통화 가 작동하지 않고 충돌합니다 . VBO가 바인딩되지 않은 것 같습니다. 사용중인 코드는 다음과 같습니다.

표현:

/* Prepare vertex attributes */
glBindVertexArrayOES(vao);

/* Upload the buffer to the GPU */
glBindBuffer(GL_ARRAY_BUFFER, pool->next());
glBufferSubData(GL_ARRAY_BUFFER, 0, parts * buffer.stride() * 6, buffer.getBuffer());

/* Draw the triangles */
glDrawArrays(GL_TRIANGLES, 0, parts * 6);

glBindVertexArrayOES(0);

VAO 생성 :

glBindVertexArrayOES(vao);

glEnableVertexAttribArray(ls.position);
glVertexAttribPointer(ls.position, 2, GL_FLOAT, GL_FALSE, buffer.stride(), 0);

glEnableVertexAttribArray(ls.color);
glVertexAttribPointer(ls.color, 3, GL_FLOAT, GL_FALSE, buffer.stride(), GL_BUFFER_OFFSET(buffer.dataTypeSize * 2));

glBindVertexArrayOES(0);

속성 위치를 보유한 ls단순 struct위치 는 어디입니까 ?

렌더링 부분에서 glBindBufferglBindVertexArrayOES주변을 바꾸는 것도 효과가 없었습니다.

따라서 문제는 : 그렇게 할 수 있습니까? 아니면 각 버퍼에 대해 VAO를 만들어야합니까? 각 VBO에 대해 VAO를 만들어야하는 경우 VAO glBufferSubData와 함께 사용하여 VBO의 데이터를 업데이트 할 수 있습니까?

답변:


18

VAO는 GL_ELEMENT_ARRAY_BUFFER바인딩 상태를 제외하고 "glBindBuffer"상태를 포함하지 않습니다 . 당신이 이해 glBindBuffer(GL_ARRAY_BUFFER) 하지 못하는 것은 아무것도하지 않는 것 입니다. 글쎄, 렌더링에 관한 한 아무것도하지 않습니다. 시도 해봐; glDraw *를 호출하기 직전에 glBindBuffer(GL_ARRAY_BUFFER, 0); 렌더링은 잘 작동합니다.

glVertexAttribPointer작동 방식 은 호출 될 때glVertexAttribPointer GL_ARRAY_BUFFER 바인딩 된 것을 확인 하는 것 입니다 . 렌더링 시점이 아닙니다. 나중에 요 바로 그 순간에. 버퍼 객체가 무엇이든지 가져 와서 VAO 내에 캡슐화 된 또 다른 OpenGL 상태로 저장합니다.

일반적으로 두 가지 옵션이 있습니다. 그중 하나는 새로운 것이며 지금은 사용해서는 안됩니다.

첫 번째 옵션은 동일한 버텍스 형식 을 사용하는 모든 객체 (예 : 버퍼 객체 및 오프셋을 제외한 모든 객체)를 동일한 버퍼 객체에 배치하는 것입니다. 기본적으로 동일한 형식을 사용하는 모든 객체의 모든 정점이 포함 된 거대한 배열을 만듭니다.

렌더링 할 시점이되면 정점의 일부를 렌더링 할 수 있습니다. glDrawArrays렌더링하려면 다양한 요소 glDrawElements가 필요하며 동일한 방식으로 인덱스를 조정할 수 있습니다 . 또는 각 정점 에 오프셋이 추가되도록 정점glDrawElementsBaseVertex바이어스하는 데 사용할 수 있습니다 . 이 오프셋은 큰 배열에서 해당 정점 앞의 정점 수입니다.

다른 대안은 GL 4.3에 추가 된 비교적 새로운 형식 속성 분리 시스템 을 사용하는 것 입니다. 형식을 재설정하지 않고 버퍼를 변경할 수 있습니다. 따라서 단일 VAO를 바인딩 한 다음 필요에 따라 다른 버퍼로 대체하십시오 glBindVertexBuffer. ES 3.1에서도 사용할 수 있습니다.


1
NV GL4.3 드라이버는 이제 정식 버전입니다.
Maximus Minimus

glVertexAttribPointer의 작동 방식을 설명해 주셔서 감사합니다. 그것은 깨달았고 그것이 왜 그리고 어떻게 작동하는지 설명합니다.
Martijn Courteaux

5

VAO는 glVertexAttribPointer 상태를 저장합니다. VAO를 변경해도 현재 glBindBuffer에 영향을 미치지 않으며 glBindBuffer를 변경해도 VAO에 영향을 미치지 않습니다. 호출시 사용중인 버퍼를 기록하여 glVertexAttribPointer 호출 만 VAO에 영향을줍니다.

따라서 귀하의 질문에 대한 대답은 아니오입니다.

객체 수를 줄이려면 하나의 옵션을 사용하여 모든 메시 데이터를 하나의 큰 VBO에 넣고 'first'및 'count'인수를 사용하여 glDrawArrays 호출에서 메시 데이터가 VBO에있는 위치를 지정하십시오.


VAO의 인터넷상의 모든 기사는 VAO를 바인딩하면 VBO가 자동으로 바인딩된다는 것을 보여줍니다. 따라서 VAO는 glVertexAttribPointer 상태 와 glBindBuffer 상태를 모두 보유하는 구성이라고 생각합니다 . 그렇습니다. VAO가 바인딩 될 때 VBO를 바인딩하면 VAO가 변경됩니다. 나는 이것을 테스트했기 때문에 이것을 말하고 있으며 효과적으로 수행합니다. 이 정보는 어디에서 왔습니까?
Martijn Courteaux

2
@MartijnCourteaux : " VAO의 인터넷상의 모든 기사는 VAO를 바인딩하면 VBO가 자동으로 바인딩됨을 보여줍니다. "아니요, 그렇지 않습니다. 정점 사양 의 OpenGL Wiki 는 그렇지 않습니다. 실제로, 인터넷 에서 VAO를 바인딩하여 제외한 모든 glBindBuffer상태 가 변경 되었다는 단일 기사를 보여주세요 . GL_ELEMENT_ARRAY_BUFFER
Nicol Bolas

다른 답변은 glVertexAttribPointer 메서드가 어떻게 작동하는지 잘 설명했습니다. 그때 VBO 바운드를 사용합니다. 당신이 맞아요! 고마워요, 지금 이해합니다
Martijn Courteaux
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.