728x90
반응형
Using Uniforms to Transform Geometry
행렬 곱을 이용하면 보려는 위치와 카메라 위치 및 방향을 갖고 객체를 뷰어 공간의 좌표로 변환하는 행렬을 만들 수 있다. 또한 화면에 원근 투영 및 정사영을 나타내는 행렬을 만들 수 있다.
회전하는 정육면체를 그려보자.
// First create and bind a vertex array object
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
static const GLfloat vertex_positions[] =
{
-0.25f, 0.25f, -0.25f,
-0.25f, -0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
0.25f, 0.25f, -0.25f,
-0.25f, 0.25f, -0.25f,
/* MORE DATA HERE */
-0.25f, 0.25f, -0.25f,
0.25f, 0.25f, -0.25f,
0.25f, 0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
-0.25f, 0.25f, 0.25f,
-0.25f, 0.25f, -0.25f
};
// Now generate some data and put it in a buffer object
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_positions),
vertex_positions,
GL_STATIC_DRAW);
// Set up our vertex attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
먼저 원점에 위치하는 단위 정육면체에 대한 지오메트리를 만들어 버퍼 객체에 저장하고, 버텍스 쉐이더를 사용해서 여러 변환을 적용하고 월드 공간에서 이동시킨다.
float f = (float)currentTime * (float)M_PI * 0.1f;
vmath::mat4 mv_matrix =
vmath::translate(0.0f, 0.0f, -4.0f) *
vmath::translate(sinf(2.1f * f) * 0.5f,
cosf(1.7f * f) * 0.5f,
sinf(1.3f * f) * cosf(1.5f * f) * 2.0f) *
vmath::rotate((float)currentTime * 45.0f, 0.0f, 1.0f, 0.0f) *
vmath::rotate((float)currentTime * 81.0f, 1.0f, 0.0f, 0.0f);
기본 뷰 행렬을 만들고, 모델 및 뷰 행렬을 곱해 모델-뷰 행렬을 만든다.
void onResize(int w, int h)
{
sb7::application::onResize(w, h);
aspect = (float)info.windowWidth / (float)info.windowHeight;
proj_matrix = vmath::perspective(50.0f, aspect, 0.1f, 1000.0f);
}
그 다음 카메라의 속성을 가지는 원근 변환 행렬을 만든다.
onResize는 sb6::application에서 제공하는 함수이다. 윈도우의 크기가 변할 때마다 호출되어 투영 행렬을 재계산한다.
// Clear the framebuffer with dark green
glClearBufferfv(GL_COLOR, 0, sb7::color::Green);
// Activate our program
glUseProgram(program);
// Set the model-view and projection matrices
glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
glUniformMatrix4fv(proj_location, 1, GL_FALSE, proj_matrix);
// Draw 6 faces of 2 triangles of 3 vertices each = 36 vertices
glDrawArrays(GL_TRIANGLES, 0, 36);
마지막으로 유니폼을 사용해서 간단한 버텍스 쉐이더에 전달하고 화면에 정육면체를 그린다.
#version 450 core
in vec4 position;
out VS_OUT
{
vec4 color;
} vs_out;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
void main(void)
{
gl_Position = proj_matrix * mv_matrix * position;
vs_out.color = position * 2.0 + vec4(0.5, 0.5, 0.5, 0.0);
}
위와 같은 버텍스 쉐이더 코드와
#version 450 core
out vec4 color;
in VS_OUT
{
vec4 color;
} fs_in;
void main(void)
{
color = fs_in.color;
}
위 프래그먼트 쉐이더를 이용해서 정육면체에 컬러 정보를 전달하자.
// Clear the framebuffer with dark green and clear
// the depth buffer to 1.0
glClearBufferfv(GL_COLOR, 0, sb7::color::Green);
glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
// Activate our program
glUseProgram(program);
// Set the model-view and projection matrices
glUniformMatrix4fv(proj_location, 1, GL_FALSE, proj_matrix);
// Draw 24 cubes...
for (i = 0; i < 24; i++)
{
// Calculate a new model-view matrix for each one
float f = (float)i + (float)currentTime * 0.3f;
vmath::mat4 mv_matrix =
vmath::translate(0.0f, 0.0f, -20.0f) *
vmath::rotate((float)currentTime * 45.0f, 0.0f, 1.0f, 0.0f) *
vmath::rotate((float)currentTime * 21.0f, 1.0f, 0.0f, 0.0f) *
vmath::translate(sinf(2.1f * f) * 2.0f,
cosf(1.7f * f) * 2.0f,
sinf(1.3f * f) * cosf(1.5f * f) * 2.0f);
// Update the uniform
glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
// Draw - notice that we haven't updated the projection matrix
glDrawArrays(GL_TRIANGLES, 0, 36);
}
기존 코드에서 위와 같이 변경하면 여러 정육면체가 돌아다닌다.
#include <sb6.h>
#include <vmath.h>
// Remove this to draw only a single cube!
#define MANY_CUBES
class singlepoint_app : public sb6::application
{
void init()
{
static const char title[] = "OpenGL SuperBible - Spinny Cube";
sb6::application::init();
memcpy(info.title, title, sizeof(title));
}
virtual void startup()
{
static const char * vs_source[] =
{
"#version 410 core \n"
" \n"
"in vec4 position; \n"
" \n"
"out VS_OUT \n"
"{ \n"
" vec4 color; \n"
"} vs_out; \n"
" \n"
"uniform mat4 mv_matrix; \n"
"uniform mat4 proj_matrix; \n"
" \n"
"void main(void) \n"
"{ \n"
" gl_Position = proj_matrix * mv_matrix * position; \n"
" vs_out.color = position * 2.0 + vec4(0.5, 0.5, 0.5, 0.0); \n"
"} \n"
};
static const char * fs_source[] =
{
"#version 410 core \n"
" \n"
"out vec4 color; \n"
" \n"
"in VS_OUT \n"
"{ \n"
" vec4 color; \n"
"} fs_in; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = fs_in.color; \n"
"} \n"
};
program = glCreateProgram();
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, fs_source, NULL);
glCompileShader(fs);
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, vs_source, NULL);
glCompileShader(vs);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
mv_location = glGetUniformLocation(program, "mv_matrix");
proj_location = glGetUniformLocation(program, "proj_matrix");
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
static const GLfloat vertex_positions[] =
{
-0.25f, 0.25f, -0.25f,
-0.25f, -0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
0.25f, 0.25f, -0.25f,
-0.25f, 0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
0.25f, -0.25f, 0.25f,
0.25f, 0.25f, -0.25f,
0.25f, -0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
0.25f, 0.25f, -0.25f,
0.25f, -0.25f, 0.25f,
-0.25f, -0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
-0.25f, -0.25f, 0.25f,
-0.25f, 0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
-0.25f, -0.25f, 0.25f,
-0.25f, -0.25f, -0.25f,
-0.25f, 0.25f, 0.25f,
-0.25f, -0.25f, -0.25f,
-0.25f, 0.25f, -0.25f,
-0.25f, 0.25f, 0.25f,
-0.25f, -0.25f, 0.25f,
0.25f, -0.25f, 0.25f,
0.25f, -0.25f, -0.25f,
0.25f, -0.25f, -0.25f,
-0.25f, -0.25f, -0.25f,
-0.25f, -0.25f, 0.25f,
-0.25f, 0.25f, -0.25f,
0.25f, 0.25f, -0.25f,
0.25f, 0.25f, 0.25f,
0.25f, 0.25f, 0.25f,
-0.25f, 0.25f, 0.25f,
-0.25f, 0.25f, -0.25f
};
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertex_positions),
vertex_positions,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
glEnable(GL_CULL_FACE);
glFrontFace(GL_CW);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
}
virtual void render(double currentTime)
{
static const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };
static const GLfloat one = 1.0f;
glViewport(0, 0, info.windowWidth, info.windowHeight);
glClearBufferfv(GL_COLOR, 0, green);
glClearBufferfv(GL_DEPTH, 0, &one);
glUseProgram(program);
glUniformMatrix4fv(proj_location, 1, GL_FALSE, proj_matrix);
#ifdef MANY_CUBES
int i;
for (i = 0; i < 24; i++)
{
float f = (float)i + (float)currentTime * 0.3f;
vmath::mat4 mv_matrix = vmath::translate(0.0f, 0.0f, -6.0f) *
vmath::rotate((float)currentTime * 45.0f, 0.0f, 1.0f, 0.0f) *
vmath::rotate((float)currentTime * 21.0f, 1.0f, 0.0f, 0.0f) *
vmath::translate(sinf(2.1f * f) * 2.0f,
cosf(1.7f * f) * 2.0f,
sinf(1.3f * f) * cosf(1.5f * f) * 2.0f);
glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
#else
float f = (float)currentTime * 0.3f;
vmath::mat4 mv_matrix = vmath::translate(0.0f, 0.0f, -4.0f) *
vmath::translate(sinf(2.1f * f) * 0.5f,
cosf(1.7f * f) * 0.5f,
sinf(1.3f * f) * cosf(1.5f * f) * 2.0f) *
vmath::rotate((float)currentTime * 45.0f, 0.0f, 1.0f, 0.0f) *
vmath::rotate((float)currentTime * 81.0f, 1.0f, 0.0f, 0.0f);
glUniformMatrix4fv(mv_location, 1, GL_FALSE, mv_matrix);
glDrawArrays(GL_TRIANGLES, 0, 36);
#endif
}
virtual void shutdown()
{
glDeleteVertexArrays(1, &vao);
glDeleteProgram(program);
glDeleteBuffers(1, &buffer);
}
void onResize(int w, int h)
{
sb6::application::onResize(w, h);
aspect = (float)w / (float)h;
proj_matrix = vmath::perspective(50.0f, aspect, 0.1f, 1000.0f);
}
private:
GLuint program;
GLuint vao;
GLuint buffer;
GLint mv_location;
GLint proj_location;
float aspect;
vmath::mat4 proj_matrix;
};
DECLARE_MAIN(singlepoint_app)
최종적으로 예제를 합친 코드는 위와 같다.
define MANY_CUBES를 지우면 하나의 정육면체만 나오고, 정의할 경우 24개의 정육면체가 렌더링된다.
(github 소스코드에서 해당 예제는 spinnycube project이다)
728x90
반응형
'개발 · 컴퓨터공학' 카테고리의 다른 글
OpenGL 공부일지 - OpenGL Super Bible 텍스처 - 1 (0) | 2022.03.11 |
---|---|
OpenGL 공부일지 - OpenGL Super Bible 쉐이더 스토리지 블록, 어토믹 카운터 (0) | 2022.03.10 |
OpenGL 공부일지 - OpenGL Super Bible 유니폼 - 1 (0) | 2022.03.08 |
OpenGL 공부일지 - OpenGL Super Bible Buffer - 2 (0) | 2022.03.07 |
OpenGL 공부일지 - OpenGL Super Bible Buffer - 1 (0) | 2022.03.06 |