erebus

view liberebus/src/geomobj.cc @ 46:c4d48a21bc4a

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