[GPU프로그래밍] 3. Working with GLSL Programs
shader에 데이터 보내기
- vertex attributes(버텍스별로 달라지는 데이터)와 vertex buffer objects 사용
- uniform variables(한 장면 렌더링하는 동안 바뀌지 않는 데이터) 사용
1. Vertex attributes
- vertex shader에서 각 vertex에 대한 input변수 정의 (per-vertex input)
- GLSL qualifier를 사용하여 정의
- ex) in vec3 VertexColor;
- 데이터는 OpenGL Program에서 제공되어야 하며, Vertex Buffer Object를 통해 전달됨 (VBO에 vertex data가 저장)
- Buffer와 Input attribute간의 연결 필요 (아래 코드)
📃 Triangle Rendering Example (p.5~8)
- 들어온 Position 데이터를 그대로 내보내는 중
- vertex shader의 output이 fragment shader의 input으로 사용 (무조건은 X)
- 버퍼가 여러 개인 경우 fragment shader의 output이 여러 개일 수 있음 (p.21)
- VAO: vertex array object
- VBO: vertex buffer object
- VAO는 VBO를 포함하며, VBO는 여러개일 수 있음
- VAO bind
glBindVertexArray
- VBO bind 및 세팅
glBindBuffer
- binding된 VBO에 data loading
glBufferData
- Vertex attribute 구성
glVertexAttribPointer
✨
- VBO, VAO unbind
- Render loop (해당 VAO bind하여 draw)
glBindVertexArray
👀 아래부터 위의 코드 부분부분 뜯어 정리한 것
◾ Vertex Attribute Data
- 모든 vertex들의 vertex attribute(3D position, 3D normal, Color, ...)를 정의한 Array
- ex) 삼각형의 three vertices의 3D position
◾ VBO (Vertex Buffer Object)
- 많은 데이터(large batches)를 그래픽카드에 한꺼번에 전달하기 위해 Vertex Buffer를 사용
- 많은 수의 vertex들을 GPU의 메모리에 저장해야하기 때문
- 각 attribute에 VBO 생성
- 새롭게 만든 버퍼를 원하는 버퍼 종류로 Bind
GL_ARRAY_BUFFER
, GL_ELEMENT_ARRAY_BUFFER
, GL_TEXTURE_BUFFER
, …
- Binding된 VBO에 데이터 넣기
- 마지막 파라미터는 그래픽 카드가 주어진 데이터를 관리하는 방법(데이처를 어떻게 사용할건지)
- GL_STATIC_DRAW: 버퍼에 올린 데이터를 바꿀 일이 거의 없을 때
- GL_DYNAMIC_DRAW: 데이터가 자주 변경
- GL_STREAM_DRAW: 데이터가 그려질때마다 변경 (가장 많이 바뀌는 경우) -> 그래픽 카드가 빠르게 쓸 수 있는 메모리에 데이터를 저장함
- VBO에 Vertex attribute configurations를 Linking하기
- Vertex attribute configurations: VBO데이터를 어떻게(어떤 순서로) 사용할건지에 대한 규칙
- vertex shader의 어떠한 정점 속성이 입력 데이터의 어느 부분과 맞는지 직접 지정해줘야해서 VBO 데이터를 어떻게 사용할건지 규칙을 정해줘야함✨
- VBO에 데이터 하나씩 올리면서 Position(버텍스)들이 차례대로 들어가있는 상태
- 버퍼에 저장된 데이터들을 순서대로 쓰는 경우도 있지만, 그렇지 않은 경우도 있다
- ex) Position과 Color가 같이 저장된 형태의 한 VAO (보통 따로 버퍼 만들어서 사용함)
- Position과 Color를 따로 쉐이더에 전달해줘야한다 (두 개의 Input)
-> 어떤 순서로 데이터를 사용할건지 규칙을 알려줘야한다!
glVertexAttribPointer
는 vertex attribute configuration 설정하고, VBO들을 vertex attribute들로 구성시킴
- 각 vertex의 attribute는 VBO에 의헤 관리되는 메모리로부터 데이터를 받는데, 그 VBO는 이 함수를 호출하면서 현재 바인딩된 VBO로 결정됨
glEnableVertexAttribArray
로 vertex attribute location을 전달하고 호출하여 사용할 수 있도록함
👀 현재까지는 vertex 데이터를 그래픽카드의 메모리에 저장한 상태, 이 메모리는 VBO가 관리하게된다.
- (위에서 한 것처럼..) 한 VBO에서 데이터를 읽는 규칙을 수정하는 것은 번거롭다
- 그래서, 규칙이 여러개인 경우에는 각 VAO에 규칙들 세팅해두고, 필요한 세팅을 가진 VAO를 binding하여 사용하면 간편하다! (편의성을 위해)
◾ VAO (Vertex Array Object)
- VAO로 사용 규칙을 관리
- 위의 상태 설정을 VAO에 저장하고, VAO를 바인딩하여 상태를 복원
(VAO를 사용하지 않으면, 오브젝트를 그릴 때마다 위의 짓을 반복해야함)
- VAO는
(3)데이터를 저장하는 것
과 (4)데이터를 사용하는 방법
이 분리되어있다
-> VAO = VBO + VBO 사용 규칙
- 아래 이미지는 각각 다른 사용 규칙을 가지는 VAO (한 VBO에 다른 규칙을 갖기도 함)
- Core OpenGL은 VAO 사용 필수가 됨 (최신 버전은 필수)
- 초기화 과정
- VAO 생성 및 Bind
- 그 상태에서 원하는 VBO를 Bind하고, attribute 를 구성
- VBO unbind하고 VAO를 나중에 사용하기 위해 VAO도 unbind
-> VAO에 세팅 완료!
- 드로잉 과정 (렌더링 루프 안)
- 그릴 오브젝트에 해당하는 VAO를 Bind한 후 draw
glDrawArray
: VBO에 있는 데이터를 하나씩 읽으면서 그려줌
-> 버텍스 중복이 생기는 경우 발생 (사각형을 두개의 삼각형으로 그릴 때) glDrawArray(GL_TRIANGLES, 0, 6)
-> Element Array 사용
- 위대로 하면 VAO의 attribute pointer 0에 규칙이 들어가고 활성화 됨
👀 추가 Attributes 예시 (p.18~20)
+) EBO (Element Buffer Object)
glDrawArray
처럼 버텍스 버퍼의 데이터를 하나씩 읽으면서 그리는 것이 아닌, 인덱스 버퍼에서 인덱싱해서 그림 -> glDrawElements
- 버텍스 중복을 방지하여 쓸데없이 버텍스가 더 많이 사용되지 않도록 함
- 첫번째 버퍼: 버텍스 정보 저장 (사각형)
- 두번째 버퍼: 인덱스 정보 저장 (삼각형 2개)
- 겹쳐봤자 인덱스 번호만 겹침
- 버퍼가 2개지만 버텍스 정보가 겹치는 것보단 중복량이 적음
- Element array buffer 를 사용하여 EBO를 만들고, 인덱스 정보를 넘겨주어 오브젝트를 그린다
- 복잡한 모델인 경우
glDrawElements
를 사용하여 그리는 경우가 더 많다 (대부분 그렇다 ~..)
- VAO는 EBO도 저장한다. VAO가 바인딩 되어있는 동안 EBO가 바인딩되면 VAO의 버퍼 객체로 저장된다.
- 버텍스마다 달라지는 정보가 아닌 경우 -> 버텍스마다 보내줄 필요가 없음, 개별적으로 보내줌
- Shader code 안에서는 변하지 않는 상수값 Input
- unique per-shader program object
- 아무 쉐이더에 input 변수로 보내줄 수 있음
📃 시간에 따라 G컬러가 달라지는 예제
- OpenGL Application에서 넘겨줄 변수를 정의
- 해당 Shader Program의 Shader code에 존재하는 Uniform 변수의 이름으로 위치(포인터) 찾음
glGetUniformLocation
- 그 위치로 Uniform 변수를 Shader로 넘겨준다
glUniform데이터타입
- Shader 코드에서는
unifrom
을 사용해 Uniform 변수를 정의한다
- OpenGL Application에서 넘겨준 변수값이 Uniform 변수에 들어간다
◾ glUnifrom 데이터 타입
- f: float
- i: int
- ui: unsigned int
- 3f: 3 floats
- fv: float vector/array