glVertexAttribPointer 설명


94

내가 이것을 올바르게 이해하고 있는지 확인하고 싶습니다 (SO Chat에서 묻 겠지만 거기에는 죽었습니다!) :

우리는 정점 배열을 가지고 있으며,이를 바인딩하여 "현재"로 만들고
버퍼를 얻었습니다.이 버퍼를 Target에 바인딩
한 다음 해당 대상 glBufferData 에 바인딩 된 모든 것을 기본적으로 채우는 대상을 채 웁니다. 즉, 버퍼
그런 다음 glVertexAttribPointer데이터가 배치되는 방식을 설명하는 호출 을 호출 합니다. 데이터는 바인딩 된 데이터이며이 GL_ARRAY_BUFFER 설명자는 원래 Vertex Array에 저장됩니다.

(1) 내 이해가 정확합니까? 문서는 어떻게 모든의 상관 관계에 대해 조금 스파 스입니다.

(2) 어떤 종류의 기본 정점 배열이 있습니까? 잊고 / 생략 glGenVertexArrays했고 glBindVertexArray내 프로그램이 그것 없이는 잘 작동했기 때문입니다.


편집 : 나는 단계를 놓쳤다 ... glEnableVertexAttribArray.

(3) Vertex Attrib glVertexAttribPointerglEnableVertexAttribArray해당 시점에 Vertex Array에 연결되어 있습니까? 그러면 현재 어떤 Vertex Array가 바인딩되어 있는지에 관계없이 언제든지 해당 attrib을 활성화 / 비활성화 할 수 있습니까?

또는 (3b) 당시 Vertex Array에 묶인 Vertex Attrib glEnableVertexAttribArray이 호출 되었는가 glEnableVertexAttribArray? 따라서 다른 Vertex Array가 바인딩되어있을 때 다른 시간 에 호출하여 동일한 Vertex Attrib을 여러 Vertex Array에 추가 할 수 있습니까?

답변:


210

일부 용어는 약간 벗어났습니다.

  • A Vertex Arrayfloat[]꼭짓점 데이터를 포함 하는 배열 (일반적으로 a )입니다. 어떤 것에 묶일 필요가 없습니다. Vertex Array Object또는 VAO 와 혼동하지 마십시오. 나중에 살펴 보겠습니다.
  • A는 Buffer Object, 일반적으로 언급 Vertex Buffer Object정점을 저장, 또는 줄여서 VBO 때, 당신은 단지를 호출하는 것입니다 Buffer.
  • 어떤 것도 정점 배열에 다시 저장되지 않고 glVertexAttribPointer정확히 동일하게 작동 glVertexPointer하거나 glTexCoordPointer작동합니다. 이름이 지정된 속성 대신 고유 한 속성을 지정하는 숫자를 제공하게됩니다. 이 값을 index. 모든 glVertexAttribPointer통화는 다음에 glDrawArrays또는을 ( 를) 호출 할 때 대기열에 추가됩니다 glDrawElements. VAO 바인딩이있는 경우 VAO는 모든 속성에 대한 설정을 저장합니다.

여기서 가장 중요한 문제는 정점 속성을 VAO와 혼동하고 있다는 것입니다. 정점 속성은 그리기를 위해 정점, texcoord, 법선 등을 정의하는 새로운 방법입니다. VAO는 상태를 저장합니다. 먼저 버텍스 속성을 사용하여 드로잉이 작동하는 방식을 설명하고 VAO를 사용하여 메서드 호출 수를 줄이는 방법을 설명합니다.

  1. 셰이더에서 속성을 사용하려면 먼저 속성을 활성화해야합니다. 예를 들어 정점을 셰이더로 보내려는 경우 첫 번째 속성 인 0으로 보낼 가능성이 높습니다. 따라서 렌더링하기 전에을 사용하여 활성화해야합니다 glEnableVertexAttribArray(0);.
  2. 이제 속성이 활성화되었으므로 사용할 데이터를 정의해야합니다. 그렇게하려면 VBO-를 바인딩해야합니다 glBindBuffer(GL_ARRAY_BUFFER, myBuffer);.
  3. 이제 속성을 정의 할 수 있습니다 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);. 매개 변수 순서 : 0은 정의하려는 속성, 3은 각 정점의 크기 GL_FLOAT, 유형, GL_FALSE각 정점을 정규화하지 않음을 의미하며 마지막 2 개의 0은 정점에 보폭이나 오프셋이 없음을 의미합니다.
  4. 그것으로 무언가를 그려라- glDrawArrays(GL_TRIANGLES, 0, 6);
  5. 다음으로 그리는 것은 속성 0을 사용하지 않을 수 있으므로 (실제로는 사용되지만 이것은 예제입니다) 비활성화 할 수 있습니다. glDisableVertexAttribArray(0);

