-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrender_intersect_cylinder.c
119 lines (111 loc) · 3.69 KB
/
render_intersect_cylinder.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* render_intersect_cylinder.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fvonsovs <fvonsovs@student.42prague.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/31 16:17:51 by fvonsovs #+# #+# */
/* Updated: 2024/09/14 15:10:12 by fvonsovs ### ########.fr */
/* */
/* ************************************************************************** */
#include "minirt.h"
// calculate vars as described in the struct definition
// checks for intersection with the cylinders side
// if no intersection with the cylindrical side, check the caps
int cylinder_intersect(t_ray ray, t_cy *cylinder, float *t)
{
t_cyl_intersect vars;
vars.hit_side = 0;
vars.hit_cap = 0;
vars.dia = cylinder->dia;
vars.oc = vec_sub(ray.orig, cylinder->pos);
vars.cyl_vec = vec_normalize(cylinder->vec);
vars.d_cross_a = vec_cross(ray.dir, vars.cyl_vec);
vars.oc_cross_a = vec_cross(vars.oc, vars.cyl_vec);
vars.a = vec_dot(vars.d_cross_a, vars.d_cross_a);
vars.b = 2.0f * vec_dot(vars.d_cross_a, vars.oc_cross_a);
vars.c = vec_dot(vars.oc_cross_a, vars.oc_cross_a) \
- (cylinder->dia / 2) * (cylinder->dia / 2);
vars.disc = vars.b * vars.b - 4 * vars.a * vars.c;
vars.hit_side = hit_cyl_side(ray, cylinder, &vars, t);
vars.hit_cap = hit_cyl_cap(ray, cylinder, &vars, t);
if (vars.hit_side || vars.hit_cap)
return (1);
else
return (0);
}
int hit_cyl_side(t_ray ray, t_cy *cylinder, t_cyl_intersect *vars, float *t)
{
if (vars->disc >= 0)
{
vars->t0 = (-vars->b - sqrt(vars->disc)) / (2.0f * vars->a);
vars->t1 = (-vars->b + sqrt(vars->disc)) / (2.0f * vars->a);
if (vars->t0 > vars->t1)
vars->t0 = vars->t1;
if (vars->t0 >= 1e-6)
{
vars->hit_point = vec_add(ray.orig, vec_mul(ray.dir, vars->t0));
vars->hit_base = vec_sub(vars->hit_point, cylinder->pos);
vars->proj_l = vec_dot(vars->hit_base, vars->cyl_vec);
if (vars->proj_l >= 0 && vars->proj_l <= cylinder->hth)
{
*t = vars->t0;
return (1);
}
}
}
return (0);
}
int hit_cyl_cap(t_ray ray, t_cy *cylinder, t_cyl_intersect *vars, float *t)
{
t_float_3 top_center;
float t_cap;
top_center = vec_add(cylinder->pos, vec_mul(vars->cyl_vec, cylinder->hth));
if (intersect_disk(ray, top_center, vars, &t_cap))
{
if (!vars->hit_side || t_cap < *t - 1e-6)
{
*t = t_cap;
return (1);
}
}
if (intersect_disk(ray, cylinder->pos, vars, &t_cap))
{
if (!vars->hit_side || t_cap < *t - 1e-6)
{
*t = t_cap;
return (1);
}
}
return (0);
}
// calculate denominator for intersection with the plane of the disk
// calculate the intersection point with the plane
// if the intersection is in the point of the ray, calculate the point
// check if we are within the diameter of the disk
int intersect_disk(t_ray ray, t_float_3 disk_center, \
t_cyl_intersect *vars, float *t)
{
t_float_3 vec;
t_float_3 hit_point;
float denom;
float t_temp;
denom = vec_dot(ray.dir, vars->cyl_vec);
if (fabs(denom) > 1e-4)
{
vec = vec_sub(disk_center, ray.orig);
t_temp = vec_dot(vec, vars->cyl_vec) / denom;
if (t_temp >= 1e-6)
{
hit_point = vec_add(ray.orig, vec_mul(ray.dir, t_temp));
if (vec_length(vec_sub(hit_point, disk_center)) \
<= (vars->dia / 2.0f))
{
*t = t_temp;
return (1);
}
}
}
return (0);
}