hit.c
1 /* ************************************************************************** */ 2 /* */ 3 /* ::: :::::::: */ 4 /* hit.c :+: :+: :+: */ 5 /* +:+ +:+ +:+ */ 6 /* By: gychoi <gychoi@student.42seoul.kr> +#+ +:+ +#+ */ 7 /* +#+#+#+#+#+ +#+ */ 8 /* Created: 2023/05/12 18:11:47 by gychoi #+# #+# */ 9 /* Updated: 2023/05/18 20:57:37 by gychoi ### ########.fr */ 10 /* */ 11 /* ************************************************************************** */ 12 13 #include "pracrt.h" 14 #include "hit.h" 15 16 t_hit hit(double d, t_point3 point, t_vec3 normal) 17 { 18 t_hit hit; 19 20 hit.d = d; 21 hit.point = point; 22 hit.normal = normal; 23 return (hit); 24 } 25 26 t_hit intersect_ray_collision_sphere(t_ray ray, t_sphere *sphere) 27 { 28 t_hit hitobj; 29 double b; 30 double c; 31 double nabla; 32 double d1; 33 double d2; 34 35 hitobj = hit(-1.0f, point3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f)); 36 b = 2.0f * vdot(ray.dir, vsub(ray.start, sphere->center)); 37 c = vdot(vsub(ray.start, sphere->center), vsub(ray.start, sphere->center)) - sphere->radius * sphere->radius; 38 nabla = b * b / 4.0f - c; 39 40 if (nabla >= 0.0) 41 { 42 d1 = -b / 2.0 + sqrt(nabla); 43 d2 = -b / 2.0 - sqrt(nabla); 44 hitobj.d = fmin(d1, d2); 45 if (hitobj.d < 0.0f) 46 hitobj.d = fmax(d1, d2); 47 hitobj.point = vadd(ray.start, vmults(ray.dir, hitobj.d)); 48 hitobj.normal = vunit(vsub(hitobj.point, sphere->center)); 49 } 50 return (hitobj); 51 } 52 53 int check_ray_collision_triangle(t_ray ray, t_triangle *triangle, t_point3 *point, t_point3 *face_normal, double *t, double *u, double *v) 54 { 55 t_vec3 cross0; 56 t_vec3 cross1; 57 t_vec3 cross2; 58 double area0; 59 double area1; 60 double area2; 61 double area_sum; 62 63 // division zero 주의 64 *face_normal = vunit(vcross(vsub(triangle->v1, triangle->v0), vsub(triangle->v2, triangle->v0))); 65 if (vdot(vmults(ray.dir, -1), *face_normal) < 0.0f) 66 return (FALSE); 67 if (fabs(vdot(ray.dir, *face_normal)) < EPSILON) 68 return (FALSE); 69 *t = (vdot(triangle->v0, *face_normal) - vdot(ray.start, *face_normal)) / (vdot(ray.dir, *face_normal)); 70 if (*t < 0.0f) 71 return (FALSE); 72 *point = vadd(ray.start, vmults(ray.dir, *t)); 73 cross0 = vcross(vsub(*point, triangle->v2), vsub(triangle->v1, triangle->v2)); 74 cross1 = vcross(vsub(*point, triangle->v0), vsub(triangle->v2, triangle->v0)); 75 cross2 = vcross(vsub(triangle->v1, triangle->v0), vsub(*point, triangle->v0)); 76 if (vdot(cross0, *face_normal) < 0.0f) 77 return (FALSE); 78 if (vdot(cross1, *face_normal) < 0.0f) 79 return (FALSE); 80 if (vdot(cross2, *face_normal) < 0.0f) 81 return (FALSE); 82 area0 = vlen(cross0) * 0.5f; 83 area1 = vlen(cross1) * 0.5f; 84 area2 = vlen(cross2) * 0.5f; 85 area_sum = area0 + area1 + area2; 86 87 *u = area0 / area_sum; 88 *v = area1 / area_sum; 89 90 return (TRUE); 91 } 92 93 t_hit intersect_ray_collision_triangle(t_ray ray, t_triangle *triangle) 94 { 95 t_hit hitobj; 96 t_point3 point; 97 t_point3 face_normal; 98 double t; 99 double u; 100 double v; 101 102 point = point3(0.0f, 0.0f, 0.0f); 103 face_normal = point3(0.0f, 0.0f, 0.0f); 104 t = 0.0f; 105 u = 0.0f; 106 v = 0.0f; 107 hitobj = hit(-1.0f, point3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f)); 108 if (check_ray_collision_triangle(ray, triangle, &point, &face_normal, &t, &u, &v)) 109 { 110 hitobj.d = t; 111 hitobj.point = point; 112 hitobj.normal = face_normal; 113 hitobj.uv = v2add(v2add(v2mults(triangle->uv0, u), v2mults(triangle->uv1, v)), v2mults(triangle->uv2, (1.0f - u - v))); 114 //printf("%f, %f, %f\n", hitobj.normal.x, hitobj.normal.y, hitobj.normal.z); 115 } 116 return (hitobj); 117 } 118 119 t_hit intersect_ray_collision_square(t_ray ray, t_square *square) 120 { 121 t_hit hit1; 122 t_hit hit2; 123 124 hit1 = intersect_ray_collision_triangle(ray, square->triangle1); 125 hit2 = intersect_ray_collision_triangle(ray, square->triangle2); 126 if (hit1.d >= 0.0f && hit2.d >= 0.0f) 127 { 128 if (hit1.d < hit2.d) 129 return (hit1); 130 else 131 return (hit2); 132 } 133 else if (hit1.d >= 0.0f) 134 return (hit1); 135 else 136 return (hit2); 137 } 138 139 t_hit find_closest_collision(t_ray ray, t_obj_list *list) 140 { 141 t_hit closest_hit; 142 t_hit hitobj; 143 t_hit hitobj2; 144 t_sphere *sphere; 145 t_triangle *triangle; 146 t_square *square; 147 double closest; 148 149 closest_hit = hit(-1.0f, point3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f)); 150 closest = INFINITY; 151 while (list) 152 { 153 if (list->type == SP) 154 { 155 sphere = list->element; 156 hitobj = intersect_ray_collision_sphere(ray, sphere); 157 if (hitobj.d >= 0.0f) 158 { 159 if (hitobj.d < closest) 160 { 161 closest = hitobj.d; 162 closest_hit = hitobj; 163 closest_hit.obj = sphere->obj; 164 } 165 } 166 } 167 if (list->type == TR) 168 { 169 triangle = list->element; 170 hitobj = intersect_ray_collision_triangle(ray, triangle); 171 if (hitobj.d >= 0.0f) 172 { 173 if (hitobj.d < closest) 174 { 175 closest = hitobj.d; 176 closest_hit = hitobj; 177 closest_hit.obj = triangle->obj; 178 } 179 } 180 } 181 if (list->type == SQ) 182 { 183 square = list->element; 184 hitobj = intersect_ray_collision_square(ray, square); 185 if (hitobj.d >= 0.0f) 186 { 187 if (hitobj.d < closest) 188 { 189 closest = hitobj.d; 190 closest_hit = hitobj; 191 closest_hit.obj = square->obj; 192 closest_hit.uv = hitobj.uv; 193 } 194 } 195 } 196 list = list->next; 197 } 198 return (closest_hit); 199 } 200