00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <float.h>
00021 #include <math.h>
00022 #include <vector>
00023 #include <float.h>
00024
00025 #include <archon/math/geometry.H>
00026 #include <archon/math/quartic_solve.H>
00027 #include <archon/util/miniball.H>
00028
00029 #include "object.H"
00030
00031 #if ! defined M_PI
00032 #define M_E 2.7182818284590452353602874713526625
00033 #define M_LOG2E 1.4426950408889634073599246810018922
00034 #define M_LOG10E 0.4342944819032518276511289189166051
00035 #define M_LN2 0.6931471805599453094172321214581766
00036 #define M_LN10 2.3025850929940456840179914546843642
00037 #define M_PI 3.1415926535897932384626433832795029
00038 #define M_PI_2 1.5707963267948966192313216916397514
00039 #define M_PI_4 0.7853981633974483096156608458198757
00040 #define M_1_PI 0.3183098861837906715377675267450287
00041 #define M_2_PI 0.6366197723675813430755350534900574
00042 #define M_2_SQRTPI 1.1283791670955125738961589031215452
00043 #define M_SQRT2 1.4142135623730950488016887242096981
00044 #define M_SQRT1_2 0.7071067811865475244008443621048490
00045 #endif
00046
00047 namespace Archon
00048 {
00049 namespace Raytracer
00050 {
00051 using namespace Utilities;
00052 using namespace Math;
00053
00054 inline bool leastPositiveDist(double t1, double t2, double &dist)
00055 {
00056 if(t1 > t2)
00057 {
00058 if(t1 >= 0)
00059 {
00060 dist = t2 >= 0 ? t2 : t1;
00061 return true;
00062 }
00063 }
00064 else
00065 {
00066 if(t2 >= 0)
00067 {
00068 dist = t1 >= 0 ? t1 : t2;
00069 return true;
00070 }
00071 }
00072 return false;
00073 }
00074
00075 bool Plane::intersect(const Line3 &ray, const Object *originObject,
00076 const Object::Part *, double &dist,
00077 const Object::Part **p) const
00078 {
00079
00080
00081
00082
00083 if(originObject == this) return false;
00084
00085 const double cosine = dot(normal, ray.direction);
00086 if(cosine > 0) return false;
00087 dist = dot(normal, origin - ray.point) / cosine;
00088 if(p) *p = this;
00089 return true;
00090 }
00091
00092 void Plane::map(const Vector3 &point, Vector3 &normal) const
00093 {
00094 normal = this->normal;
00095 }
00096
00097 void Plane::map(const Vector3 &point, Vector3 &normal,
00098 Vector2 &texturePoint) const
00099 {
00100 Vector3 p = invMap(point);
00101 texturePoint[0] = 0.5 + p[0]/2;
00102 texturePoint[1] = 0.5 - p[2]/2;
00103 normal = this->normal;
00104 }
00105
00106 Cylinder::Cylinder(const Surface *surface, const CoordSystem3x3 &s):
00107 Object::Part(surface)
00108 {
00109 invMap.setInverseOf(s);
00110 pointToNormalMap = invMap;
00111 pointToNormalMap.basis.transpose();
00112 pointToNormalMap.basis.map(pointToNormalMap.origin);
00113 pointToNormalMap.basis *= Matrix3x3(Vector3(1, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 1)) * invMap.basis;
00114 {
00115 CoordSystem3x3 s2 = s;
00116 s2.translate(Vector3(0, 1, 0));
00117 topCap = new Plane(surface, s2);
00118 }
00119 {
00120 CoordSystem3x3 s2 = s;
00121 s2.basis.scale(Vector3(1, -1, -1));
00122 s2.translate(Vector3(0, 1, 0));
00123 bottomCap = new Plane(surface, s2);
00124 }
00125 }
00126
00127 Cylinder::~Cylinder()
00128 {
00129 delete topCap;
00130 delete bottomCap;
00131 }
00132
00137 bool Cylinder::intersect(const Line3 &ray, const Object *originObject,
00138 const Object::Part *, double &dist,
00139 const Object::Part **p) const
00140 {
00141
00142
00143
00144
00145
00146 if(originObject == this) return false;
00147
00148 const Vector3 rp = invMap(ray.point);
00149 const Vector3 rd = invMap.basis(ray.direction);
00150
00151 const double a = 2 * (rd[0] * rd[0] + rd[2] * rd[2]);
00152 const double b = -2 * (rd[0] * rp[0] + rd[2] * rp[2]);
00153 const double c = (rp[0] * rp[0] + rp[2] * rp[2]) - 1;
00154 const double d = b * b - 2 * a * c;
00155
00156 if(d < 0) return false;
00157
00158 const double sqrt_d = sqrt(d);
00159 const double t = (b - sqrt_d) / a;
00160
00161
00162
00163 const double y = rp[1] + rd[1] * t;
00164
00165 if(y > 1)
00166 {
00167
00168 const double t2 = (b + sqrt_d) / a;
00169 if(t2 < 0) return false;
00170 const double y2 = rp[1] + t2 * rd[1];
00171 if(y2 > 1) return false;
00172 dist = (1 - rp[1]) / rd[1];
00173 if(p) *p = topCap;
00174 return true;
00175 }
00176
00177 if(y < -1)
00178 {
00179
00180 const double t2 = (b + sqrt_d) / a;
00181 if(t2 < 0) return false;
00182 const double y2 = rp[1] + t2 * rd[1];
00183 if(y2 < -1) return false;
00184 dist = (-1 - rp[1]) / rd[1];
00185 if(p) *p = bottomCap;
00186 return true;
00187 }
00188
00189 if(b <= 0) return false;
00190
00191 dist = t;
00192 if(p) *p = this;
00193 return true;
00194 }
00195
00196 void Cylinder::interiorIntersect(const Line3 &ray,
00197 const Object::Part *,
00198 double &dist,
00199 const Object::Part *&p) const
00200 {
00201 const Vector3 rp = invMap(ray.point);
00202 const Vector3 rd = invMap.basis(ray.direction);
00203
00204 const double a = 2 * (rd[0] * rd[0] + rd[2] * rd[2]);
00205 const double b = -2 * (rd[0] * rp[0] + rd[2] * rp[2]);
00206 const double c = (rp[0] * rp[0] + rp[2] * rp[2]) - 1;
00207 const double d = b * b - 2 * a * c;
00208
00209 if(d < 0)
00210 {
00211 dist = 0;
00212 p = this;
00213 return;
00214 }
00215
00216 const double sqrt_d = sqrt(d);
00217
00218
00219
00220
00221
00222
00223 const double t = (b + sqrt_d) / a;
00224
00225 const double y = rp[1] + rd[1] * t;
00226
00227 if(y > 1)
00228 {
00229
00230 dist = (1 - rp[1]) / rd[1];
00231 p = topCap;
00232 return;
00233 }
00234
00235 if(y < -1)
00236 {
00237
00238 dist = (-1 - rp[1]) / rd[1];
00239 p = bottomCap;
00240 return;
00241 }
00242
00243 dist = t;
00244 p = this;
00245 }
00246
00247 void Cylinder::map(const Vector3 &point, Vector3 &normal,
00248 Vector2 &texturePoint) const
00249 {
00250 map(point, normal);
00251
00252 Vector3 p = invMap(point);
00253
00254 texturePoint[0] = p[0] == 0 ? p[2] < 0 ? 0 : 0.5 :
00255 (p[0] < 0 ? 0.25 : 0.75) - atan(p[2]/p[0]) / (2 * M_PI);
00256
00257 texturePoint[1] = 0.5 + p[1]/2;
00258 }
00259
00260 bool Sphere::intersect(const Line3 &ray, const Object *originObject,
00261 const Object::Part *, double &dist,
00262 const Object::Part **p) const
00263 {
00264
00265
00266
00267
00268 if(originObject == this) return false;
00269
00270 const Vector3 rp = invMap(ray.point);
00271 const Vector3 rd = invMap.basis(ray.direction);
00272 const double b = -2 * dot(rd, rp);
00273 if(b <= 0) return false;
00274 const double a = 2 * rd.squareSum();
00275 const double c = rp.squareSum() - 1;
00276 const double d = b * b - 2 * a * c;
00277 if(d < 0) return false;
00278 dist = (b - sqrt(d)) / a;
00279 if(p) *p = this;
00280 return true;
00281 }
00282
00283 void Sphere::interiorIntersect(const Line3 &ray,
00284 const Object::Part *,
00285 double &dist,
00286 const Object::Part *&p) const
00287 {
00288 const Vector3 rp = invMap(ray.point);
00289 const Vector3 rd = invMap.basis(ray.direction);
00290 const double b = -2 * dot(rd, rp);
00291 const double a = 2 * rd.squareSum();
00292 const double c = rp.squareSum() - 1;
00293 const double d = b * b - 2 * a * c;
00294 dist = d < 0 ? 0 : (b + sqrt(d)) / a;
00295 p = this;
00296 }
00297
00298 void Sphere::map(const Vector3 &point, Vector3 &normal,
00299 Vector2 &texturePoint) const
00300 {
00301 map(point, normal);
00302
00303 Vector3 p = invMap(point);
00304
00305
00306
00307
00308
00309
00310
00311
00312 texturePoint[0] = p[0] == 0 ? p[2] < 0 ? 0 : 0.5 :
00313 (p[0] < 0 ? 0.25 : 0.75) - atan(p[2]/p[0]) / (2 * M_PI);
00314
00315
00316
00317
00318
00319
00320
00321
00322 texturePoint[1] = acos(-p[1]/p.length()) / M_PI;
00323 }
00324
00325
00416 bool Torus::intersect(const Line3 &ray, const Object *originObject,
00417 const Object::Part *, double &dist,
00418 const Object::Part **part) const
00419 {
00420
00421
00422
00423 Vector3 p = ray.point;
00424 invMap.map(p);
00425 Vector3 d = ray.direction;
00426 invMap.basis.map(d);
00427 const double l = d.length();
00428 d /= l;
00429
00430 const double spx = p[0]*p[0];
00431 const double spy = p[1]*p[1];
00432 const double spz = p[2]*p[2];
00433
00434 const double dpx = d[0]*p[0];
00435 const double dpy = d[1]*p[1];
00436 const double dpz = d[2]*p[2];
00437
00438 const double dp = dpx + dpy + dpz;
00439
00440 const double sma = majorRadius*majorRadius;
00441
00442 const double a = spx + spy + spz - minorRadius*minorRadius;
00443 const double b = a + sma;
00444
00445 const double k3 = 4*dp;
00446 const double k2 = 2*(2*dp*dp + a - sma*(1 - 2*d[1]*d[1]));
00447 const double k1 = 4*(dp*a - sma*(dp - 2*dpy));
00448 const double k0 = b*b - 4*sma*(spx + spz);
00449
00450
00451
00452 double roots[4];
00453 const int numberOfRealRoots =
00454 Math::quarticSolve(k3, k2, k1, k0, roots);
00455
00456 if(numberOfRealRoots == 0) return false;
00457
00458 if(originObject == this)
00459 {
00460 int minAbs = -1;
00461 for(int i=0; i<numberOfRealRoots; ++i)
00462 if(minAbs == -1 || fabs(roots[i]) < fabs(roots[minAbs])) minAbs = i;
00463 roots[minAbs] = -1;
00464 }
00465
00466 double minDist = 0;
00467 bool any = false;
00468 for(int i=0; i<numberOfRealRoots; ++i)
00469 {
00470 if(roots[i] > 0 && (!any || roots[i] < minDist))
00471 {
00472 minDist = roots[i];
00473 any = true;
00474 }
00475 }
00476 if(!any) return false;
00477 dist = minDist / l;
00478 if(part) *part = this;
00479 return true;
00480 }
00481
00482 void Torus::interiorIntersect(const Line3 &ray,
00483 const Object::Part *,
00484 double &dist,
00485 const Object::Part *&p) const
00486 {
00487 if(!intersect(ray, this, this, dist, &p)) p = this, dist = 0;
00488 }
00489
00490 void Torus::map(const Vector3 &point, Vector3 &normal) const
00491 {
00492 normal = point;
00493 invMap.map(normal);
00494 const double a = 1-majorRadius/sqrt(normal[0]*normal[0] + normal[2]*normal[2]);
00495 normal[0] *= a;
00496 normal[2] *= a;
00497 normalMap.map(normal);
00498 normal.normalize();
00499 }
00500
00501 void Torus::map(const Vector3 &point, Vector3 &normal,
00502 Vector2 &texturePoint) const
00503 {
00504 normal = point;
00505 invMap.map(normal);
00506 const double a = sqrt(normal[0]*normal[0] + normal[2]*normal[2]);
00507 const double b = a - majorRadius;
00508
00509 texturePoint[0] = normal[0] == 0 ? normal[2] < 0 ? 0 : 0.5 :
00510 (normal[0] < 0 ? 0.25 : 0.75) - atan(normal[2]/normal[0]) / (2 * M_PI);
00511
00512 texturePoint[1] = normal[1] == 0 ? b < 0 ? 0 : 0.5 :
00513 (normal[1] < 0 ? 0.25 : 0.75) - atan(b/normal[1]) / (2 * M_PI);
00514
00515 const double c = b/a;
00516 normal[0] *= c;
00517 normal[2] *= c;
00518 normalMap.map(normal);
00519 normal.normalize();
00520 }
00521
00522
00523 Polygon::Polygon(const Surface *surface,
00524 const std::vector<Vector3 *> &vertexList,
00525 const Vector2 &textureVertex1,
00526 const Vector2 &textureVertex2,
00527 const Vector2 &textureVertex3):
00528 Object::Part(surface), vertexList(vertexList)
00529 {
00530 if(vertexList.size() < 3) ARCHON_THROW1(ArgumentException, "Too few vertices");
00531 Vector3 x = *vertexList[2];
00532 x -= *vertexList[1];
00533 Vector3 y = *vertexList[0];
00534 y -= *vertexList[1];
00535 normal = x;
00536 normal *= y;
00537 normal.normalize();
00538
00539 if(!dynamic_cast<const Texture *>(surface)) return;
00540
00541
00542 Matrix3x3 m;
00543 m.x = Vector3(textureVertex3);
00544 m.x -= Vector3(textureVertex2);
00545 m.y = Vector3(textureVertex1);
00546 m.y -= Vector3(textureVertex2);
00547 m.z = m.x;
00548 m.z *= m.y;
00549
00550
00551 m /= Matrix3x3(x, y, normal);
00552
00553 texMapX = m.getRow1();
00554 texMapY = m.getRow2();
00555 texMapOrigin = textureVertex2;
00556 texMapOrigin -= Vector2(m(*vertexList[1]));
00557 }
00558
00559 Polygon::Polygon(const Surface *surface,
00560 const std::vector<Vector3 *> &vertexList,
00561 const Vector2 &textureVertex1,
00562 const Vector2 &textureVertex2):
00563 Object::Part(surface), vertexList(vertexList)
00564 {
00565 if(vertexList.size() < 3) ARCHON_THROW1(ArgumentException, "Too few vertices");
00566 normal = *vertexList[1];
00567 normal -= *vertexList[0];
00568 Vector3 v = *vertexList[2];
00569 v -= *vertexList[1];
00570 normal *= v;
00571 normal.normalize();
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609 }
00610
00611 bool Polygon::intersect(const Line3 &ray, const Object *originObject,
00612 const Object::Part *, double &dist,
00613 const Object::Part **part) const
00614 {
00615
00616
00617
00618
00619 if(originObject == this) return false;
00620
00621 const double cosine = dot(normal, ray.direction);
00622 if(cosine > 0) return false;
00623 Vector3 v, w = *vertexList.back();
00624 for(std::vector<Vector3 *>::const_iterator i=vertexList.begin();
00625 i != vertexList.end(); ++i)
00626 {
00627 v = **i;
00628 w -= v;
00629 v -= ray.point;
00630 w *= v;
00631
00632
00633
00634
00635
00636
00637 if(dot(w, ray.direction) > 0) return false;
00638 w = **i;
00639 }
00640
00641 if(part) *part = this;
00642 dist = dot(normal, v) / cosine;
00643 return true;
00644 }
00645
00646 bool Polygon::backfaceIntersect(const Line3 &ray,
00647 const Object *originObject,
00648 const Object::Part *, double &dist,
00649 const Object::Part **part) const
00650 {
00651
00652
00653
00654
00655 if(originObject == this) return false;
00656
00657 const double cosine = dot(normal, ray.direction);
00658 if(cosine < 0) return false;
00659
00660 Vector3 v, w = *vertexList.front();
00661 for(std::vector<Vector3 *>::const_iterator i=vertexList.end();
00662 i != vertexList.begin(); --i)
00663 {
00664 v = **(i-1);
00665 w -= v;
00666 v -= ray.point;
00667 w *= v;
00668
00669
00670
00671
00672
00673
00674 if(dot(w, ray.direction) > 0) return false;
00675 w = **(i-1);
00676 }
00677
00678 if(part) *part = this;
00679 dist = dot(normal, v) / cosine;
00680 return true;
00681 }
00682
00683 void Polygon::map(const Vector3 &point, Vector3 &normal,
00684 Vector2 &texturePoint) const
00685 {
00686 normal = this->normal;
00687
00688
00689
00690
00691
00692
00693
00694
00695 texturePoint[0] = dot(point, texMapX);
00696 texturePoint[1] = dot(point, texMapY);
00697 texturePoint += texMapOrigin;
00698 }
00699
00700 ConvexPolyhedron::
00701 ConvexPolyhedron(const std::vector<Polygon *> &polygonList):
00702 polygonList(polygonList)
00703 {
00704
00705 MinimalBoundingBall<3> ball;
00706 for(std::vector<Polygon *>::const_iterator i=polygonList.begin();
00707 i != polygonList.end(); ++i)
00708 {
00709 for(std::vector<Vector3 *>::iterator j=(*i)->vertexList.begin();
00710 j != (*i)->vertexList.end(); ++j)
00711 {
00712 const Vector3 *v = *j;
00713 MinimalBoundingBall<3>::Point p;
00714 p[0]=(*v)[0];
00715 p[1]=(*v)[1];
00716 p[2]=(*v)[2];
00717 ball.check_in(p);
00718 }
00719 }
00720 ball.build();
00721 const MinimalBoundingBall<3>::Point c = ball.center();
00722 boundingVolume.center.set(c[0], c[1], c[2]);
00723 boundingVolume.radius = sqrt(ball.squared_radius());
00724 }
00725
00726 ConvexPolyhedron::~ConvexPolyhedron()
00727 {
00728 for(std::vector<Polygon *>::iterator i=polygonList.begin();
00729 i != polygonList.end(); ++i) delete *i;
00730 }
00731
00732 bool ConvexPolyhedron::intersect(const Line3 &ray,
00733 const Object *originObject,
00734 const Part *originPart, double &dist,
00735 const Object::Part **part) const
00736 {
00737
00738
00739
00740
00741
00742 if(originObject == this) return false;
00743
00744 double d1 = 0, d2 = 0;
00745 if(!Math::intersect(Ray3(ray), boundingVolume, d1))
00746 return false;
00747
00748 bool hit = false;
00749 const Part *p1, *p2 = 0;
00750
00751 for(std::vector<Polygon *>::const_iterator i=polygonList.begin();
00752 i != polygonList.end(); ++i)
00753 if((*i)->intersect(ray, originObject, originPart, d1, &p1) &&
00754 (!hit || d1 < d2))
00755 {
00756 d2 = d1;
00757 p2 = p1;
00758 hit = true;
00759 }
00760
00761 if(hit)
00762 {
00763 dist = d2;
00764 if(part) *part = p2;
00765 return true;
00766 }
00767
00768 return false;
00769 }
00770
00771 void ConvexPolyhedron::interiorIntersect(const Line3 &ray,
00772 const Object::Part *originPart,
00773 double &dist,
00774 const Object::Part *&p) const
00775 {
00776 for(std::vector<Polygon *>::const_iterator i=polygonList.begin();
00777 i != polygonList.end(); ++i)
00778 {
00779 if(originPart == *i) continue;
00780 if((*i)->backfaceIntersect(ray, this, originPart, dist, &p)) return;
00781 }
00782
00783
00784 p = originPart;
00785 dist = 0;
00786 }
00787 }
00788 }