koodev

'Circle'에 해당되는 글 1건

  1. OpenGL로 원 그리기 1

OpenGL로 원 그리기

Programming

OpenGL로 원을 그리려면 어떻게 해야 할까? OpenGL primitive에는 원이 없고 점이나 선, 삼각형 등만 그릴 수 있다. 그러면 점근적인 접근방식으로 삼각형을 여러개 이어서 원 모양으로 그릴 수 있을 것이다. 그렇지만 이 방식은 정교하게 하려하면 할수록 더 많은 점들이 필요하다. 여기서는 점 4개 만으로 그릴 수 있는 방법을 정리해 보았다.

우선 그릴 원을 정의해 보자. 구현을 단순하게 하기 위해서 NDC(Normalized Device Coordinates)를 기반으로 해서 아래와 같이 정의해 보았다.

  • 반지름: 0.5
  • 원점좌표: (0.0, 0.0, 0.0)
  • 색깔: 외접하는 사각형의 네 귀퉁이를 빨강, 파랑, 노랑, 초록으로 하여 섞어서 보간

추가적으로 타원이 아닌 동그라미를 그리기 위해서는 그림을 그릴 윈도우의 가로세로 비율이 필요하다. 가로/세로 = 3/2 = 1.5 로 고정시킨다.

일단 원을 그리기 앞서 외접하는 사각형을 그린다. 점들의 좌표와 인덱스는 아래와 같이 정의한다.

let vertices: [GLfloat] = [
    -0.5, -0.5, +0.0, 1.0, 0.0, 0.0,
    +0.5, -0.5, +0.0, 0.0, 1.0, 0.0,
    +0.5, +0.5, +0.0, 0.0, 0.0, 1.0,
    -0.5, +0.5, +0.0, 1.0, 1.0, 0.0,
]
let indices: [GLuint] = [
    0, 1, 2,
    0, 2, 3
]

아래는 Vertex shader고,

layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
out vec3 ourColor;
void main()
{
  gl_Position = vec4(position.x, position.y, position.z, 1.0);
  ourColor = color;
}

Fragment shader는 아래와 같다.

#version 330 core
in vec3 ourColor;
out vec4 color;
void main()
{
  color = vec4(ourColor, 1.0);
}

이걸 가지고 사각형을 그리면 아래와 같이 된다. 풀 소스는 다음 링크를 참고한다:

결과는 아래 그림과 같다.

이를 기반으로 원을 그려보자. 원을 그리는 전략은 각 Fragment에서 원의 중심 좌표로부터 거리를 재서 정의한 반지름 안에 들어오면 해당하는 색을 칠하고, 거리가 너무 멀면 색을 칠하지 않는 것이다. 거리를 재기 위해서 GLSL의 내장 함수인 distance를, 반지름과 비교하여 0아님 1의 값을 내기 위해 step함수를 사용할 것이다.

우선 Vertex shader는 아래와 같다.

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
out vec3 ourColor;
out vec3 ourPosition;
void main()
{
  gl_Position = vec4(position.x, position.y, position.z, 1.0);
  ourColor = color;
  float ratio = 3.0 / 2.0;
  ourPosition = vec3(position.x * ratio, position.y, position.z);
}

그리고 Fragment shader는 아래와 같다.

#version 330 core
in vec3 ourColor;
in vec3 ourPosition;
out vec4 color;
void main()
{
  float radius = 0.5;
  vec3 origin = vec3(0.0);
  float dist = distance(origin, ourPosition);
  float alpha = step(dist, radius);
  color = vec4(ourColor, alpha);
}

그러면 아래와 같은 동그라미를 그릴 수 있다. 근데 원의 가장자리가 찌글찌글한 모양새를 (선호하는 사람도 있겠지만) 불편해 하는 사람도 있을 것이다.

가장자리에 안티알리아스 효과를 주기 위해서 step 함수를 대신하여 smoothstep 함수를 사용할 수 있다. step이 계단이라면 smoothstep은 언덕길이라고 할 수 있겠다. 아래 그림 참고.

smoothstep을 사용하는 Fragment shader는 아래와 같다.

#version 330 core
in vec3 ourColor;
in vec3 ourPosition;
out vec4 color;
void main()
{
  float radius = 0.5;
  vec3 origin = vec3(0.0);
  float dist = distance(origin, ourPosition);
  float delta = 0.01;
  float alpha = smoothstep(dist-delta, dist, radius-delta);
  color = vec4(ourColor, alpha);
}

그리고 최종 결과는 아래와 같다.

풀 소스는 다음 링크를 참고한다: CircleRenderer.swift

참고한 사이트: