erebus

view liberebus/src/geomobj.cc @ 18:09028848f276

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