Model, View, Projection Matrix들은 최종적으로 어떤 vertex가 화면 상의 어느 픽셀에 위치해야 하는지를 결정할 때 사용되는 행렬들이며, 이 행렬들을 서로 곱해 4x4 크기의 MVP matrix를 만들어 사용한다. 이렇게 구한 행렬을 vertex position과 곱해 화면 상의 위치를 구할 수 있다. Projection Matrix는 지난 시간에도 잠시 다뤘지만, 어떠한 3차원 공간을 2차원 상의 공간에 맵핑하는(=투영) 역할을 해 준다. 카메라와 거리가 0인 물체는 x, y 좌표를 3차원 공간일 때의 값 그대로 유지하겠지만, 멀리 있는 물체는 같은 x, y 좌표에 있더라도 z값이 크기 때문에 맵핑 후에는 x, y 값이 변하는데, 이를 하나의 행렬곱으로 표현할 때 사용되는 행렬..
그래픽스 프로그래밍에서 수학은 빼놓을 수 없다. 이번 포스트에서는 glm이라는 오픈소스 header-only 수학 라이브러리를 사용해 간단한 Projection Matrix 행렬 연산을 코드에 추가해보겠다. Application.cpp // Include GLEW #include // Include GLFW #include #include #include "VertexBuffer.h" #include "VertexArray.h" #include "IndexBuffer.h" #include "Shader.h" #include "Renderer.h" #include "Texture.h" #include "glm/glm.hpp" // 라이브러리 사용 #include "glm/gtc/matrix_transfor..
Blending이란? 일부 혹은 전체가 transparent한 무언가를 렌더링할 때 어떤 식으로 렌더링 할지를 연산하는 과정 OpenGL에서 블렌딩을 조정하는 세 가지 방법 glEnable(GL_BLEND) / glDisable(GL_BLEND) : 블랜딩 기능 활성화/비활성화 glBlendFunc(src, dest) : src는 새로 블렌딩시켜줄 픽셀의 RGBA(다른 컬러채널일 수도 있음)에 곱해줄 값을 의미하고, dest는 목표 위치에 이미 있는 픽셀의 RGBA에 곱해줄 값을 의미한다. src의 기본값은 1, dest는 0이다. glBlendEquation(mode) : src RGBA와 dest RGBA를 서로 어떤 연산을 통해 블랜딩 시켜줄지를 결정한다. 기본값은 더하기이다. 고로 OpenGL의 ..
텍스쳐란? 오브젝트 표면에 입힐 수 있는 어떠한 이미지 실제 게임 엔진에서 png를 텍스쳐로 사용하는 경우는 많지 않지만, 본 포스트에선 편의를 위해 png 파일을 텍스쳐로 사용한다. (stb라는 라이브러리의 stb_image를 사용해 png를 로딩한다, 파일경로를 입력하면 rgba 픽셀들 array(버퍼) 포인터를 반환하는 역할을 하는 라이브러리 - https://github.com/nothings/stb) 그 후 이미지 버퍼를 opengl을 통해 gpu에 텍스쳐 값으로 전달후 pixel shader(=fragment shader)에도 전달해 렌더링한다. 해당 라이브러리를 사용하려면 단순히 stb_image.h를 프로젝트 어딘가에 넣으면 되는데, 이 때 해당 헤더 상단에 적혀있는 유의사항대로 사용 전 ..
OpenGL을 프로젝트에서 보다 사용하기 편하게 클래스를 이용해 추상화하는 과정에 대해 살펴보자. 전반적으로 크게 어려운 내용은 없다. 그냥 OpenGL에서 제공되는 함수들을 역할 별로 클래스로 감싸 보다 사용하기 쉽게 만드는 과정이다. 그 후 렌더러 클래스를 제작함으로써 이렇게 추상화한 다른 클래스들을 렌더러라는 하나의 파이프라인으로 묶어 렌더러.Draw()로 한 번에 렌더링할 수 있게 할 것이다. 이렇게 하면 무언가를 렌더링(Draw Call)할 때 추상화한 이 클래스 저 클래스 왔다갔다 하면서 복잡하게 함수를 호출할 필요 없이 렌더러라는 하나의 클래스로만 렌더링 통제가 가능해진다. 코드 구조를 살펴보면 기존 openGL에서 제공하던 오브젝트들을 다음과 같이 클래스로 나누었다. IndexBuffer,..
VAO의 사용 목적은 Vertex buffer가 여러 개 있을 때 각 버퍼마다 Layout(Attribute를 지정해서 버퍼 내에 어떤 정보가 어디에 얼만큼 위치하는지를 지정해두는 것)을 개별적으로 지정해둘 필요가 없게 하는 것이다. 즉 Binding된 Vertex Buffer가 변경될 때마다 매번 그 버퍼가 가진 Attribute들에 대해 glVertexAttribPointer()를 호출할 필요가 없다는 의미다. glBindBuffer(buffer1); glVertexAttribPointer(...); ... glBindBuffer(buffer2); glEnableVertexAttribArray(...); 이런식으로 할 필요가 없어진다는 의미다. 참고: https://stackoverflow.com/q..
uniform은 cpu side 데이터들을 gpu 상으로 옮길 수 있도록 양쪽 모두에서 액세스가 가능한 일종의 변수 역할을 해준다. uniform은 set-per-draw 인데, 즉 Draw call 동안에는(즉 화면에 실제로 렌더링하는 도중에는) uniform을 수정할 수 없음을 의미한다. #shader vertex #version 330 core layout(location = 0) in vec4 position; void main() { gl_Position = position; } #shader fragment #version 330 core layout(location = 0) out vec4 color; // uniform 선언 uniform vec4 u_Color; void main() { ..
OpenGL에서의 디버깅은 굉장히 까다롭다. // Draw the triangle ! //glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); glDrawElements(GL_TRIANGLES, 6, GL_INT, nullptr); //DrawArrays에서 DrawElements로 변했다. //대부분의 상황에서 index buffer가 쓰이기 때문에 DrawElements가 더 자주 쓰인다. //또 앞서 여러차례 보았듯이 unsigned int를 사용했다는 걸 알 수 있는데, //그냥 int를 사용하면 화면이 검게 나오며 아무것도 draw되지 않는다! //(참고: unsinged char등을 사용해 크기를 줄일수야 있지만 최대 정점..