정점 배열 객체는 무엇입니까?


114

저는 오늘이 튜토리얼에서 OpenGL을 배우기 시작했습니다 : http://openglbook.com/the-book/
저는 삼각형을 그리는 2 장에 도달했고 VAO를 제외한 모든 것을 이해합니다 (이 두문자어는 괜찮습니까?). 튜토리얼에는 다음 코드가 있습니다.

glGenVertexArrays(1, &VaoId);
glBindVertexArray(VaoId);

나는 코드가 필요하다는 것을 이해하지만 그것이 무엇을하는지 전혀 모른다. 이 시점 이후에는 VaoId를 사용하지 않지만 (파괴 제외) 코드가 없으면 작동하지 않습니다. 바인딩이 필요하기 때문이라고 생각하지만 그 이유는 모르겠습니다. 이 정확한 코드가 모든 OpenGL 프로그램의 일부 여야합니까? 이 튜토리얼에서는 VAO를 다음과 같이 설명합니다.

Vertex Array Object (또는 VAO)는 Vertex Buffer Object (또는 VBO)에 정점 속성이 저장되는 방법을 설명하는 객체입니다. 이것은 VAO가 정점 데이터를 저장하는 실제 객체가 아니라 정점 데이터의 설명 자임을 의미합니다. 정점 속성은 glVertexAttribPointer 함수와 두 자매 함수 인 glVertexAttribIPointer 및 glVertexAttribLPointer로 설명 할 수 있습니다. 첫 번째는 아래에서 살펴볼 것입니다.

VAO가 정점 속성을 어떻게 설명하는지 이해하지 못합니다. 나는 그것들을 어떤 식으로도 설명하지 않았습니다. glVertexAttribPointer에서 정보를 얻습니까? 나는 이것이 틀림 없다고 생각한다. VAO는 단순히 glVertexAttribPointer의 정보에 대한 대상입니까?

참고로 내가 따르는 튜토리얼이 허용됩니까? 주의해야 할 사항이나 따라야 할 더 나은 튜토리얼이 있습니까?

답변:


100

"Vertex Array Object"는 OpenGL ARB Subcommittee for Silly Names에서 제공합니다.

기하학 객체로 생각하십시오. (오래된 SGI 수행자 프로그래머로서 저는 그것들을 지오 셋이라고 부릅니다.) 객체의 인스턴스 변수 / 멤버는 정점 포인터, 일반 포인터, 색상 포인터, attrib N 포인터, ...

VAO가 처음 바인딩되면 다음을 호출하여 이러한 멤버를 할당합니다.

glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer...;
glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer...;

등등. 활성화 된 속성과 제공하는 포인터는 VAO에 저장됩니다.

그 후 VAO를 다시 바인딩하면 모든 속성과 포인터도 현재 상태가됩니다. 따라서 한 번의 glBindVertexArray호출은 이전에 모든 속성을 설정하는 데 필요한 모든 코드와 동일합니다. 자체 구조체 나 객체를 만들지 않고도 함수 나 메서드간에 지오메트리를 전달할 때 편리합니다.

(한 번 설정, 다중 사용은 VAO를 사용하는 가장 쉬운 방법이지만 바인딩하고 더 많은 활성화 / 포인터 호출을 수행하여 속성을 변경할 수도 있습니다. VAO는 상수가 아닙니다.)

Patrick의 질문에 대한 추가 정보 :

새로 생성 된 VAO의 기본값은 비어 있다는 것입니다 (AFAIK). 지오메트리가 전혀없고 꼭지점이 아니므로 그리려고하면 OpenGL 오류가 발생합니다. 이것은 "모든 것을 False / NULL / 0으로 초기화"에서와 같이 합리적으로 정상입니다.

glEnableClientState설정 을 할 때만 필요 합니다. VAO는 각 포인터에 대한 활성화 / 비활성화 상태를 기억합니다.

