Model, View, Projection Matrix들은 최종적으로 어떤 vertex가 화면 상의 어느 픽셀에 위치해야 하는지를 결정할 때 사용되는 행렬들이며, 이 행렬들을 서로 곱해 4x4 크기의 MVP matrix를 만들어 사용한다. 이렇게 구한 행렬을 vertex position과 곱해 화면 상의 위치를 구할 수 있다.
Projection Matrix는 지난 시간에도 잠시 다뤘지만, 어떠한 3차원 공간을 2차원 상의 공간에 맵핑하는(=투영) 역할을 해 준다. 카메라와 거리가 0인 물체는 x, y 좌표를 3차원 공간일 때의 값 그대로 유지하겠지만, 멀리 있는 물체는 같은 x, y 좌표에 있더라도 z값이 크기 때문에 맵핑 후에는 x, y 값이 변하는데, 이를 하나의 행렬곱으로 표현할 때 사용되는 행렬이다.
참고하면 좋은 글: https://jw910911.tistory.com/19
그래픽스 - Projection Matrix란?
투영행렬과 뷰행렬의 관계 뷰 행렬(View Matrix)란 랜더링 파이프라인 단계의 3번째 단계인 뷰 스페이스를 구성하는데 사용되는 설정을 위한 행렬이라고 한다면 투영 행렬은 파이프라인 단계의 투
jw910911.tistory.com
View Matrix는 카메라의 위치(시점)을 나타낼 때 사용되는 행렬이며,
Model Matrix는 오브젝트의 Transform을 나타내는 행렬이다. (=TRS Matrix로 이해하면 된다)
주의해야 할 것은, 카메라를 이동시키는 건 결국 나머지 모든 오브젝트들을 반대로 이동시키는 것과 동일하다는 것이다. 즉 중요한 것은 오브젝트와 카메라의 상대적 관계이지, 카메라의 절대적 위치가 아니다.
코드와 함께 살펴보자.
Application.cpp
// Include GLEW
#include <GL/glew.h>
// Include GLFW
#include <GLFW/glfw3.h>
#include <iostream>
#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_transform.hpp"
GLFWwindow* InitWindow()
{
// Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW\n" );
getchar();
return nullptr;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
GLFWwindow* window = glfwCreateWindow( 960, 540, "Tutorial 02 - Red triangle", NULL, NULL);
if( window == NULL ){
fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
getchar();
glfwTerminate();
return nullptr;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return nullptr;
}
std::cout << "Using GL Version: " << glGetString(GL_VERSION) << std::endl;
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
return window;
}
int main( void )
{
GLFWwindow* window = InitWindow();
if (!window)
return -1;
float positions[] = {
100.0f, 100.0f, 0.0f, 0.0f, // 0
200.0f, 100.0f, 1.0f, 0.0f, // 1
200.0f, 200.0f, 1.0f, 1.0f, // 2
100.0f, 200.0f, 0.0f, 1.0f // 3
};
unsigned int indices[] = {
0, 1, 2,
2, 3, 0
};
GLCall( glEnable(GL_BLEND) );
GLCall( glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) );
{
VertexArray va;
VertexBuffer vb(positions, 4 * 4 * sizeof(float));
IndexBuffer ib(indices, 6);
glm::mat4 proj = glm::ortho(0.0f, 960.0f, 0.0f, 540.0f, -1.0f, 1.0f);
glm::mat4 ident = glm::mat4(1.0f);
/*
레퍼런스 참고:
5.4.2 Vector and Matrix Constructors
If there is a single scalar parameter to a matrix constructor,
it is used to initialize all the components on the matrix's diagonal,
with the remaining components initialized to 0.0.
간단히 말해 위 코드는 4x4짜리 Identity Matrix를 만드는 코드임.
*/
glm::vec3 trvec = glm::vec3(-100, 0, 0); // translation vector, x축으로 -100만큼 이동
glm::mat4 view = glm::translate(ident, trvec); // Translation matrix를 만든다. ([Mathematics] 11. Translation 글 참고)
glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(200, 200, 0)); // 마찬가지로 translation matrix를 만들되, 오브젝트를 x,y축으로 모두 200씩 이동시킨다.
/*
Model matrix와 view matrix는 결국 둘다 해주는 일은 같다. (수학적 원리는 동일하다)
또한 본 예제에서는 translation matrix만 사용했지만 Rotation과 Scalining을 모두 곱해 TRS Matrix 형태를 사용해도 된다.
*/
glm::mat4 mvp = proj * view * model;
// 곱하는 순서가 PVM순인걸 알 수 있는데, 이는 행렬곱 특성상 P*(V*M) 순으로 진행되기에 결국은 MVP순으로 곱이 계산되기 때문이다.
// 주의) TRS Matrix는 MVP와 다르게 이름 순서와 똑같이 T*(R*S) 순으로 곱해준다
// projection matrix
// view matrix
// model matrix
VertexBufferLayout layout;
layout.AddFloat(2);
layout.AddFloat(2);
va.AddBuffer(vb, layout);
Shader shader("res/shaders/Basic.shader");
shader.Bind();
shader.SetUniform4f("u_Color", 0.0f, 0.3f, 0.8f, 1.0f);
shader.SetUniformMat4f("u_MVP", mvp);
Texture texture("res/textures/phone.png");
texture.Bind();
shader.SetUniform1i("u_Texture", 0);
float red = 0.0f;
float step = 0.05f;
Renderer renderer;
do {
renderer.Clear();
shader.Bind();
shader.SetUniform4f("u_Color", red, 0.3, 0.8, 1.0);
renderer.Draw(va, ib, shader);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
// increment red
if (red < 0.0f || red > 1.0f)
step *= -1.0;
red += step;
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
}
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
'computer graphics > OpenGL' 카테고리의 다른 글
[OpenGL] 11. OpenGL과 수학 (0) | 2022.04.16 |
---|---|
[OpenGL] 10. Blending (0) | 2022.04.16 |
[OpenGL] 9. Textures (0) | 2022.04.09 |
[OpenGL] 8. 추상화(Abstraction)와 렌더러 (0) | 2022.04.02 |
[OpenGL] 7. Vertex Array Object (VAO) (0) | 2022.03.01 |