컴퓨터 그래픽스/Ray Tracing

Ray Tracing (1) - 구와 직선 충돌의 원리

SL123 2024. 6. 29. 16:36

안녕하세요.

오늘은 Ray Tracing을 이용한 구와 직선 충돌의 원리에 대해 알아보겠습니다.

 

여기에 우리가 보는 모니터 즉, 눈이 있다고 가정하겠습니다.

역방향 광 추적에서는 각각 픽셀로부터 역방향 광선(Ray)을 쏴줍니다.

(한 픽셀에서 여러 개의 광선을 쏘는 방법도 있습니다.)

 

Ray가 가다가 구에 부딪힙니다.

부딪힌 지점을 계산할 수 있습니다.

 

광선이 쭉 다가 물체에 부딪혔다고 가정해봅니다.

충돌된 부분을 계산해 물체의 색을 가져옵니다.

이 색으로 픽셀의 색을 결정합니다.

 

그래서 이 눈으로 픽셀을 볼 때 모든 픽셀들의 색을 결정하면

이 위치에 물체가 그려졌구나 하는 것을 알 수 있습니다.

 

 

눈이 있고 2차원의 x, y 좌표가 있는 모니터가 있습니다.

이 안에 x,y,z 3차원의 가상의 공간과 가상의 물체를 정의합니다.

 

Z가 위 그림처럼 뒤 쪽으로 하는 것을 왼손 좌표계

앞 쪽(눈 쪽)으로 튀어나는 것을 오른손 좌표계라고 부릅니다.

 

왼손 좌표계 -> DirectX

오른손 좌표계 -> OpenGL

 

픽셀을 시작점으로 이 모니터에 수직방향으로 Ray(광선) 을 쏴줍니다.

그로부터 색을 결정합니다.

 

이 Ray의 방향은 Z Direction(방향)으로 이동합니다.

   = vec3(0.0f,0.0f,1.0f); 

 

광선의 시작점으로부터 충돌지점까지의 거리가 음수라면

충돌을 하지 않았다는 의미이다.

 

그리고 만약 양수라면 Light를 통해 픽셀의 색을 어떻게 결정하는 지에 따라

다르게 나타날 수 있습니다.

 

3차원 공간에 구가 있을 때 Ray와 구의 충돌은 3가지가 있습니다.

1. 충돌을 하지 않을 때

2. 처음 충돌하고 나올 때 한번 더 충돌하는 경우

3. 딱 가장자리에 맞아 충돌을 한번만 맞을 때 

 

 -> 3번 이상 충돌하는 것은 수학자들이 증명했기 때문에 없다고

했으니까 만약 틀리다면 수학자를 비판해주세요.

 

 

||x - c|| ^ 2 = r ^ 2 는

절대값(구 표면에 있는 한 점(x) - 구의 중앙(c)) 의 2제곱 = 반지름의 2제곱입니다.

 = dot( ray.start - sphere.center , ray.start - sphere.center ) - radius * radius;

 

x = o + du 는

광선 위에 있는 한 점 = ray의 시작점 +  거리(distance)  * 광선의 방향(unit vector)

dot(ray.dir, ray.start - this->center);

 

u 방향으로 거리를 얼마나 가면(d) 충돌하는 지 알아야합니다.

(d를 찾아야 한다.) 

 

d(거리)만큼 갔더니 구 표면에 있는 한 점(x)과 광선 위에 있는 한 점(x)이 

같아진다라는 것을 찾아야 합니다.

 

 

구 표면에 있는 한 점(x) == 광선 위에 있는 한 점(x) 를 찾아야 한다라는

결론이 나왔으니 ||x - c|| ^ 2 = r ^ 2(구의 방정식) 의 값을 

|| o + du  - c|| ^ 2 = r ^ 2 로 바꿔주도록 하죠.

 

식을 전개해서 d를 구해보도록 합시다.

|| (o + du) - c || ^ 2 = r ^ 2

(o + du - c) · (o + du - c)  = r ^ 2 

 

(o · o) + (du · o) - (o · c) + (du · o) + (d^2u · u) - (du · c) - (c · o) - (du · c) + (c · c) = r ^ 2 

 

d^2(2제곱) 과 d가 붙어있는 항목을 다시 나눠서 식을 전개하고

o와c를 다시 전개해보죠.

 

d^2(u ·u) + 2d(u · o - u · c) + o · o - 2o · c + c · c - r ^ 2 = 0

d^2(u · u) + 2d(u ·(o - c)) + (o - c) · (o - c)

 

 

(o−c)^2 은 제곱의 공식을 사용하여 다음과 같이 전개할 수 있습니다:

(o−c) ^ 2 =o ^ 2 − 2o⋅c + c ^ 2

(oc)  (oc) = (oc) ^ 2 이므로 위와 같은 식이 전개됩니다.

 

여기서 이제 o 와 c를 알면 d를 구할 수 있습니다.

 

(u · u) -> 스칼라 값

(u · (o - c)) -> 벡터 · (벡터 - 백터) -> 스칼라값

(o - c) · (o - c) -> 벡터 · 벡터 -> 스칼라값

 

d^2 * 스칼라 + 2d * 스칼라 + 스칼라

 -> 최적의 해를 이용해 d값을 근의 공식을 이용해 값을 계산할 수 있습니다.

 

 

ad^2 + db + c = 0

 

a = u  · u = ||u|| ^ 2 -> a는 unit vector(1로 가정) -> 곱해도 똑같음 -> 식에서 제거

b = 2[u · (o - c)]

c = (o - c) · (o - c) - r ^ 2 = ||o - c|| ^ 2 - r ^ 2

 

식이 복잡해보일 수 있는데 u가 1이라고 가정하고 식을 지워보면 생각보다 어렵지 않다.

 

 

역 삼각형은 나블라라는 것인데

수학자의 마음을 이해할 수 가 없다.. 이런 것을 쓰다니

 

u 위에 ^(hat) 이 있는데 이것은 유닛 벡터이다.

 

d1 = -[유닛 벡터 · (o - c)] + root(나블라)

d2 = -[유닛 벡터 · (o - c)] - root(나블라)

 

if(나블라 < 0) -> 한 점도 충돌하지 않음

if(나블라 == 0) -> 한 점만 충돌함

if(나블라 > 0) -> 두 점이 충돌함

 

나블라가 0 이상이라면 충돌위치를 정확하게 계산 가능

계산할 때 주의해야 할 점은 물체가 뒤에 있다면 그리면 안된다.(d가 음수면 충돌 X)

 

0 보다 작은 값이라면 충돌하지 않는다.

 

d1과 d2 중에 작은 것이 d(거리)의 값이다.

거리는 구했으니 충돌된 지점의 수직인 normal 과 충돌된 position인 point을 구해주죠.

 

point = ray의 시작점 + ray의 방향 * 거리

normal = normalize(point - center(원의 가운데))

 

 

이렇게 해서 d1과 d2 둘 다 음수가 아니라면 충돌된 물체의 재질이 그려지는 원리를 알아보았습니다.

다음은 조명 효과의 원리에 대해 알아보겠습니다.