Ray Tracing (1) - 구와 직선 충돌의 원리
안녕하세요.
오늘은 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
(o−c) ⋅ (o−c) = (o−c) ^ 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 둘 다 음수가 아니라면 충돌된 물체의 재질이 그려지는 원리를 알아보았습니다.
다음은 조명 효과의 원리에 대해 알아보겠습니다.