3dphotoshoot

annotate src/geom.cc @ 25:ac80210d5fbe

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