그것을 glUseProgram()호출로 감싸면 셰이더와 제대로 작동하는 렌더링 시스템이 있습니다. 하지만 5 개의 다른 속성, 정점, texcoord, 법선, 색상 및 라이트 맵 좌표가 있다고 가정 해 보겠습니다. 우선, glVertexAttribPointer이러한 각 속성에 대해 단일 호출을 만들고 모든 속성을 미리 활성화해야합니다. 내가 나열한대로 0-4 속성을 정의한다고 가정 해 보겠습니다. 다음과 같이 모두 활성화합니다.

for (int i = 0; i < 5; i++)
    glEnableVertexAttribArray(i);

그런 다음 각 속성에 대해 서로 다른 VBO를 바인딩해야합니다 (모두 하나의 VBO에 저장하고 오프셋 / 스트라이드를 사용하지 않는 한), 정점에 대해 각각 라이트 맵 좌표 에 대해 5 개의 서로 다른 glVertexAttribPointer호출 을 수행해야합니다 .glVertexAttribPointer(0,...);glVertexAttribPointer(4,...);

이 시스템만으로도 이해가 되길 바랍니다. 이제 이러한 유형의 렌더링을 수행 할 때 VAO를 사용하여 메서드 호출 수를 줄이는 방법을 설명하기 위해 VAO로 이동합니다. VAO를 사용할 필요는 없습니다.

A Vertex Array Object또는 VAO는 모든 glVertexAttribPointer호출 의 상태 와 각 glVertexAttribPointer호출이 수행 될 때 대상이 된 VBO 를 저장하는 데 사용됩니다 .

에 대한 호출로 하나를 생성합니다 glGenVertexArrays. 필요한 모든 것을 VAO에 저장하려면로 바인딩 glBindVertexArray한 다음 전체 그리기 호출을 수행하십시오 . 모든 드로우 바인드 호출은 VAO에 의해 가로 채서 저장됩니다. VAO의 바인딩을 해제 할 수 있습니다.glBindVertexArray(0);

이제 개체를 그리려는 경우 모든 VBO 바인딩 또는 호출을 다시 호출 할 필요가 없습니다 glVertexAttribPointer. VAO를 glBindVertexArraythen call glDrawArrays또는 호출 로 바인딩 glDrawElements하면됩니다. 모든 메소드 호출을하고있었습니다. 나중에 VAO의 바인딩을 해제하고 싶을 수도 있습니다.

VAO의 바인딩을 해제하면 모든 상태가 VAO를 바인딩하기 전의 상태로 돌아갑니다. VAO가 바인딩되어있는 동안 변경 한 내용이 유지되는지 확실하지 않지만 테스트 프로그램으로 쉽게 알아낼 수 있습니다. glBindVertexArray(0);"기본"VAO에 바인딩하는 것으로 생각할 수 있습니다 .


업데이트 : 누군가가 실제 드로우 콜이 필요하다는 점을 알려주었습니다. 결과적으로 VAO를 설정할 때 실제로 FULL 드로우 콜을 수행 할 필요가 없습니다. 왜 더 일찍 필요하다고 생각했는지 모르겠지만 지금은 해결되었습니다.


10
"정점 버퍼 개체 또는 VBO (때로는 그냥 버퍼 개체라고도 함)"실제로 호출되기 때문에 "때때로"라고 부릅니다. 균일 한 블록, 픽셀 전송, 변환 피드백 또는 기타 용도에 사용할 수있는 다른 버퍼 객체와 다르지 않은 버퍼 객체 일뿐입니다. OpenGL 사양 은 어떤 것도 "정점 버퍼 객체"라고 언급 하지 않습니다 . 원래 확장 사양 조차도 그렇게 부르지 않습니다.
Nicol Bolas 2012 년

