goat3dgfx

annotate src/geom.cc @ 34:3eb6c8f89fe1

merge
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Mar 2014 17:41:10 +0200
parents 7d6b667821cf
children
rev   line source
nuclear@0 1 #include <algorithm>
nuclear@0 2 #include <float.h>
nuclear@0 3 #include "geom.h"
nuclear@0 4 #include "logger.h"
nuclear@0 5
nuclear@15 6 using namespace goatgfx;
nuclear@15 7
nuclear@0 8 GeomObject::~GeomObject()
nuclear@0 9 {
nuclear@0 10 }
nuclear@0 11
nuclear@0 12
nuclear@0 13 Sphere::Sphere()
nuclear@0 14 {
nuclear@0 15 radius = 1.0;
nuclear@0 16 }
nuclear@0 17
nuclear@0 18 Sphere::Sphere(const Vector3 &cent, float radius)
nuclear@0 19 : center(cent)
nuclear@0 20 {
nuclear@0 21 this->radius = radius;
nuclear@0 22 }
nuclear@0 23
nuclear@0 24 void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2)
nuclear@0 25 {
nuclear@0 26 const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1);
nuclear@0 27 const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2);
nuclear@0 28
nuclear@0 29 if(!sph1 || !sph2) {
nuclear@0 30 error_log("Sphere::set_union: arguments must be spheres");
nuclear@0 31 return;
nuclear@0 32 }
nuclear@0 33
nuclear@0 34 float dist = (sph1->center - sph2->center).length();
nuclear@0 35 float surf_dist = dist - (sph1->radius + sph2->radius);
nuclear@0 36 float d1 = sph1->radius + surf_dist / 2.0;
nuclear@0 37 float d2 = sph2->radius + surf_dist / 2.0;
nuclear@0 38 float t = d1 / (d1 + d2);
nuclear@0 39
nuclear@0 40 if(t < 0.0) t = 0.0;
nuclear@0 41 if(t > 1.0) t = 1.0;
nuclear@0 42
nuclear@0 43 center = sph1->center * t + sph2->center * (1.0 - t);
nuclear@0 44 radius = std::max(dist * t + sph2->radius, dist * (1.0f - t) + sph1->radius);
nuclear@0 45 }
nuclear@0 46
nuclear@0 47 void Sphere::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
nuclear@0 48 {
nuclear@0 49 error_log("Sphere::intersection undefined\n");
nuclear@0 50 }
nuclear@0 51
nuclear@23 52 bool Sphere::contains(const Vector3 &pt) const
nuclear@23 53 {
nuclear@23 54 float dist_sq = (pt - center).length_sq();
nuclear@23 55 return dist_sq <= radius * radius;
nuclear@23 56 }
nuclear@23 57
nuclear@0 58 bool Sphere::intersect(const Ray &ray, HitPoint *hit) const
nuclear@0 59 {
nuclear@0 60 float a = dot_product(ray.dir, ray.dir);
nuclear@0 61 float b = 2.0 * ray.dir.x * (ray.origin.x - center.x) +
nuclear@0 62 2.0 * ray.dir.y * (ray.origin.y - center.y) +
nuclear@0 63 2.0 * ray.dir.z * (ray.origin.z - center.z);
nuclear@0 64 float c = dot_product(ray.origin, ray.origin) + dot_product(center, center) -
nuclear@0 65 2.0 * dot_product(ray.origin, center) - radius * radius;
nuclear@0 66
nuclear@0 67 float discr = b * b - 4.0 * a * c;
nuclear@0 68 if(discr < 1e-4) {
nuclear@0 69 return false;
nuclear@0 70 }
nuclear@0 71
nuclear@0 72 float sqrt_discr = sqrt(discr);
nuclear@0 73 float t0 = (-b + sqrt_discr) / (2.0 * a);
nuclear@0 74 float t1 = (-b - sqrt_discr) / (2.0 * a);
nuclear@0 75
nuclear@0 76 if(t0 < 1e-4)
nuclear@0 77 t0 = t1;
nuclear@0 78 if(t1 < 1e-4)
nuclear@0 79 t1 = t0;
nuclear@0 80
nuclear@0 81 float t = t0 < t1 ? t0 : t1;
nuclear@0 82 if(t < 1e-4) {
nuclear@0 83 return false;
nuclear@0 84 }
nuclear@0 85
nuclear@0 86 // fill the HitPoint structure
nuclear@0 87 if(hit) {
nuclear@0 88 hit->obj = this;
nuclear@0 89 hit->dist = t;
nuclear@0 90 hit->pos = ray.origin + ray.dir * t;
nuclear@0 91 hit->normal = (hit->pos - center) / radius;
nuclear@0 92 }
nuclear@0 93 return true;
nuclear@0 94 }
nuclear@0 95
nuclear@0 96
nuclear@0 97 AABox::AABox()
nuclear@0 98 {
nuclear@0 99 }
nuclear@0 100
nuclear@0 101 AABox::AABox(const Vector3 &vmin, const Vector3 &vmax)
nuclear@0 102 : min(vmin), max(vmax)
nuclear@0 103 {
nuclear@0 104 }
nuclear@0 105
nuclear@0 106 void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2)
nuclear@0 107 {
nuclear@0 108 const AABox *box1 = dynamic_cast<const AABox*>(obj1);
nuclear@0 109 const AABox *box2 = dynamic_cast<const AABox*>(obj2);
nuclear@0 110
nuclear@0 111 if(!box1 || !box2) {
nuclear@0 112 error_log("AABox::set_union: arguments must be AABoxes too\n");
nuclear@0 113 return;
nuclear@0 114 }
nuclear@0 115
nuclear@0 116 min.x = std::min(box1->min.x, box2->min.x);
nuclear@0 117 min.y = std::min(box1->min.y, box2->min.y);
nuclear@0 118 min.z = std::min(box1->min.z, box2->min.z);
nuclear@0 119
nuclear@0 120 max.x = std::max(box1->max.x, box2->max.x);
nuclear@0 121 max.y = std::max(box1->max.y, box2->max.y);
nuclear@0 122 max.z = std::max(box1->max.z, box2->max.z);
nuclear@0 123 }
nuclear@0 124
nuclear@0 125 void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
nuclear@0 126 {
nuclear@0 127 const AABox *box1 = dynamic_cast<const AABox*>(obj1);
nuclear@0 128 const AABox *box2 = dynamic_cast<const AABox*>(obj2);
nuclear@0 129
nuclear@0 130 if(!box1 || !box2) {
nuclear@0 131 error_log("AABox::set_intersection: arguments must be AABoxes too\n");
nuclear@0 132 return;
nuclear@0 133 }
nuclear@0 134
nuclear@0 135 for(int i=0; i<3; i++) {
nuclear@0 136 min[i] = std::max(box1->min[i], box2->min[i]);
nuclear@0 137 max[i] = std::min(box1->max[i], box2->max[i]);
nuclear@0 138
nuclear@0 139 if(max[i] < min[i]) {
nuclear@0 140 max[i] = min[i];
nuclear@0 141 }
nuclear@0 142 }
nuclear@0 143 }
nuclear@0 144
nuclear@23 145 bool AABox::contains(const Vector3 &pt) const
nuclear@23 146 {
nuclear@23 147 return pt.x >= min.x && pt.x <= max.x &&
nuclear@23 148 pt.y >= min.y && pt.y <= max.y &&
nuclear@23 149 pt.z >= min.z && pt.z <= max.z;
nuclear@23 150 }
nuclear@23 151
nuclear@0 152 bool AABox::intersect(const Ray &ray, HitPoint *hit) const
nuclear@0 153 {
nuclear@0 154 Vector3 param[2] = {min, max};
nuclear@0 155 Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
nuclear@0 156 int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
nuclear@0 157
nuclear@0 158 float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
nuclear@0 159 float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
nuclear@0 160 float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
nuclear@0 161 float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
nuclear@0 162
nuclear@0 163 if(tmin > tymax || tymin > tmax) {
nuclear@0 164 return false;
nuclear@0 165 }
nuclear@0 166 if(tymin > tmin) {
nuclear@0 167 tmin = tymin;
nuclear@0 168 }
nuclear@0 169 if(tymax < tmax) {
nuclear@0 170 tmax = tymax;
nuclear@0 171 }
nuclear@0 172
nuclear@0 173 float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
nuclear@0 174 float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
nuclear@0 175
nuclear@0 176 if(tmin > tzmax || tzmin > tmax) {
nuclear@0 177 return false;
nuclear@0 178 }
nuclear@0 179 if(tzmin > tmin) {
nuclear@0 180 tmin = tzmin;
nuclear@0 181 }
nuclear@0 182 if(tzmax < tmax) {
nuclear@0 183 tmax = tzmax;
nuclear@0 184 }
nuclear@0 185
nuclear@0 186 float t = tmin < 1e-4 ? tmax : tmin;
nuclear@0 187 if(t >= 1e-4) {
nuclear@0 188
nuclear@0 189 if(hit) {
nuclear@0 190 hit->obj = this;
nuclear@0 191 hit->dist = t;
nuclear@0 192 hit->pos = ray.origin + ray.dir * t;
nuclear@0 193
nuclear@0 194 float min_dist = FLT_MAX;
nuclear@0 195 Vector3 offs = min + (max - min) / 2.0;
nuclear@0 196 Vector3 local_hit = hit->pos - offs;
nuclear@0 197
nuclear@0 198 static const Vector3 axis[] = {
nuclear@0 199 Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)
nuclear@0 200 };
nuclear@0 201 //int tcidx[][2] = {{2, 1}, {0, 2}, {0, 1}};
nuclear@0 202
nuclear@0 203 for(int i=0; i<3; i++) {
nuclear@0 204 float dist = fabs((max[i] - offs[i]) - fabs(local_hit[i]));
nuclear@0 205 if(dist < min_dist) {
nuclear@0 206 min_dist = dist;
nuclear@0 207 hit->normal = axis[i] * (local_hit[i] < 0.0 ? 1.0 : -1.0);
nuclear@0 208 //hit->texcoord = Vector2(hit->pos[tcidx[i][0]], hit->pos[tcidx[i][1]]);
nuclear@0 209 }
nuclear@0 210 }
nuclear@0 211 }
nuclear@0 212 return true;
nuclear@0 213 }
nuclear@0 214 return false;
nuclear@0 215
nuclear@0 216 }
nuclear@0 217
nuclear@0 218 Plane::Plane()
nuclear@0 219 : normal(0.0, 1.0, 0.0)
nuclear@0 220 {
nuclear@0 221 }
nuclear@0 222
nuclear@0 223 Plane::Plane(const Vector3 &p, const Vector3 &norm)
nuclear@0 224 : pt(p)
nuclear@0 225 {
nuclear@0 226 normal = norm.normalized();
nuclear@0 227 }
nuclear@0 228
nuclear@0 229 Plane::Plane(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3)
nuclear@0 230 : pt(p1)
nuclear@0 231 {
nuclear@0 232 normal = cross_product(p2 - p1, p3 - p1).normalized();
nuclear@0 233 }
nuclear@0 234
nuclear@0 235 Plane::Plane(const Vector3 &normal, float dist)
nuclear@0 236 {
nuclear@0 237 this->normal = normal.normalized();
nuclear@0 238 pt = this->normal * dist;
nuclear@0 239 }
nuclear@0 240
nuclear@0 241 void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2)
nuclear@0 242 {
nuclear@0 243 error_log("Plane::set_union undefined\n");
nuclear@0 244 }
nuclear@0 245
nuclear@0 246 void Plane::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
nuclear@0 247 {
nuclear@0 248 error_log("Plane::set_intersection undefined\n");
nuclear@0 249 }
nuclear@0 250
nuclear@23 251 bool Plane::contains(const Vector3 &pt) const
nuclear@23 252 {
nuclear@23 253 return false; // TODO: maybe define containment as half-space containment?
nuclear@23 254 }
nuclear@23 255
nuclear@0 256 bool Plane::intersect(const Ray &ray, HitPoint *hit) const
nuclear@0 257 {
nuclear@0 258 float ndotdir = dot_product(normal, ray.dir);
nuclear@0 259 if(fabs(ndotdir) < 1e-4) {
nuclear@0 260 return false;
nuclear@0 261 }
nuclear@0 262
nuclear@0 263 if(hit) {
nuclear@0 264 Vector3 ptdir = pt - ray.origin;
nuclear@0 265 float t = dot_product(normal, ptdir) / ndotdir;
nuclear@0 266
nuclear@0 267 hit->pos = ray.origin + ray.dir * t;
nuclear@0 268 hit->normal = normal;
nuclear@0 269 hit->obj = this;
nuclear@0 270 }
nuclear@0 271 return true;
nuclear@0 272 }