예 VAO는 저장됩니다 glEnableVertexAttribArrayglVertexAttrib. 이전 vertex, normal, color, ... 배열은 속성 배열과 동일하며 vertex == # 0 등등입니다.


62
""Vertex Array Object "는 OpenGL ARB Subcommittee for Silly Names에서 가져 왔습니다." 예, 정점 배열 바인딩 을 저장 하는 객체에 대한 그런 어리석은 이름입니다 .
Nicol Bolas 2012 년

2
또한, 관련된 모든에서 VAOs 있습니다glVertexAttribPointer
패트릭

2
코어 프로필을 사용하는 사람들을위한 일반 정점 속성 사용에 대한 정보를 추가하십시오.
Oskar

8
@NicolBolas 더 나은 이름은 VertexArrayMacro또는 비슷한 것입니다.
bobobobo

7
@NicolBolas "Vertex Array Object"는 끔찍한 이름입니다. 데이터를 속성바인딩하는 것 입니다. 이름에서 알 수 있듯이 정점 배열에 관한 것이 아닙니다. 이름에 바인딩이나 속성에 대한 참조가 없으며 "정점 배열"자체가 분리 된 개념이기 때문에 이해가 더 어려워집니다. IMHO, "(Vertex) Attributes Binding Object"는 이해하기 더 쉽습니다. Geometry Object조차 더 낫습니다. 나는 그것을 좋아하지 않지만 적어도 과부하는 아닙니다.
AkiRoss

8

Vertex Array Objects는 워드 프로세싱 프로그램 등의 매크로 와 같습니다. 여기에 좋은 설명이 있습니다 .

매크로는 단지 기억 당신이 호출 할 때 등의 활성화이 속성 바인드 그 버퍼로 당신이 한 행동을 glBindVertexArray( yourVAOId )단순히, 다시 재생 하는 속성 포인터 바인딩과 바인딩을 버퍼.

따라서 다음 그리기 호출은 VAO에 의해 바인딩 된 모든 것을 사용합니다.

VAO는 정점 데이터를 저장하지 않습니다 . 아니요. 정점 데이터는 정점 버퍼 또는 클라이언트 메모리 배열에 저장됩니다.


19
-1 : 매크로와 같지 않습니다. 그렇다면 새 VAO를 바인딩해도 이전 VAO에서 활성화 한 정점 배열이 비활성화되지 않습니다. 단, 새 VAO가 해당 배열 을 명시 적으로 비활성화 한 경우가 아니면 모든 OpenGL 객체 와 마찬가지로 VAO는 명령이 아닌 state를 보유 합니다. 명령은 단순히 상태 를 변경 하지만 개체에는 기본 상태가 설정되어 있습니다. 그렇기 때문에 새로 생성 된 VAO를 바인딩하면 항상 모든 속성이 비활성화됩니다.
Nicol Bolas 2013

6

저는 항상 VAO를 OpenGL에서 사용하는 데이터 버퍼의 배열로 생각합니다. 최신 OpenGL을 사용하여 VAO 및 Vertex Buffer Objects를 만듭니다.

여기에 이미지 설명 입력

//vaoB is a buffer
glGenVertexArrays(1, vaoB); //creates one VAO
glBindVertexArray(vao.get(0));
glGenBuffers(vbo.length, vbo, 0); //vbo is a buffer
glBindVertexArray(vao.get(1));
glGenBuffers(vbo1.length, vbo1, 0); //vbo1 is a buffer
glBindVertexArray(vao.get(2));
glGenBuffers(vbo2.length, vbo2, 0); //vbo2 is a buffer

다음 단계는 데이터를 버퍼에 바인딩하는 것입니다.

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER,vertBuf.limit()*4, vertBuf, GL_STATIC_DRAW); //vertf buf is a floatbuffer of vertices

이 시점에서 OpenGL은 다음을 확인합니다.

여기에 이미지 설명 입력

