Search
Duplicate

mini_raytracing_in_c (7) 오브젝트

간단소개
42seoul_miniRT 실습 교재
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
42seoul
Scrap
태그
mlx
튜토리얼
9 more properties
궁금한 내용, 오타, 수정사항, 문의사항은 아래 깃허브 이슈 혹은 노션 블록 댓글로 달아주시면 바로 확인해드립니다! 도움이 되셨다면 아래 링크를 통해 한번 꾹 눌러주세요

7. 오브젝트

이번 장에서는 여러가지 오브젝트(도형)들을 하나의 오브젝트로 다루기 위해 object라는 리스트를 만드려고 한다.

7.1. 실습목표

object 리스트에 대해 알아보고 리스트를 만든다. 이 전에 만든 함수들을 object 리스트에 맞게 수정한다.

7.2. object

6단원까지는 sphere 하나의 object를 구현하고 저장하였지만 앞으로 여러가지의 object를 추가할 수 있게 하기 위해서 코드의 수정이 필요하다. 우선 여러가지의 object를 저장할 수 있어야하고 그 object들을 한번에 가지고 다닐 수 있어야한다. ray는 여러개의 object 중 가장 가까이에 있는 object에 히트를 해야한다.
우리는 object라는 리스트를 만들어 각 도형의 정보를 저장할 것이다. 그리고 기존에 sphere에만 적용 가능했던 함수들을 조금씩 손봐줄 예정이다.
먼저 다음과 같은 구조체를 만들어서 structures.h에 추가해주자.
... // 3. 오브젝트 구조체 // 추가 typedef struct s_object t_object; // 추가 끝 typedef struct s_sphere t_sphere; ... # define FALSE 0 # define TRUE 1 // 추가 typedef int t_object_type; # define SP 0 // 추가 끝 ... // 오브젝트 구조체 // 추가 struct s_object { t_object_type type; void *element; void *next; }; // 추가 끝 #endif
C
복사
Code1 : [miniRT/include/structures.h]
Object 리스트 안에 type은 object 리스트를 봤을 때 현재 리스트가 가리키는 도형이 무엇인지 바로 알 수 있기 위해 추가하였다. 그리고 우리는 sphere라는 도형은 매크로 SP로 type을 지정했다. 리스트의 element에 각 도형의 데이터를 저장할 것이다.

7.3. object 적용

