이번에는 Rasterization을 통해 원을 그리고 그 원을 2차원변환(이동, 크기조절, 회전 등)을 조절해볼 것입니다.
고등학교 때 배웠던 간단한 수학 공식이 조금 필요한데요. 그 전에 Rasterization에서는 Raytracing과는 원을 그리는 방식이 다르다는 점을 이해해야합니다. Raysterizaion은 삼각형을 레스터좌표계에 투영해서 픽셀에 나타내는데요. 원 또한 수많은 삼각형을 통해 나타냅니다. 다음 그림과 같이 삼각형을 5개 그리면 5각형이 됩니다. 삼각형을 20개 정도 그리면 원에 가까워지겠죠?
여기서 원을 그리는 원리를 알아볼 것입니다.
5개의 삼각형을 표현할 때 x,y좌표의 원점을 원의 중심이라고 생각합니다. 그리고 꼭짓점이 원점에서의 삼각형의 각도는 θ 입니다. 따라서 각 꼭짓점은 (r*cos (nθ), r*sin (nθ))로 나타낼 수 있습니다. 이 때 주의할 점이 우리는 삼각형의 시계방향을 앞면이라고 약속했습니다. 따라서 삼각형의 정점 v0,v1,v2는 반드시 시계방향으로 정의되어져야합니다.
다음은 원을 그리고, Update함수를 통해 원을 2차원변환 시켜볼 것입니다. 그 전에 회전 변환에 대해 이해해봅시다. x,y는 Φ로 나타내고 변환된 x',y'는 θ+ Φ로 나타낸다고 했을 때, x',y'는 다음 그림과 같습니다.이 때, x', y'는 삼각함수 공식을 통해 , x,y, θ로 나타낼 수 있습니다. .
또한 코드로 표현하면 다음과 같습니다.
vec3 RotateAboutZ(const vec3 &v, const float &theta) {
return vec3(v.x * cos(theta) - v.y * sin(theta),
v.x * sin(theta) + v.y * cos(theta), v.z);
}
이제 이것을 이용해 회전변환에 대해 이해해봅시다.
void Example::Update() {
// 간단한 애니메이션 구현
rasterization.Update();
// 화면 지우기
std::fill(pixels.begin(), pixels.end(),
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); // 검은 배경
// 렌더링
rasterization.Render(pixels);
D3D11_MAPPED_SUBRESOURCE ms;
deviceContext->Map(canvasTexture, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);
memcpy(ms.pData, pixels.data(), pixels.size() * sizeof(glm::vec4));
deviceContext->Unmap(canvasTexture, NULL);
}
void Rasterization::Render(vector<vec4> &pixels) {
//삼각형을 통해 원 구현하는 로직..
}
void Rasterization::Update() {
// 애니메이션 구현
for (size_t i = 0; i < circle.vertices.size(); i++) {
//첫번째 회전변환
this->vertexBuffer[i] =
RotateAboutZ(circle.vertices[i], this->rotation1);
//크기 변환
this->vertexBuffer[i] =
this->vertexBuffer[i] * vec3(scaleX, scaleY, 1.0f);
//첫번째 이동
this->vertexBuffer[i] = this->vertexBuffer[i] + this->translation1;
//두번째 회전변환
this->vertexBuffer[i] =
RotateAboutZ(this->vertexBuffer[i], this->rotation2);
//두번째 이동
this->vertexBuffer[i] = this->vertexBuffer[i] + this->translation2;
}
}
Example 클라스의 Update는 매 프레임마다 Update가 한번 호출됩니다. 이 Update안의 함수 안에 Rasterization의 Update함수와 Render함수가 차례로 진행됩니다. Rasterization의 Update는 매 프레임마다 한번 호출이 되긴하는데 Example클라스의 Update함수에서 한번씩 호출하기 때문에 그렇게 됩니다. 즉 Rasterization의 Update는 변환 vertex에 대해서 작업을 하고 그 후에 Render함수에서 픽셀에 삼각형들을 그려주는 작업을 하게 됩니다.
여기서 가장 중요한 것은 Rasterization의 Update함수의 로직을 이해하는 것입니다. 이 로직을 이해하기 위해 다음을 이해해봅시다.
주의 : vertexBuffer에는 첫 회전변환시에만 circle의 vertex들을 받습니다.
처음 아무것도 움직이지 않았을 때의 그림은 다음과 같습니다.
첫번째 이동을 한 후 두번째 회전변환을 하였을 때, 다음 그림과 같이 원에서 떨어진 원의 vertex들이 원점을 기준으로 회전합니다.
이 때 여기서 첫 번째 회전 변환을 하면 어떻게 될까요?
이번에는 원 자체가 회전을 하였습니다. 얼핏 봤을때 이미 떨어진 원이 원점을 중심으로 회전하고 원자체가 회전한 것처럼 보이지만, 사실 Rasterization의 Update문의 순서를 보면 원 자체를 회전시키고 첫번 째 이동 후에 그 원이 vertex들을 회전시킨 것입니다. 이 로직을 이해하고 있으면 다음을 이해할 수 있습니다.
여기서 다시 첫번째 이동 값 translation1을 줄이면 어떻게 될까요?
이렇게 x,y축을 중심으로 이동하는게 아니라 원점으로 다가갑니다. 이유는 translation1이 진행이 되고, rotation2이 진행이 되기 때문입니다.
강의 및 코드 출처 :
https://honglab.co.kr/courses/graphicspt2
HongLab 홍정모 연구소
홍정모의 컴퓨터 그래픽스 새싹코스
honglab.co.kr
'그래픽스 기술' 카테고리의 다른 글
[Rasterization] Blinn-Phone 모델(블린 퐁 모델) (0) | 2024.11.05 |
---|---|
[Rasterization] 버텍스 쉐이딩과 픽셀 쉐이딩 개념 + 뒷면 제거 (0) | 2024.10.29 |
[Rasterization] 삼각형의 레스터화 (2) | 2024.10.24 |
[Ray Tracing] - 투명한 구의 빛의 굴절 (2) | 2024.10.22 |
[Ray Tracing] - 빛의 반사(거울반사) (0) | 2024.10.22 |