Rasterization은 기본적으로 삼각형을 가지고 모든 물체를 표현하게 된다. 그렇기 때문에 원 또한 삼각형으로 구성되는데, 이를 어떻게 그릴 수 있는지를 작성해 본다.

원점에 위치한 원주 위의 점을 구하는 방법을 생각해보자. 점을 나타내기 위한 식은 다음과 같다.

왜 그런지에 대해서는 그림과 같이 점을 지정하고, 반지름을 1로 두고 계산해 보고, 확장하면 쉽게 유도할 수 있다.

마지막으로 원점이 아닌 다른 지점에 원이 있다면 앞에 원점을 더해줌으로써 최종식을 만들어 낼 수 있다.

이제 원을 몇 개의 삼각형으로 표현할지를 정해야 한다. 더 많은 삼각형으로 표현할 수록 더욱 원에 가까워진다. 최종식에 이를 적용하고 호도법으로 정리하면 세타를 다음과 같은 식으로 나타낼 수 있다.

여기서 NT는 총 삼각형의 개수이고, i는 각도가 늘어나면서 원을 그려야 하므로 NT의 개수까지 0부터 증가하는 변수이다.


구현 코드

const auto radius = 0.5f;                   // 원의 반지름
const auto center = vec3(0.0f, 0.0f, 1.0f); //원의 중심
const size_t numTriangles = 360; // 삼각형 몇 개로 그릴지
 
this->vertices.reserve(numTriangles + 1); // 중심 버텍스 추가
this->colors.reserve(this->vertices.size());
this->indices.reserve(numTriangles * 3);
 
// 중심 버텍스의 위치와 색
this->vertices.push_back(center);
this->colors.push_back(vec3(1.0f, 0.0f, 0.0f));
 
// 라디안(Radian) 2*PI는 360도를 의미한다.
// kTwoPi 이름은 구글 스타일 사용
// <https://google.github.io/styleguide/cppguide.html#Constant_Names>
const auto kTwoPi = 2.0f * 3.141592f;
const auto deltaTheta = kTwoPi / float(numTriangles);
 
// 여기서부터 this->vertices, colors, indices 결정
for (size_t i = 0; i < numTriangles; i++) {
    const float xPos = cos(deltaTheta * i) * radius;
    const float yPos = sin(deltaTheta * i) * radius;
    this->vertices.push_back(center + vec3(xPos, yPos, 0.0f));
    this->colors.push_back(vec3(0.0f, 0.0f, 1.0f));
    ...
}

코드에서 vertices에 각 지점에 대한 좌표들을 전부 넣어줬는데, 삼각형을 그릴 수 있도록 조합하는 과정이 필요하다.

조합은 원점, i + 2, i + 1의 순서를 가진다. i + 2 다음에 1이 오는 이유는 clock-wise로 inside-outside check를 하기 때문이다.

for (size_t i = 0; i < numTriangles; i++) {
		...
		this->indices.push_back(0);
		if (i + 1 == numTriangles)
				this->indices.push_back(1);
		else
		    this->indices.push_back(i + 2);
		this->indices.push_back(i + 1);
}