rev |
line source |
nuclear@16
|
1 #include <math.h>
|
nuclear@4
|
2 #include <float.h>
|
nuclear@45
|
3 #include <gmath/gmath.h>
|
nuclear@4
|
4 #include "geomobj.h"
|
nuclear@41
|
5 #include "erebus_impl.h"
|
nuclear@4
|
6
|
nuclear@4
|
7 static LambertRefl lambert;
|
nuclear@4
|
8
|
nuclear@4
|
9 GeomObject::GeomObject()
|
nuclear@4
|
10 {
|
nuclear@4
|
11 brdf = &lambert;
|
nuclear@4
|
12 }
|
nuclear@4
|
13
|
nuclear@4
|
14 ObjType GeomObject::get_type() const
|
nuclear@4
|
15 {
|
nuclear@4
|
16 return ObjType::geom;
|
nuclear@4
|
17 }
|
nuclear@4
|
18
|
nuclear@4
|
19 bool GeomObject::intersect(const Ray &ray, RayHit *hit) const
|
nuclear@4
|
20 {
|
nuclear@4
|
21 return false;
|
nuclear@4
|
22 }
|
nuclear@4
|
23
|
nuclear@41
|
24 Vector3 GeomObject::gen_surface_point() const
|
nuclear@41
|
25 {
|
nuclear@41
|
26 return Vector3(0, 0, 0);
|
nuclear@41
|
27 }
|
nuclear@41
|
28
|
nuclear@8
|
29 Vector3 GeomObject::calc_normal(const RayHit &hit) const
|
nuclear@8
|
30 {
|
nuclear@8
|
31 // when you look at singularities, the singularities always look back at you :)
|
nuclear@17
|
32 return -(hit.local_ray.dir).normalized();
|
nuclear@8
|
33 }
|
nuclear@8
|
34
|
nuclear@8
|
35 Vector3 GeomObject::calc_tangent(const RayHit &hit) const
|
nuclear@8
|
36 {
|
nuclear@8
|
37 return Vector3(1, 0, 0); // whatever...
|
nuclear@8
|
38 }
|
nuclear@8
|
39
|
nuclear@8
|
40 Vector2 GeomObject::calc_texcoords(const RayHit &hit) const
|
nuclear@8
|
41 {
|
nuclear@8
|
42 return Vector2();
|
nuclear@8
|
43 }
|
nuclear@8
|
44
|
nuclear@4
|
45 // --- class Sphere ---
|
nuclear@4
|
46
|
nuclear@4
|
47 bool Sphere::intersect(const Ray &ray, RayHit *hit) const
|
nuclear@4
|
48 {
|
nuclear@4
|
49 // assumes center is the origin and radius is 1
|
nuclear@4
|
50 float a = dot_product(ray.dir, ray.dir);
|
nuclear@4
|
51 float b = 2.0 * dot_product(ray.dir, ray.origin);
|
nuclear@4
|
52 float c = dot_product(ray.origin, ray.origin) - 1.0;
|
nuclear@4
|
53
|
nuclear@4
|
54 float d = b * b - 4.0 * a * c;
|
nuclear@43
|
55 if(d < 1e-5) return false;
|
nuclear@4
|
56
|
nuclear@4
|
57 float sqrt_d = sqrt(d);
|
nuclear@4
|
58 float t0 = (-b + sqrt_d) / (2.0 * a);
|
nuclear@4
|
59 float t1 = (-b - sqrt_d) / (2.0 * a);
|
nuclear@4
|
60
|
nuclear@43
|
61 if(t0 < 1e-5) t0 = t1;
|
nuclear@43
|
62 if(t1 < 1e-5) t1 = t0;
|
nuclear@4
|
63 float t = t0 < t1 ? t0 : t1;
|
nuclear@43
|
64 if(t < 1e-5) return false;
|
nuclear@4
|
65
|
nuclear@4
|
66 if(hit) {
|
nuclear@4
|
67 hit->dist = t;
|
nuclear@4
|
68 hit->obj = this;
|
nuclear@4
|
69 hit->subobj = 0;
|
nuclear@4
|
70 }
|
nuclear@4
|
71 return true;
|
nuclear@4
|
72 }
|
nuclear@4
|
73
|
nuclear@41
|
74 Vector3 Sphere::gen_surface_point() const
|
nuclear@41
|
75 {
|
nuclear@41
|
76 return sphrand(1.0);
|
nuclear@41
|
77 }
|
nuclear@41
|
78
|
nuclear@8
|
79 Vector3 Sphere::calc_normal(const RayHit &hit) const
|
nuclear@8
|
80 {
|
nuclear@17
|
81 Vector3 pt = hit.local_ray.origin + hit.local_ray.dir * hit.dist;
|
nuclear@8
|
82 return pt.normalized();
|
nuclear@8
|
83 }
|
nuclear@8
|
84
|
nuclear@8
|
85 static inline Vector3 sphvec(float u, float v)
|
nuclear@8
|
86 {
|
nuclear@8
|
87 float theta = u * M_PI * 2.0;
|
nuclear@8
|
88 float phi = v * M_PI;
|
nuclear@8
|
89
|
nuclear@8
|
90 return Vector3(sin(theta) * sin(phi), cos(phi), cos(theta) * sin(phi));
|
nuclear@8
|
91 }
|
nuclear@8
|
92
|
nuclear@8
|
93 Vector3 Sphere::calc_tangent(const RayHit &hit) const
|
nuclear@8
|
94 {
|
nuclear@8
|
95 Vector2 uv = calc_texcoords(hit);
|
nuclear@8
|
96 Vector3 pnext = sphvec(uv.x + 0.05, 0.5);
|
nuclear@8
|
97 Vector3 pprev = sphvec(uv.y - 0.05, 0.5);
|
nuclear@8
|
98 return (pnext - pprev).normalized();
|
nuclear@8
|
99 }
|
nuclear@8
|
100
|
nuclear@8
|
101 Vector2 Sphere::calc_texcoords(const RayHit &hit) const
|
nuclear@8
|
102 {
|
nuclear@17
|
103 Vector3 pt = hit.local_ray.origin + hit.local_ray.dir * hit.dist;
|
nuclear@8
|
104 pt.normalize();
|
nuclear@8
|
105
|
nuclear@8
|
106 float theta = atan2(pt.z, pt.x);
|
nuclear@8
|
107 float phi = acos(pt.y);
|
nuclear@8
|
108
|
nuclear@8
|
109 return Vector2(theta / M_PI + 0.5, phi / M_PI);
|
nuclear@8
|
110 }
|
nuclear@8
|
111
|
nuclear@8
|
112
|
nuclear@4
|
113 // --- class Box ---
|
nuclear@4
|
114
|
nuclear@4
|
115 bool Box::intersect(const Ray &ray, RayHit *hit) const
|
nuclear@4
|
116 {
|
nuclear@18
|
117 Vector3 param[2] = {Vector3{-0.5, -0.5, -0.5}, Vector3{0.5, 0.5, 0.5}};
|
nuclear@18
|
118 Vector3 inv_dir{1.0f / ray.dir.x, 1.0f / ray.dir.y, 1.0f / ray.dir.z};
|
nuclear@18
|
119 int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
|
nuclear@18
|
120
|
nuclear@18
|
121 float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
|
nuclear@18
|
122 float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
|
nuclear@18
|
123 float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
|
nuclear@18
|
124 float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
|
nuclear@18
|
125
|
nuclear@18
|
126 if(tmin > tymax || tymin > tmax) {
|
nuclear@18
|
127 return false;
|
nuclear@18
|
128 }
|
nuclear@18
|
129 if(tymin > tmin) {
|
nuclear@18
|
130 tmin = tymin;
|
nuclear@18
|
131 }
|
nuclear@18
|
132 if(tymax < tmax) {
|
nuclear@18
|
133 tmax = tymax;
|
nuclear@18
|
134 }
|
nuclear@18
|
135
|
nuclear@18
|
136 float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
|
nuclear@18
|
137 float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
|
nuclear@18
|
138
|
nuclear@18
|
139 if(tmin > tzmax || tzmin > tmax) {
|
nuclear@18
|
140 return false;
|
nuclear@18
|
141 }
|
nuclear@18
|
142 if(tzmin > tmin) {
|
nuclear@18
|
143 tmin = tzmin;
|
nuclear@18
|
144 }
|
nuclear@18
|
145 if(tzmax < tmax) {
|
nuclear@18
|
146 tmax = tzmax;
|
nuclear@18
|
147 }
|
nuclear@18
|
148
|
nuclear@43
|
149 float t = tmin < 1e-5 ? tmax : tmin;
|
nuclear@43
|
150 if(t >= 1e-5) {
|
nuclear@18
|
151 if(hit) {
|
nuclear@18
|
152 hit->obj = this;
|
nuclear@18
|
153 hit->dist = t;
|
nuclear@18
|
154 }
|
nuclear@18
|
155 return true;
|
nuclear@18
|
156 }
|
nuclear@4
|
157 return false;
|
nuclear@41
|
158 }
|
nuclear@18
|
159
|
nuclear@41
|
160 #define SIGN(x) (x >= 0.0 ? 1.0 : -1.0)
|
nuclear@41
|
161
|
nuclear@41
|
162 Vector3 Box::gen_surface_point() const
|
nuclear@41
|
163 {
|
nuclear@41
|
164 Vector3 rnd{randf(-1, 1), randf(-1, 1), randf(-1, 1)};
|
nuclear@41
|
165 float absrnd[3];
|
nuclear@41
|
166
|
nuclear@41
|
167 absrnd[0] = fabs(rnd.x);
|
nuclear@41
|
168 absrnd[1] = fabs(rnd.y);
|
nuclear@41
|
169 absrnd[2] = fabs(rnd.z);
|
nuclear@41
|
170
|
nuclear@41
|
171 int major = 0;
|
nuclear@41
|
172 for(int i=1; i<3; i++) {
|
nuclear@41
|
173 if(absrnd[i] > absrnd[major]) {
|
nuclear@41
|
174 major = i;
|
nuclear@41
|
175 }
|
nuclear@41
|
176 }
|
nuclear@41
|
177 rnd[major] = SIGN(rnd[major]);
|
nuclear@41
|
178 return rnd;
|
nuclear@18
|
179 }
|
nuclear@18
|
180
|
nuclear@18
|
181 #define BOX_EXT 0.499999
|
nuclear@18
|
182 Vector3 Box::calc_normal(const RayHit &hit) const
|
nuclear@18
|
183 {
|
nuclear@18
|
184 Vector3 pt = hit.local_ray.origin + hit.local_ray.dir * hit.dist;
|
nuclear@18
|
185 if(pt.x > BOX_EXT) return Vector3(1, 0, 0);
|
nuclear@18
|
186 if(pt.x < -BOX_EXT) return Vector3(-1, 0, 0);
|
nuclear@18
|
187 if(pt.y > BOX_EXT) return Vector3(0, 1, 0);
|
nuclear@18
|
188 if(pt.y < -BOX_EXT) return Vector3(0, -1, 0);
|
nuclear@18
|
189 if(pt.z > BOX_EXT) return Vector3(0, 0, 1);
|
nuclear@18
|
190 if(pt.z < -BOX_EXT) return Vector3(0, 0, -1);
|
nuclear@18
|
191 return Vector3(0, 0, 0); // shouldn't happen unless numerical precision is fucked
|
nuclear@18
|
192 }
|
nuclear@18
|
193
|
nuclear@18
|
194 Vector3 Box::calc_tangent(const RayHit &hit) const
|
nuclear@18
|
195 {
|
nuclear@18
|
196 return Vector3(1, 0, 0); // TODO
|
nuclear@18
|
197 }
|
nuclear@18
|
198
|
nuclear@18
|
199 Vector2 Box::calc_texcoords(const RayHit &hit) const
|
nuclear@18
|
200 {
|
nuclear@18
|
201 return Vector2(0, 0); // TODO
|
nuclear@4
|
202 }
|
nuclear@4
|
203
|
nuclear@4
|
204 // --- class Triangle ---
|
nuclear@4
|
205
|
nuclear@4
|
206 bool Triangle::intersect(const Ray &ray, RayHit *hit) const
|
nuclear@4
|
207 {
|
nuclear@4
|
208 return false;
|
nuclear@4
|
209 }
|
nuclear@4
|
210
|
nuclear@41
|
211 Vector3 Triangle::gen_surface_point() const
|
nuclear@41
|
212 {
|
nuclear@44
|
213 // TODO: this is probably not uniform, fix at some point
|
nuclear@41
|
214 float bu = randf();
|
nuclear@41
|
215 float bv = randf();
|
nuclear@41
|
216 float bw = 1.0 - (bu + bv);
|
nuclear@41
|
217
|
nuclear@41
|
218 return v[0] * bu + v[1] * bv + v[2] * bw;
|
nuclear@41
|
219 }
|
nuclear@41
|
220
|
nuclear@4
|
221 // --- class Mesh ---
|
nuclear@4
|
222
|
nuclear@4
|
223 bool Mesh::intersect(const Ray &ray, RayHit *hit) const
|
nuclear@4
|
224 {
|
nuclear@4
|
225 RayHit nearest;
|
nuclear@4
|
226 nearest.dist = FLT_MAX;
|
nuclear@4
|
227
|
nuclear@4
|
228 for(size_t i=0; i<faces.size(); i++) {
|
nuclear@4
|
229 if(faces[i].intersect(ray, hit)) {
|
nuclear@4
|
230 if(!hit) return true;
|
nuclear@4
|
231 if(hit->dist < nearest.dist) {
|
nuclear@4
|
232 nearest = *hit;
|
nuclear@4
|
233 }
|
nuclear@4
|
234 }
|
nuclear@4
|
235 }
|
nuclear@4
|
236
|
nuclear@4
|
237 if(nearest.dist < FLT_MAX) {
|
nuclear@4
|
238 *hit = nearest;
|
nuclear@4
|
239 hit->subobj = hit->obj;
|
nuclear@4
|
240 hit->obj = this;
|
nuclear@4
|
241 return true;
|
nuclear@4
|
242 }
|
nuclear@4
|
243 return false;
|
nuclear@4
|
244 }
|
nuclear@41
|
245
|
nuclear@41
|
246 Vector3 Mesh::gen_surface_point() const
|
nuclear@41
|
247 {
|
nuclear@41
|
248 // this needs some precalculation...
|
nuclear@41
|
249 return Vector3(0, 0, 0); // TODO
|
nuclear@41
|
250 }
|