erebus

annotate liberebus/src/geomobj.cc @ 28:4a0a288ffb27

phong/lafortune BRDF
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 06 Jun 2014 14:39:40 +0300
parents e9da2916bc79
children 2e817711d0f6
rev   line source
nuclear@16 1 #include <math.h>
nuclear@4 2 #include <float.h>
nuclear@4 3 #include "geomobj.h"
nuclear@4 4
nuclear@4 5 static LambertRefl lambert;
nuclear@4 6
nuclear@4 7 GeomObject::GeomObject()
nuclear@4 8 {
nuclear@4 9 brdf = &lambert;
nuclear@4 10 }
nuclear@4 11
nuclear@4 12 ObjType GeomObject::get_type() const
nuclear@4 13 {
nuclear@4 14 return ObjType::geom;
nuclear@4 15 }
nuclear@4 16
nuclear@4 17 bool GeomObject::intersect(const Ray &ray, RayHit *hit) const
nuclear@4 18 {
nuclear@4 19 return false;
nuclear@4 20 }
nuclear@4 21
nuclear@8 22 Vector3 GeomObject::calc_normal(const RayHit &hit) const
nuclear@8 23 {
nuclear@8 24 // when you look at singularities, the singularities always look back at you :)
nuclear@17 25 return -(hit.local_ray.dir).normalized();
nuclear@8 26 }
nuclear@8 27
nuclear@8 28 Vector3 GeomObject::calc_tangent(const RayHit &hit) const
nuclear@8 29 {
nuclear@8 30 return Vector3(1, 0, 0); // whatever...
nuclear@8 31 }
nuclear@8 32
nuclear@8 33 Vector2 GeomObject::calc_texcoords(const RayHit &hit) const
nuclear@8 34 {
nuclear@8 35 return Vector2();
nuclear@8 36 }
nuclear@8 37
nuclear@4 38 // --- class Sphere ---
nuclear@4 39
nuclear@4 40 bool Sphere::intersect(const Ray &ray, RayHit *hit) const
nuclear@4 41 {
nuclear@4 42 // assumes center is the origin and radius is 1
nuclear@4 43 float a = dot_product(ray.dir, ray.dir);
nuclear@4 44 float b = 2.0 * dot_product(ray.dir, ray.origin);
nuclear@4 45 float c = dot_product(ray.origin, ray.origin) - 1.0;
nuclear@4 46
nuclear@4 47 float d = b * b - 4.0 * a * c;
nuclear@17 48 if(d < 1e-6) return false;
nuclear@4 49
nuclear@4 50 float sqrt_d = sqrt(d);
nuclear@4 51 float t0 = (-b + sqrt_d) / (2.0 * a);
nuclear@4 52 float t1 = (-b - sqrt_d) / (2.0 * a);
nuclear@4 53
nuclear@17 54 if(t0 < 1e-6) t0 = t1;
nuclear@17 55 if(t1 < 1e-6) t1 = t0;
nuclear@4 56 float t = t0 < t1 ? t0 : t1;
nuclear@17 57 if(t < 1e-6) return false;
nuclear@4 58
nuclear@4 59 if(hit) {
nuclear@4 60 hit->dist = t;
nuclear@4 61 hit->obj = this;
nuclear@4 62 hit->subobj = 0;
nuclear@4 63 }
nuclear@4 64 return true;
nuclear@4 65 }
nuclear@4 66
nuclear@8 67 Vector3 Sphere::calc_normal(const RayHit &hit) const
nuclear@8 68 {
nuclear@17 69 Vector3 pt = hit.local_ray.origin + hit.local_ray.dir * hit.dist;
nuclear@8 70 return pt.normalized();
nuclear@8 71 }
nuclear@8 72
nuclear@8 73 static inline Vector3 sphvec(float u, float v)
nuclear@8 74 {
nuclear@8 75 float theta = u * M_PI * 2.0;
nuclear@8 76 float phi = v * M_PI;
nuclear@8 77
nuclear@8 78 return Vector3(sin(theta) * sin(phi), cos(phi), cos(theta) * sin(phi));
nuclear@8 79 }
nuclear@8 80
nuclear@8 81 Vector3 Sphere::calc_tangent(const RayHit &hit) const
nuclear@8 82 {
nuclear@8 83 Vector2 uv = calc_texcoords(hit);
nuclear@8 84 Vector3 pnext = sphvec(uv.x + 0.05, 0.5);
nuclear@8 85 Vector3 pprev = sphvec(uv.y - 0.05, 0.5);
nuclear@8 86 return (pnext - pprev).normalized();
nuclear@8 87 }
nuclear@8 88
nuclear@8 89 Vector2 Sphere::calc_texcoords(const RayHit &hit) const
nuclear@8 90 {
nuclear@17 91 Vector3 pt = hit.local_ray.origin + hit.local_ray.dir * hit.dist;
nuclear@8 92 pt.normalize();
nuclear@8 93
nuclear@8 94 float theta = atan2(pt.z, pt.x);
nuclear@8 95 float phi = acos(pt.y);
nuclear@8 96
nuclear@8 97 return Vector2(theta / M_PI + 0.5, phi / M_PI);
nuclear@8 98 }
nuclear@8 99
nuclear@8 100
nuclear@4 101 // --- class Box ---
nuclear@4 102
nuclear@4 103 bool Box::intersect(const Ray &ray, RayHit *hit) const
nuclear@4 104 {
nuclear@18 105 Vector3 param[2] = {Vector3{-0.5, -0.5, -0.5}, Vector3{0.5, 0.5, 0.5}};
nuclear@18 106 Vector3 inv_dir{1.0f / ray.dir.x, 1.0f / ray.dir.y, 1.0f / ray.dir.z};
nuclear@18 107 int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
nuclear@18 108
nuclear@18 109 float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
nuclear@18 110 float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
nuclear@18 111 float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
nuclear@18 112 float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
nuclear@18 113
nuclear@18 114 if(tmin > tymax || tymin > tmax) {
nuclear@18 115 return false;
nuclear@18 116 }
nuclear@18 117 if(tymin > tmin) {
nuclear@18 118 tmin = tymin;
nuclear@18 119 }
nuclear@18 120 if(tymax < tmax) {
nuclear@18 121 tmax = tymax;
nuclear@18 122 }
nuclear@18 123
nuclear@18 124 float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
nuclear@18 125 float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
nuclear@18 126
nuclear@18 127 if(tmin > tzmax || tzmin > tmax) {
nuclear@18 128 return false;
nuclear@18 129 }
nuclear@18 130 if(tzmin > tmin) {
nuclear@18 131 tmin = tzmin;
nuclear@18 132 }
nuclear@18 133 if(tzmax < tmax) {
nuclear@18 134 tmax = tzmax;
nuclear@18 135 }
nuclear@18 136
nuclear@18 137 float t = tmin < 1e-4 ? tmax : tmin;
nuclear@18 138 if(t >= 1e-4) {
nuclear@18 139 if(hit) {
nuclear@18 140 hit->obj = this;
nuclear@18 141 hit->dist = t;
nuclear@18 142 }
nuclear@18 143 return true;
nuclear@18 144 }
nuclear@4 145 return false;
nuclear@18 146
nuclear@18 147 }
nuclear@18 148
nuclear@18 149 #define BOX_EXT 0.499999
nuclear@18 150 Vector3 Box::calc_normal(const RayHit &hit) const
nuclear@18 151 {
nuclear@18 152 Vector3 pt = hit.local_ray.origin + hit.local_ray.dir * hit.dist;
nuclear@18 153 if(pt.x > BOX_EXT) return Vector3(1, 0, 0);
nuclear@18 154 if(pt.x < -BOX_EXT) return Vector3(-1, 0, 0);
nuclear@18 155 if(pt.y > BOX_EXT) return Vector3(0, 1, 0);
nuclear@18 156 if(pt.y < -BOX_EXT) return Vector3(0, -1, 0);
nuclear@18 157 if(pt.z > BOX_EXT) return Vector3(0, 0, 1);
nuclear@18 158 if(pt.z < -BOX_EXT) return Vector3(0, 0, -1);
nuclear@18 159 return Vector3(0, 0, 0); // shouldn't happen unless numerical precision is fucked
nuclear@18 160 }
nuclear@18 161
nuclear@18 162 Vector3 Box::calc_tangent(const RayHit &hit) const
nuclear@18 163 {
nuclear@18 164 return Vector3(1, 0, 0); // TODO
nuclear@18 165 }
nuclear@18 166
nuclear@18 167 Vector2 Box::calc_texcoords(const RayHit &hit) const
nuclear@18 168 {
nuclear@18 169 return Vector2(0, 0); // TODO
nuclear@4 170 }
nuclear@4 171
nuclear@4 172 // --- class Triangle ---
nuclear@4 173
nuclear@4 174 bool Triangle::intersect(const Ray &ray, RayHit *hit) const
nuclear@4 175 {
nuclear@4 176 return false;
nuclear@4 177 }
nuclear@4 178
nuclear@4 179 // --- class Mesh ---
nuclear@4 180
nuclear@4 181 bool Mesh::intersect(const Ray &ray, RayHit *hit) const
nuclear@4 182 {
nuclear@4 183 RayHit nearest;
nuclear@4 184 nearest.dist = FLT_MAX;
nuclear@4 185
nuclear@4 186 for(size_t i=0; i<faces.size(); i++) {
nuclear@4 187 if(faces[i].intersect(ray, hit)) {
nuclear@4 188 if(!hit) return true;
nuclear@4 189 if(hit->dist < nearest.dist) {
nuclear@4 190 nearest = *hit;
nuclear@4 191 }
nuclear@4 192 }
nuclear@4 193 }
nuclear@4 194
nuclear@4 195 if(nearest.dist < FLT_MAX) {
nuclear@4 196 *hit = nearest;
nuclear@4 197 hit->subobj = hit->obj;
nuclear@4 198 hit->obj = this;
nuclear@4 199 return true;
nuclear@4 200 }
nuclear@4 201 return false;
nuclear@4 202 }