3
훌륭한 대답입니다. 시간을내어 작성해 주셔서 감사합니다! 몇 가지 후속 질문이 있습니다. (1) "렌더링하기 전에 속성을 정의하기 전에 glEnableVertexAttribArray (0)"를 사용하여 활성화해야한다고 말했습니다. 호출하기 전에 활성화해야 glVertexAttribPointer합니까? 내 테스트에서 순서는 중요하지 않은 것 같습니다. (2) 내가 올바르게 이해했다면 Vertex Attributes는 전역 적이며 활성화 / 비활성화 상태 만 현재 바인딩 된 VAO에 저장됩니까?
mpen 2012 년

1
(1) glDrawArrays또는 이전에 활성화 한 경우 주문이 중요하지 않다고 생각합니다 glDrawElements. (2) 예를 반영하기 위해 게시물을 업데이트하겠습니다.하지만 저장된 활성화 / 비활성화 상태뿐만 아니라 해당 호출과 관련된 모든 것입니다. 당시 GL_ARRAY_BUFFER에 바인딩 된 항목, 유형, 보폭 및 오프셋입니다. 기본적으로 모든 정점 속성을 VAO로 설정 한 방식으로 되돌릴 수있을만큼 충분히 저장됩니다.
Robert Rouhani

2
예, VAO는 대부분의 그리기 메서드를 VAO 바인딩으로 대체 할 수 있도록 설계되었습니다. 모든 엔터티는 별도의 VAO를 가질 수 있으며 여전히 잘 작동합니다. 그래도 유니폼을 업데이트하고 자신의 텍스처를 바인딩해야합니다. 그리고 layout(location = x)셰이더를 통하거나 glBindAttributeLocation셰이더를 컴파일 할 때 와 상관없이 셰이더의 속성을 속성 인덱스로 바인딩해야하는 것과 동일한 속성 인덱스를 사용해야합니다 .
Robert Rouhani

8
최신 OpenGL에는 더 이상 기본 정점 배열 개체가 없으므로 직접 만들어야합니다. 그렇지 않으면 응용 프로그램이 포워드 호환 컨텍스트에서 작동하지 않습니다.
Overv

3

호출 할 API의 용어와 순서는 실제로 매우 혼란 스럽습니다. 더욱 혼란스러운 것은 버퍼, 일반 정점 속성 및 셰이더 속성 변수와 같은 다양한 측면이 연결되는 방식입니다. 꽤 좋은 설명 은 OpenGL 용어 를 참조하십시오 .

또한 OpenGL-VBO, shader, VAO 링크 는 필요한 API 호출이 포함 된 간단한 예를 보여줍니다. 즉각적인 모드에서 프로그래밍 가능한 파이프 라인으로 전환하는 사람들에게 특히 좋습니다.

도움이되기를 바랍니다.

편집 : 아래 설명에서 볼 수 있듯이 사람들은 가정을하고 결론을 내릴 수 있습니다. 현실은 초보자에게 상당히 혼란 스럽습니다.


" 꽤 좋은 설명은 OpenGL-Terminology를 참조하십시오. "1 분도 채 안되어서 저는 이미 한 가지 잘못된 정보를 발견했습니다. "이들은 셰이더 변수 (인덱스라고 함)와 관련된 일반 정점 속성으로 대체되었습니다. 좌표, 색상 등) 속성을 처리합니다. " "인덱스"라고 부르지 않습니다. 그들은 "위치"입니다. 정점 속성 때문은 매우 중요한 차이점이다 또한 "인덱스"가 있다, 매우 다른 위치에서합니다. 그것은 매우 끔찍한 웹 사이트입니다.
Nicol Bolas 2016

2
그것은 공정한 의견이지만 완전히 정확하지는 않습니다. 당신은 일반적인 속성 정의는 OpenGL API를 보면 glVertexAttribPointer을 , void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer)식별자는 다음과 같이 언급한다 index. 프로그램 컨텍스트에서 동일한 식별자가 locationAPI glGetAttribLocation 에서 호출 됩니다 .
ap-osd
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.