miniRT 실습 - 06. Sphere Normals and Hittable

jkeum·2021년 2월 7일
0

miniRT

목록 보기
6/7

출처:
Ray Tracing in One Weekend - Shading with Surface Normals
Github - GaepoMorningEagles/mini_raytracing_in_c


Normals and Hittable


Simplifying the Ray-Sphere Intersection Code

이전에 작성한 코드에서 광선과 구의 교점을 구하는 방정식의 b가 인수로 2를 가지고 있으므로 짝수 근의 공식을 사용할 수 있다. 연산을 줄이기 위해 짝수 근의 공식을 사용하여 bhalf_b로 바꿔서 계산했다.


An Abstraction for Hittable Objects

우리는 여러 객체를 나타내는 것이 목표이다. 화면에 객체가 여러 개 있다면 광선하고 만날 수도 있고 만나지 않을 수도 있으며, 광선과 객체의 교점을 구하는 방정식에서는 만나지만 그 앞을 다른 객체가 가로막는다면 실제로는 만나지 않을 수도 있다. 이렇게 다양한 경우를 고려해야 하므로 hit 여부에 대한 정보를 저장하는 hit_record 구조체를 만들었다.
이 구조체에는 광선이 객체와 만나는 점 p, 그 점에서의 법선벡터 normal, 그 점에서의 근 t, 현재 광선에서의 t값으로 가능한 범위 tmintmax, 그리고 광선이 객체의 겉면과 만났는지 여부를 저장하는 front_face 변수가 선언되어 있다. 이 구조체를 이용해서 광선이 구와 어디서 만나는지를 확인한다.

이전에는 판별식이 0보다 크면 그때의 근을 반환했는데, 이제는 hit 여부만 판단하므로 TRUE 혹은 FALSE만 반환한다. 판별식이 0보다 작으면 FALSE를 반환하고, 판별식이 0보다 크거나 같으면 root에 작은 근을 넣어준다. 그리고 그 rootrec->tminrec->tmax 사이에 있는지를 확인한다.(rechit_record 구조체 변수) 아직은 하나의 객체(구)만 존재하기 때문에 rec->tmin0, rec->tmaxINFINITY로 맨 처음에 초기화할 때 넣어준 값 그대로이다.
하지만 공간에 여러 개의 객체가 있고, 하나의 광선이 여러 객체를 지날 때 만약 앞에 있는 객체의 hit 여부를 먼저 검사하고 그 다음으로 뒤에 있는 객체를 검사한다면, 뒤의 객체를 검사할 때는 rec->tmax의 값이 앞에서 만난 객체에서의 hit point, rec->t로 바뀌어 있을 것이다. 따라서 그때의 root값이 rec->tmax보다 크기 때문에 if문 안으로 들어가서 root가 큰 근으로 바뀌고 다시 검사를 한다.
만약 카메라가 객체의 내부에 존재한다면, 광선이 지나는 두 점(근) 중에서 작은 근일 때의 점은 카메라 뒤쪽에 위치할 것이다. 그 점을 검사할 때는 그 때의 root값이 rec->tmin보다 작기 때문에 if문 안으로 들어가서 root가 큰 근으로 바뀌고 다시 검사를 한다.

FALSE가 리턴되지 않고 rec->tminrec->tmax 사이에 root가 존재하게 되면, 이제 hit_record 구조체의 각 변수에 해당하는 값을 넣어준다. rec->t에는 root를, rec->p에는 ray_at()을 이용하여 광선의 시작점에서 hit 한 그 점을 향하는 단위벡터에 root를 곱해서 더해준 값을 저장하여 hit point 의 좌표를 저장한다. 그리고 rec->normal에는 정규화된 법선벡터를 넣어준다.


Front Faces vs Back Faces

광선이 객체의 외부에서 구와 교차하는 경우, 법선은 광선을 향한다.(광선의 방향과 법선의 방향이 반대임) 광선이 객체의 내부에서 교차하면 법선은 광선의 방향을 따른다.(광선의 방향과 법선의 방향이 같음) 우리는 법선이 항상 광선을 향하도록, 법선과 광선이 서로 마주보는 방향으로 만들어야 한다. 광선이 객체의 외부에 있으면 법선이 바깥쪽을 가리키고, 객체의 내부에 있으면 법선이 안쪽을 가리키게 하는 것이다.

이를 확인하려면 광선과 법선의 벡터를 내적해서 그 값이 양수인지 음수인지를 확인하면 된다. cosθ\cos \theta 값은 0˚~90˚에서는 양수이고 90˚~180˚에서는 음수이므로 두 벡터의 내적값이 양수이면 광선이 객체의 내부에서 교차한 경우이고, 음수이면 외부에서 교차한 경우이다.

우리 코드에서는 rec->front_face에 광선과 법선벡터를 내적한 값이 0보다 작은지를 담아주었다. 0보다 작으면 참이고 0보다 크거나 같으면 거짓이다. 그리고 rec->normal에 만약 rec->front_face가 참이면 그대로 냅두고, 거짓이면 -1을 곱해서 법선벡터의 방향을 반대로 바꿔준다.


Result Image

profile
It's me, jkeum!

0개의 댓글