
지금까지 우리는 평면만 살펴봤음
이제 이걸 3D로 돌려볼거임
이때 필요한게 전 포스트인 glm에서 사용해본 변환행렬임
정점과 텍스쳐로 설정된 모든 삼각형 혹은 물체는 공간 변환을 통해 스크린에 출력되게 됨

이렇게 5개의 공간이 있음
모든 좌표를 -1~1사이의 좌표로 정의해야 한다면 좀 불편하겠지?
따라서 원하는 좌표 체계를 정의하고
이거를 NDC기억남?
Normalized Device Coordinates라고 GL에서 정의한 정규화된 좌표체계로 변환함
여기서 중요한 개념이 등장하는데
정투영, 원근투영임
먼저 원근 분할이라는 개념을 알아야함
먼저 행렬이 벡터를 조작하는 함수라는걸 기억할거임
그리고 동차좌표계를 사용해서 n차원일때 n+1개의 원소를 가지는 벡터를 사용한다고도 햇고,
그렇게 만든 행렬을 이용해서 벡터를 조작하는걸 애파인 변환이라고도 했음!
원근분할은 간단함
가 있을때
값이 원근감을 주기위해 사용되는거임
정투영일때는 각 좌표
, , 가 와 똑같음
가 1.0으로 고정되어야 정투영이거든 ㅇㅇ
원근투영일때는 각 좌표
, , 가 와 다름
가 카메라부터의 거리에 따라 값이 커지게 됨
따라서 좌표 가 -1~1사이에 있도록 도움을 줌
자 근데 가 커질수록 원근투영에서는 0에 가까워지겠지?
그럼 원점에 모이게 되고, 엄청 작아지게되어 결국 안보이게 되는거임
정투영은 말 그대로 원근감 없이 모든 정점간의 거리에 대하여 같은 비율을 적용하는거임
Frustum이라고 불리는데 절두체라는게 있음
원뿔, 삼각뿔 같은거를 중간을 밑면과 평행하게 짜르면 총 2개의 면이 생김
이때 카메라와 가까운쪽은 near, 먼쪽은 far이라고 부름
그리고, 이 near, far frustum사이에 잇는 오브젝트 면을 클립함
바깥에 있는건 무시되는거임 ㅇㅇ
이때 정투영은 사진에서 보이다 싶이
원근이 필요없으므로, near와 far frustum이 1:1비율을 가지게 됨
따라서 아무리 물체가 멀리있어도 원근감이 생기지 않음
그래서 2D에 적합함
glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);
이런식으로 사용함
cpu 래스터라이저를 만들어보면
각 레이트레이싱이라는 개념을 접하게 됨
레이트레이싱을 할때 각 픽셀에서 좌표계에 맞춰
0,0,(1 | -1)로 직선을 쏴서 hit되는 부분의 색상을 결정하는걸 구현하게 됨이게 정투영임
정투영과는 다르게
near와 far의 frustum의 크기가 다름
진짜로 사각뿔을 이용해서 밑면과 평행한 일정부분을 잘라

이런식으로 각 frustum의 비율 차이가 생기게 됨
이 비율이 바로 해상도 비율과 똑같음
16:9뭐 이런거 ㅇㅇ
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f);
이렇게 사용함
y의 각임값의 계산방식이 궁금하다면
OpenGL Projection Matric - Projection Matric With FOV 참고 ㄱㄱ
cpu 래스터라이저를 만들어보면
각 레이트레이싱이라는 개념을 접하게 됨
레이트레이싱을 할때 카메라 좌표(0,0,0)에서 화면의 각 픽셀(x,y,z)로 레이를 쏴서
hit되는 지점의 색상을 결정짓는 방식을 구현하게 됨이게 정투영임
정투영과 원근투영의 차이점을 보여주자면

