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