-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsphere.h
150 lines (124 loc) · 4.42 KB
/
sphere.h
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#ifndef SPHERE_H
#define SPHERE_H
#include "color.h"
#include "common.h"
#include "hittable.h"
#include "material.h"
#include "point3.h"
#include "ray.h"
typedef struct {
t_point3 center;
float radius;
t_material material;
} t_sphere;
__host__ __device__ t_sphere sphere_new(
t_point3 center,
float radius,
t_material material
) {
return (t_sphere) { center, radius, material };
}
// Returns hit point and normal vector of a ray with a sphere.
// For the details of how this calculation is performed, refer to the sources
// in README.md
__host__ void h_sphere_hit(
t_hit_result *result,
t_ray *r,
t_sphere s,
float t_min,
float t_max
) {
t_vec3 oc = subtract(s.center, r->origin);
float a = squared_length(r->direction);
float h = dot(r->direction, oc);
float c = squared_length(oc) - (s.radius)*(s.radius);
float discriminant = h*h - a*c;
// discriminant < 0 -> no real solutions -> no intersections
if (discriminant < 0) {
result->did_hit = false;
return;
}
// Check for each of the intersections if it lies in the acceptable range
float sqrt_discriminant = sqrt(discriminant);
float root = (h - sqrt(discriminant)) / a;
// First root not in the acceptable range (t_min, t_max)
if (root <= t_min || root >= t_max) {
root = (h + sqrt(discriminant)) / a;
// None of the two roots is in the acceptable range (t_min, t_max)
if (root <= t_min || root >= t_max) {
result->did_hit = false;
return;
}
}
// Calculate intersection
result->did_hit = true;
result->t = root;
ray_at(&(result->p), *r, result->t);
// Calculating the normal vector with this formula, it always points
// outwards
result->normal = divide(subtract(result->p, s.center), s.radius);
// In order to calculate wether we hit an inside or ourside face, we can
// compute the dot product with the (OUTSIDE-POINTING!!!) normal
result->front_face = (dot(r->direction, result->normal) < 0.0F);
// TOTO switch to just memorizing the sphere object
result->albedo = s.material.albedo;
result->surface_material = s.material.type;
result->fuzz = s.material.fuzz;
result->refraction_index = s.material.refraction_index;
// If the ray hits an object from inside (like in dielectrics, I need to
// invert the direction of the normal
if (!result->front_face) {
result->normal = scale(result->normal, -1.0F);
}
}
__device__ void d_sphere_hit(
t_hit_result *result,
t_ray *r,
t_sphere s,
float t_min,
float t_max
) {
t_vec3 oc = subtract(s.center, r->origin);
float a = squared_length(r->direction);
float h = dot(r->direction, oc);
float c = squared_length(oc) - (s.radius)*(s.radius);
float discriminant = h*h - a*c;
// discriminant < 0 -> no real solutions -> no intersections
if (discriminant < 0) {
result->did_hit = false;
return;
}
// Check for each of the intersections if it lies in the acceptable range
float sqrt_discriminant = sqrt(discriminant);
float root = (h - sqrt_discriminant) / a;
// First root not in the acceptable range (t_min, t_max)
if (root <= t_min || root >= t_max) {
root = (h + sqrt_discriminant) / a;
// None of the two roots is in the acceptable range (t_min, t_max)
if (root <= t_min || root >= t_max) {
result->did_hit = false;
return;
}
}
// Calculate intersection
result->did_hit = true;
result->t = root;
ray_at(&(result->p), *r, result->t);
// Calculating the normal vector with this formula, it always points
// outwards
result->normal = divide(subtract(result->p, s.center), s.radius);
// In order to calculate wether we hit an inside or ourside face, we can
// compute the dot product with the (OUTSIDE-POINTING!!!) normal
result->front_face = (dot(r->direction, result->normal) < 0.0F);
// TOTO switch to just memorizing the sphere object
result->albedo = s.material.albedo;
result->surface_material = s.material.type;
result->fuzz = s.material.fuzz;
result->refraction_index = s.material.refraction_index;
// If the ray hits an object from inside (like in dielectrics, I need to
// invert the direction of the normal
if (!result->front_face) {
result->normal = scale(result->normal, -1.0F);
}
}
#endif