이렇게 됨
이제 어떻게 클립 공간을 만드느냐인데...
사실 이건 쉐이더로 넘기면 됨
vertex shader에서 gl_position을 사용해 각 정점을 매핑해준걸 기억해야함!
(location = 0) vec4 aPos뭐 이런식으로 값을 받아서 VAO를 이용해
vertex attribute linking을 해서 정점좌표 매핑해준게 기억나지?
거기서 이것도 해결하면 됨
을 하면됨
클립 공간에서 이제 우리가 처~~~음에
glViewport설정 해준 그 창의 각 좌표 픽셀로
색상값을 계산해서 gl이 알아서 NDC좌표로 변환해서 화면에 출력하게 됨
그러니까 걱정말고!
간단함!!
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 2) in vec2 aTexCoord;
out vec2 texCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0f);
texCoord = vec2(aTexCoord.x, aTexCoord.y);
}
먼저 이렇게 vertex shader를 수정해줌
3개의 변환 행렬을 받아서
차례대로 aPos -> model -> view -> projection순으로 변환이 이뤄지게 되지비
추가로 여러 상자를 출력하기 위해
float vertices[] =
{
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
glm::vec3 cubePositions[] =
{
glm::vec3( 0.0f, 0.0f, 0.0f),
glm::vec3( 2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3( 2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3( 1.3f, -2.0f, -2.5f),
glm::vec3( 1.5f, 2.0f, -2.5f),
glm::vec3( 1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
};
이렇게 vertices와 cubePosition이라는걸 이용해서 상자의 각 정점과 포지션을 옮기도록 할거임!
보통 오브젝트는 계속 값이 동적으로 바뀌므로
while문 내부에서 값을 선언해주고 쉐이더로 값을 넘김
// 모델, 뷰, 투영 행렬
shaderProgram.useShader();
glm::mat4 view = glm::mat4(1.0f);
view = glm::translate(view, glm::vec3(0, 0, -5));
glm::mat4 projection = glm::mat4(1.0f);
projection = glm::perspective(glm::radians(45.0f), (float)windowWidth/windowHeight, 0.1f, 100.0f);
uint32_t viewLoc = glGetUniformLocation(shaderProgram.shaderProgramID, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
uint32_t projectionLoc = glGetUniformLocation(shaderProgram.shaderProgramID, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(VAO);
for(unsigned int i = 0; i < 10; i++)
{
// calculate the model matrix for each object and pass it to shader before drawing
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
float angle = glfwGetTime() * 25.0f;
model = glm::rotate(model, glm::radians(angle * 10), glm::vec3(1.0f, 0.3f, 0.5f));
uint32_t modelLoc = glGetUniformLocation(shaderProgram.shaderProgramID, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
}
이렇게 회전하면서
cubePosition만큼 움직인 여러 cube들을 만들도록 했음
rotate, translate는 model행렬에서 이뤄지는거 유의!

3가지를 확인가능함
여기서 앞뒤 구분을 넣어주자
이거 구현했던거 기억남?
나만의 tiny renderer 만들기 (4) - Z-Buffer, 애파인(아핀) 변환
이거를 그냥 OpenGl에서는 한줄로 사용가능함
while이 시작되기전에
glEnable(GL_DEPTH_TEST);
이렇게 glEnable, glDisable메서드를 통해 원하는 기능을 켜고 끌 수 있음
여기선 GL_DEPTH_TEST라는 z-buffer 기능을 켜줌으로써
상자의 앞뒤가 겹치는걸 해결함!

근데 막상 넣고 실행하면 이런 검은 화면이 나올거임
이유는 zbuffer를 켜면,
이전 버퍼의 깊이정보가 그대로 유지되어
렌더링에 있어 방해가 일어나게됨
따라서
while(!glfwWindowShouldClose(window))
{
process_input(window);
glClearColor(.0f, .0f, .0f, 1.f);
/*중요!*/glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//....
}
이렇게 glClear메서드를 통해 Color와 depth 버퍼를 비워주면 됨!!

끝!!