Feeding Vertex Shaders from Buffers
GLuint vao;
glCreateVertexArrays(1, &vao);
glBindVertexArray(vao);
위와 같이 VAO를 생성하고 바인딩한다.
그 다음에 상태를 설정하는 과정에서 6판에서와 7판에서의 방법이 상당히 달랐다.
보아하니 6판에서는 glVertexAttribPointer라는 함수로 데이터가 버퍼 객체에 해당하는 위치와 인덱스로 버텍스 속성을 참조하고,
데이터 정규화를 해야하는지 여부, stride인자를 통한 opengl에서 vertex사이의 간격, vertex 속성 데이터의 시작 offset 등을 모두 다루지만,
7판에서는 attribindex를 특정하고 바인딩, 버텍스 속성 설정 과정을 glVertexArrayAttribBinding으로 처리하고,
glVertexArrayVertexBuffer에서 바인딩 된 버퍼에서 데이터를 읽어 stride, offset들을 처리하고 VAO에 저장한다.
glVertexArrayAttribFormat에서 데이터 정규화, 분할되었다.
void glVertexArrayAttribBinding(GLuint vaobj,
GLuint attribindex,
GLuint bindingindex);
void glVertexArrayVertexBuffer(GLuint vaobj,
GLuint bindingindex,
GLuint buffer,
GLintptr offset,
GLsizei stride);
void glVertexArrayAttribFormat(GLuint vaobj,
GLuint attribindex,
GLint size,
GLenum type,
GLboolean normalized,
GLuint relativeoffset);
위 두 함수를 이용한 과정으로 6판의 glVertexAttribPointer함수에서 분할된 것 같다.
6판을 기준으로 설명하자면 크게 버텍스의 속성을 glVertexAttribPointer를 통해 설정한다.
void glVertexAttribPointer(GLuint index,
GLint size,
GLenum type,
GLboolean normalized,
GLsizei stride,
const GLvoid * pointer);
void glEnableVertexAttribArray(GLuint index);
버텍스 속성 인덱스를 index인자로 설정하고,
size로 컴포넌트의 개수를 지정한다.,
type으로 데이터타입을 지정한다.
데이터 정규화 여부를 normalized인자로 결정하고,
stride는버텍스 데이터 간의 간격을 의미한다. 0일 경우 size와 type에 따라 opengl에 의해 결정된다.
// First, bind a vertex buffer to the VAO
glVertexArrayVertexBuffer(
vao, // Vertex array object
0, // First vertex buffer
binding
buffer, // Buffer object
0, // Start from the beginning
sizeof(vmath::vec4)); // Each vertex is one vec4
// Now, describe the data to OpenGL, tell it where it is, and turn on automatic
// vertex fetching for the specified attribute
glVertexArrayAttribFormat(vao, // Vertex array object
0, // First attribute
4, // Four components
GL_FLOAT, // Floating-point data
GL_FALSE, // Normalized - ignored for floats
0); // First element of the vertex
glEnableVertexArrayAttrib(vao, 0);
위는 7판의 vertex buffer와 attribformat을 이용해서 버텍스 속성을 설정하는 코드이다.
6판의 glVertexAttrubPointer도 마찬가지로 버퍼를 바인딩한 이후 읽어온 데이터를 버텍스 쉐이더의 속성에 채운다.
위 코드에서 vertex attribute index는 0이므로 첫 번째 속성에 채우는 것이다.
#version 450 core
layout (location = 0) in vec4 position;
void main(void)
{
gl_Position = position;
}
위와 같이 쉐이더의 데이터를 받아오기 때문에 main안에서 데이터 배열을 하드코딩하지 않고 깔끔하다.
void glDisableAttribArray(GLuint index);
버텍스의 속성을 채우고 난 후 위 함수를 이용해서 속성을 다시 비활성화한다.
그 다음 glVertexAttrib*함수를 이용하여 지정한 값을 쉐이더에 전달한다.
Using Multiple Vertex Shader Inputs
opengl을 이용해서 vertex shader의 데이터를 전달하거나 버퍼 객체로 전달할 수 있었다.
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
위처럼 여러 버텍스 쉐이어 입력값이 있더라도
GLint glGetAttribLocation(GLuint program,
const GLchar * name);
위 함수로 확인할 수 있다.
program은 객체의 이름,
name은 버텍의 속성이름인데, layout에서 선언한 것 처럼 "position"을 전달하면 0, "color"를 전달하면 1을 return한다. 그외 버텍스 쉐이더 속성이름이 아니라면 -1을 return한다.
버텍스 쉐이더 입력을 애플리케이션 데이터로 연결시키는 방법은 독립 속성과 인터리브 속성 두 가지이다.
GLuint buffer[2];
GLuint vao;
static const GLfloat positions[] = { ... };
static const GLfloat colors[] = { ... };
// Create the vertex array object
glCreateVertexArrays(1, &vao)
// Get create two buffers
glCreateBuffers(2, &buffer[0]);
// Initialize the first buffer
glNamedBufferStorage(buffer[0], sizeof(positions), positions, 0);
// Bind it to the vertex array - offset zero, stride = sizeof(vec3)
glVertexArrayVertexBuffer(vao, 0, buffer[0], 0, sizeof(vmath::vec3));
// Tell OpenGL what the format of the attribute is
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
// Tell OpenGL which vertex buffer binding to use for this attribute
glVertexArrayAttribBinding(vao, 0, 0);
// Enable the attribute
glEnableVertexArrayAttrib(vao, 0);
// Perform similar initialization for the second buffer
glNamedBufferStorage(buffer[1], sizeof(colors), colors, 0);
glVertexArrayVertexBuffer(vao, 1, buffer[1], 0, sizeof(vmath::vec3));
glVertexArrayAttribFormat(vao, 1, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(vao, 1, 1);
glEnableVertexAttribArray(1);
객체를 생성하고 버퍼를 GL_ARRAY_BUFFER 타깃에 바인딩하여 glVertexAttribPointer를 호출하는 식이다.
위 코드를 보자.
두 속성에 값을 전달하기 위해 배열 구조체 SoA(Structures of Array)를 사용하였다. 반대로 구조체 배열인 AoS(Array of Structures)의 형태로 구성할 수 있다.
struct vertex
{
// Position
float x;
float y;
float z;
// Color
float r;
float g;
float b;
};
단일 구조체 안에 두 개의 버텍스 쉐이더 입력이 번갈아 들어있고, 이를 배열로 만들어 구조체-배열 현태로 구성한다.
GLuint vao;
GLuint buffer;
static const vertex vertices[] = { ... };
// Create the vertex array object
glCreateVertexArrays(1, &vao);
// Allocate and initialize a buffer object
glCreateBuffers(1, &buffer);
glNamedBufferStorage(buffer, sizeof(vertices), vertices, 0);
// Set up two vertex attributes - first positions
glVertexArrayAttribBinding(vao, 0, 0);
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, offsetof(vertex, x));
glEnableVertexArrayAttrib(0);
// Now colors
glVertexArrayAttribBinding(vao, 1, 0);
glVertexArrayAttribFormat(vao, 1, 3, GL_FLOAT, GL_FALSE, offsetof(vertex, r));
glEnableVertexArrayAttrib(1);
// Finally, bind our one and only buffer to the vertex array object
glVertexArrayVertexBuffer(vao, 0, buffer);
위 코드는 7판의 코드로 glVertexAttribPointer가 아닌 binding, format과정으로 분리되어있다.
구조체 배열 형태로 선언한 버텍스 쉐이더에 대해서 glVertexArrayVertexBuffer를 호출하려면, stride 인자가 필요하고, stride인자는 버텍스 데이터의 시작이 떨어져있는 정도를 opengl에게 알린다.
0으로 설정하면 opengl이 모든 버텍스에 같은 데이터를 사용할 것이다.
VAO를 바인딩하고 데이터를 가져와 사용한다.
버텍스 formatting을 위해 glVertexArrayAttribFormat을 호출하고, 바인딩된 버텍스 버퍼를 glVertexArrayAttribBinding을 통해 변경할 수 있다.
Loading Objects from Files
하나의 쉐이더에 여러개의 버텍스 속성을 설정하는 작업은 번거롭기에, 모델에 대한 데이터를 파일에 저장해서 애플리케이션으로 로딩하는 방법이 좋다.
opengl super bible에서는 .sbm이라는 형식의 객체 포멧을 정의해놓았다.
sb7::object my_object; // 6판일 경우 sb6
my_object.load("filename.sbm");
위 방법과 같은 불러오는 과정을 object에 포함하고 있다.
object의 인스턴스로 모델을 불러와 렌더링가능하게 한다. 내부적으로 객체의 VAO 설정 및 모든 버텍스 속성 설정을 포함하고 있다.
my_object.render();
render함수를 포함하기 때문에 호출하면 쉐이더를 사용하여 객체 복사본을 렌더링한다.
'개발 · 컴퓨터공학' 카테고리의 다른 글
OpenGL 공부일지 - OpenGL Super Bible 유니폼 - 2 (0) | 2022.03.09 |
---|---|
OpenGL 공부일지 - OpenGL Super Bible 유니폼 - 1 (0) | 2022.03.08 |
OpenGL 공부일지 - OpenGL Super Bible Buffer - 1 (0) | 2022.03.06 |
Learning Unreal 4 언리얼 공부일지 - Landscape Layer Blending (0) | 2022.03.05 |
Learning Unreal 4 언리얼 공부일지 - Landscape 사용해보기 (0) | 2022.03.04 |