object 리스트를 구현했으니 hit함수를 추가하여 object를 받을 수 있게 하자. 그리고 ray_color와 hit_sphere도 t_sphere에만 한정되지 않는 함수로 바꾸어 주자.
t_point3 ray_at(t_ray *ray, double t); // 추가 t_color3 ray_color(t_ray *ray, t_object *world); // 수정. // trace/hit/ t_bool hit(t_object *obj, t_ray *ray, t_hit_record *rec); t_bool hit_obj(t_object *obj, t_ray *ray, t_hit_record *rec); t_bool hit_sphere(t_object *world, t_ray *ray, t_hit_record *rec); // 추가 끝 ...
C
복사
Code2 : [miniRT/include/trace.h]
// 추가 #include "trace.h" t_bool hit(t_object *world, t_ray *ray, t_hit_record *rec) { t_bool hit_anything; t_hit_record temp_rec; temp_rec = *rec; // temp_rec의 tmin, tmax 값 초기화를 위해. hit_anything = FALSE; while(world) { if (hit_obj(world, ray, &temp_rec)) { hit_anything = TRUE; temp_rec.tmax = temp_rec.t; *rec = temp_rec; } world = world->next; } return (hit_anything); } // hit_obj는 오브젝트 타입에 맞는 hit함수로 연결해주는 관문 t_bool hit_obj(t_object *world, t_ray *ray, t_hit_record *rec) { t_bool hit_result; hit_result = FALSE; if (world->type == SP) hit_result = hit_sphere(world, ray, rec); //hit_sphere의 첫번째 인자도 t_sphere *에서 t_object *로 수정해주자. return (hit_result); } // 추가 끝
C
복사
Code3 : [miniRT/src/trace/hit/hit.c]
각 object를 순회하며 ray를 맞았는지 확인하기 위하여 hit라는 함수를 만들어 준다. 우리는 여러가지 오브젝트가 존재할 때에 더 가까이 있는 오브젝트를 히트해야한다. 그러므로 어떠한 오브젝트에 히트하면 tmax를 히트한 t로 바꾸어 그 다음 오브젝트를 검사할 때에 더 멀리 있는 오브젝트일 경우 히트가 안되게 했다.
hit_obj에서는 리스트에 어떤 object가 저장되어 있는지 확인한 후 각각의 object에 맞는 함수를 실행할 수 있게 분기해주었다.
각 sphere와 object를 초기화 할 수 있는 함수를 만들어 보자.
// 제거 #include "structures.h" t_sphere sphere(t_point3 center, double radius) { t_sphere sp; sp.center = center; sp.radius = radius; sp.radius2 = radius * radius; return (sp); } // 제거 끝 // 추가 #include "scene.h" t_object *object(t_object_type type, void *element) { t_object *new; if (!(new = (t_object *)malloc(sizeof(t_object)))) return (NULL); new->type = type; new->element = element; new->next = NULL; return (new); } t_sphere *sphere(t_point3 center, double radius) { t_sphere *sp; if(!(sp = (t_sphere *)malloc(sizeof(t_sphere)))) return (NULL); sp->center = center; sp->radius = radius; sp->radius2 = radius * radius; return (sp); } // 추가 끝
C
복사
Code4: [miniRT/src/scene/object_create.c]
object함수는 리스트에 추가할 object를 만드는 생성자이다. 그리고 sphere는 sphere의 데이터를 저장하는 함수이다. sphere함수로 만든 구조체가 object의 element에 들어가는 것이다. object함수와 sphere함수 모두 장면을 구성하는 함수이므로 scene.h 파일에 추가해주자.
... // 추가 t_object *object(t_object_type type, void *element); // 추가 끝 t_sphere *sphere(t_point3 center, double radius);
C
복사
Code5: [miniRT/include/scene.h]
이제 object함수로 만든 오브젝트들을 오브젝트 리스트에 추가할 함수들을 만들어주자.
#include "utils.h" void oadd(t_object **list, t_object *new) { t_object *cur; if (*list == NULL) { *list = new; return ; } cur = *list; while (cur->next) cur = cur->next; cur->next = new; } t_object *olast(t_object *list) { if (list == NULL) return (NULL); while (list->next) list = list->next; return (list); }
C
복사
Code6: [miniRT/src/utils/object_utils.c]
각각 리스트 추가, 리스트의 마지막으로 이동하는 함수들이다. 위 함수들을 utils.h에 추가해주자.
... // 추가 // 오브젝트 유틸리티 void oadd(t_object **list, t_object *new); t_object *olast(t_object *list); // 추가 끝 #endif
C
복사
Code7: [miniRT/include/utils.h]
t_sphere를 바로 사용하던 ray_color를 수정해주자.
//광선이 최종적으로 얻게된 픽셀의 색상 값을 리턴. // 수정 t_color3 ray_color(t_ray *ray, t_object *world) // 수정 끝 { double t; t_vec3 n; ... rec.tmin = 0; rec.tmax = INFINITY; //광선이 구에 적중하면(광선과 구가 교점이 있고, 교점이 카메라 앞쪽이라면!) // 수정 if (hit(world, ray, &rec)) // 수정 끝 return (vmult(vplus(rec.normal, color3(1, 1, 1)), 0.5));
C
복사
Code8: [miniRT/src/trace/ray/ray.c]
sphere구조체를 받던 함수를 object를 받게 바꾸었다.
바뀐 구조를 적용하여 main을 수정해보자.
t_canvas canv; t_camera cam; t_ray ray; // 제거 t_sphere sp; // 제거 끝 // 추가 t_object *world; // 추가 끝 //Scene setting; canv = canvas(400, 300); cam = camera(&canv, point3(0, 0, 0)); // 제거 sp = sphere(point3(0, 0, -5), 2); // 제거 끝 // 추가 world = object(SP, sphere(point3(-2, 0, -5), 2)); // world 에 구1 추가 oadd(&world, object(SP, sphere(point3(2, 0, -5), 2))); // world 에 구2 추가 oadd(&world, object(SP, sphere(point3(0, -1000, 0), 990))); // world 에 구3 추가 // 추가 끝 // 랜더링 ... //ray from camera origin to pixel ray = ray_primary(&cam, u, v); // 제거 pixel_color = ray_color(&ray, &sp); // 제거 끝 // 추가 pixel_color = ray_color(&ray, world); // 추가 끝 write_color(pixel_color);
C
복사
Code9: [miniRT/src/main.c]
기존 sphere를 추가하는 부분에서 object를 추가하고 그 곳에 sphere를 추가하는 코드로 변경했다.
지금까지 코드를 수정한 결과는 다음과 같다(이미지1).
이미지1

NEXT