erebus

annotate liberebus/src/geomobj.cc @ 45:bab25c0ce337

started gmath conversion
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 29 Dec 2015 12:19:53 +0200
parents a2afaf8af09b
children c4d48a21bc4a
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 }