이제 glVertexAttribPointer를 사용하여 버퍼의 데이터가 나타내는 내용을 OpenGL에 알릴 수 있습니다.

glBindBuffer(GL_ARRAY_BUFFER, 0); //bind VBO at 0
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); //each vertex has 3 components of size GL_FLOAT with 0 stride (space) between them and the first component starts at 0 (start of data)

여기에 이미지 설명 입력

OpenGL은 이제 버퍼에 데이터를 가지고 있으며 데이터가 정점으로 구성되는 방식을 알고 있습니다. 텍스처 좌표 등에 동일한 프로세스를 적용 할 수 있지만 텍스처 좌표에는 두 가지 값이 있습니다.

glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER,coordBuf.limit()*4, coordBuf, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

다음으로 텍스처를 바인딩하고 배열을 그릴 수 있습니다. Vert 및 Frag 셰이더를 만들고 컴파일하여 프로그램에 연결합니다 (여기에 포함되지 않음).

glActiveTexture(textureID); //bind our texture
glBindTexture(GL_TEXTURE_2D, textureID);
glDrawArrays(GL_TRIANGLES,0,6); //in this case 6 indices are used for two triangles forming a square

5

VAO는 OpenGL 파이프 라인의 정점 가져 오기 단계를 나타내는 객체이며 정점 셰이더에 입력을 제공하는 데 사용됩니다.

다음과 같이 정점 배열 객체를 만들 수 있습니다.

GLuint vao;
glCreateVertexArrays(1, &vao);
glBindVertexArray(vao);

먼저 간단한 예를 들어 보겠습니다. 셰이더 코드에서 이러한 입력 매개 변수를 고려하십시오.

layout (location = 0) in vec4 offset; // input vertex attribute

이 속성을 채우려면 다음을 사용할 수 있습니다.

glVertexAttrib4fv(0, attrib); // updates the value of input attribute 0

정점 배열 객체는 이러한 정적 속성 값을 저장하지만 더 많은 작업을 수행 할 수 있습니다.

정점 배열 객체를 만든 후 상태 채우기를 시작할 수 있습니다. OpenGL에 우리가 제공하는 버퍼 객체에 저장된 데이터를 사용하여 자동으로 채우도록 요청할 것입니다. 각 정점 속성은 여러 정점 버퍼 바인딩 중 하나에 바인딩 된 버퍼에서 데이터를 가져옵니다. 이를 위해 우리는 glVertexArrayAttribBinding(GLuint vao, GLuint attribindex, GLuint bindingindex). 또한이 glVertexArrayVertexBuffer()함수를 사용하여 버퍼를 정점 버퍼 바인딩 중 하나에 바인딩합니다. 이 glVertexArrayAttribFormat()함수를 사용하여 데이터의 레이아웃과 형식을 설명하고 마지막으로를 호출하여 속성의 자동 채우기를 활성화 glEnableVertexAttribArray()합니다.

정점 속성을 사용하는 경우, OpenGL은 당신이 제공 한 형식과 위치 정보를 기반으로 버텍스 쉐이더에 데이터를 공급합니다 glVertexArrayVertexBuffer()glVertexArrayAttribFormat(). 속성이 비활성화되면 정점 셰이더에를 호출하여 제공하는 정적 정보가 제공됩니다 glVertexAttrib*().

// First, bind a vertex buffer to the VAO
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vmath::vec4));

// Now, describe the data to OpenGL, tell it where it is, and turn on automatic
// vertex fetching for the specified attribute
glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, GL_FALSE, 0);

glEnableVertexArrayAttrib(vao, 0);

그리고 셰이더에서 코드

layout (location = 0) in vec4 position;

결국 당신은에 전화해야 glDeleteVertexArrays(1, &vao)합니다.


OpenGL SuperBible 을 읽고 더 잘 이해할 수 있습니다 .


3
사람들이 DSA 스타일 OpenGL의 사용을 홍보하는 것을 보는 것이 좋습니다.
Nicol Bolas 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.