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 }
|