PBRT
|
00001 00002 /* 00003 pbrt source code Copyright(c) 1998-2012 Matt Pharr and Greg Humphreys. 00004 00005 This file is part of pbrt. 00006 00007 Redistribution and use in source and binary forms, with or without 00008 modification, are permitted provided that the following conditions are 00009 met: 00010 00011 - Redistributions of source code must retain the above copyright 00012 notice, this list of conditions and the following disclaimer. 00013 00014 - Redistributions in binary form must reproduce the above copyright 00015 notice, this list of conditions and the following disclaimer in the 00016 documentation and/or other materials provided with the distribution. 00017 00018 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 00019 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 00020 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 00021 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00022 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00023 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00024 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00025 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00026 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00028 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 00030 */ 00031 00032 #if defined(_MSC_VER) 00033 #pragma once 00034 #endif 00035 00036 #ifndef PBRT_CORE_GEOMETRY_H 00037 #define PBRT_CORE_GEOMETRY_H 00038 00039 // core/geometry.h* 00040 #include "pbrt.h" 00041 00042 // Geometry Declarations 00043 class Vector { 00044 public: 00045 // Vector Public Methods 00046 Vector() { x = y = z = 0.f; } 00047 Vector(float xx, float yy, float zz) 00048 : x(xx), y(yy), z(zz) { 00049 Assert(!HasNaNs()); 00050 } 00051 bool HasNaNs() const { return isnan(x) || isnan(y) || isnan(z); } 00052 explicit Vector(const Point &p); 00053 #ifndef NDEBUG 00054 // The default versions of these are fine for release builds; for debug 00055 // we define them so that we can add the Assert checks. 00056 Vector(const Vector &v) { 00057 Assert(!v.HasNaNs()); 00058 x = v.x; y = v.y; z = v.z; 00059 } 00060 00061 Vector &operator=(const Vector &v) { 00062 Assert(!v.HasNaNs()); 00063 x = v.x; y = v.y; z = v.z; 00064 return *this; 00065 } 00066 #endif // !NDEBUG 00067 Vector operator+(const Vector &v) const { 00068 Assert(!v.HasNaNs()); 00069 return Vector(x + v.x, y + v.y, z + v.z); 00070 } 00071 00072 Vector& operator+=(const Vector &v) { 00073 Assert(!v.HasNaNs()); 00074 x += v.x; y += v.y; z += v.z; 00075 return *this; 00076 } 00077 Vector operator-(const Vector &v) const { 00078 Assert(!v.HasNaNs()); 00079 return Vector(x - v.x, y - v.y, z - v.z); 00080 } 00081 00082 Vector& operator-=(const Vector &v) { 00083 Assert(!v.HasNaNs()); 00084 x -= v.x; y -= v.y; z -= v.z; 00085 return *this; 00086 } 00087 Vector operator*(float f) const { return Vector(f*x, f*y, f*z); } 00088 00089 Vector &operator*=(float f) { 00090 Assert(!isnan(f)); 00091 x *= f; y *= f; z *= f; 00092 return *this; 00093 } 00094 Vector operator/(float f) const { 00095 Assert(f != 0); 00096 float inv = 1.f / f; 00097 return Vector(x * inv, y * inv, z * inv); 00098 } 00099 00100 Vector &operator/=(float f) { 00101 Assert(f != 0); 00102 float inv = 1.f / f; 00103 x *= inv; y *= inv; z *= inv; 00104 return *this; 00105 } 00106 Vector operator-() const { return Vector(-x, -y, -z); } 00107 float operator[](int i) const { 00108 Assert(i >= 0 && i <= 2); 00109 return (&x)[i]; 00110 } 00111 00112 float &operator[](int i) { 00113 Assert(i >= 0 && i <= 2); 00114 return (&x)[i]; 00115 } 00116 float LengthSquared() const { return x*x + y*y + z*z; } 00117 float Length() const { return sqrtf(LengthSquared()); } 00118 explicit Vector(const Normal &n); 00119 00120 bool operator==(const Vector &v) const { 00121 return x == v.x && y == v.y && z == v.z; 00122 } 00123 bool operator!=(const Vector &v) const { 00124 return x != v.x || y != v.y || z != v.z; 00125 } 00126 00127 // Vector Public Data 00128 float x, y, z; 00129 }; 00130 00131 00132 class Point { 00133 public: 00134 // Point Public Methods 00135 Point() { x = y = z = 0.f; } 00136 Point(float xx, float yy, float zz) 00137 : x(xx), y(yy), z(zz) { 00138 Assert(!HasNaNs()); 00139 } 00140 #ifndef NDEBUG 00141 Point(const Point &p) { 00142 Assert(!p.HasNaNs()); 00143 x = p.x; y = p.y; z = p.z; 00144 } 00145 00146 Point &operator=(const Point &p) { 00147 Assert(!p.HasNaNs()); 00148 x = p.x; y = p.y; z = p.z; 00149 return *this; 00150 } 00151 #endif // !NDEBUG 00152 Point operator+(const Vector &v) const { 00153 Assert(!v.HasNaNs()); 00154 return Point(x + v.x, y + v.y, z + v.z); 00155 } 00156 00157 Point &operator+=(const Vector &v) { 00158 Assert(!v.HasNaNs()); 00159 x += v.x; y += v.y; z += v.z; 00160 return *this; 00161 } 00162 Vector operator-(const Point &p) const { 00163 Assert(!p.HasNaNs()); 00164 return Vector(x - p.x, y - p.y, z - p.z); 00165 } 00166 00167 Point operator-(const Vector &v) const { 00168 Assert(!v.HasNaNs()); 00169 return Point(x - v.x, y - v.y, z - v.z); 00170 } 00171 00172 Point &operator-=(const Vector &v) { 00173 Assert(!v.HasNaNs()); 00174 x -= v.x; y -= v.y; z -= v.z; 00175 return *this; 00176 } 00177 Point &operator+=(const Point &p) { 00178 Assert(!p.HasNaNs()); 00179 x += p.x; y += p.y; z += p.z; 00180 return *this; 00181 } 00182 Point operator+(const Point &p) const { 00183 Assert(!p.HasNaNs()); 00184 return Point(x + p.x, y + p.y, z + p.z); 00185 } 00186 Point operator* (float f) const { 00187 return Point(f*x, f*y, f*z); 00188 } 00189 Point &operator*=(float f) { 00190 x *= f; y *= f; z *= f; 00191 return *this; 00192 } 00193 Point operator/ (float f) const { 00194 float inv = 1.f/f; 00195 return Point(inv*x, inv*y, inv*z); 00196 } 00197 Point &operator/=(float f) { 00198 float inv = 1.f/f; 00199 x *= inv; y *= inv; z *= inv; 00200 return *this; 00201 } 00202 float operator[](int i) const { 00203 Assert(i >= 0 && i <= 2); 00204 return (&x)[i]; 00205 } 00206 00207 float &operator[](int i) { 00208 Assert(i >= 0 && i <= 2); 00209 return (&x)[i]; 00210 } 00211 bool HasNaNs() const { 00212 return isnan(x) || isnan(y) || isnan(z); 00213 } 00214 00215 bool operator==(const Point &p) const { 00216 return x == p.x && y == p.y && z == p.z; 00217 } 00218 bool operator!=(const Point &p) const { 00219 return x != p.x || y != p.y || z != p.z; 00220 } 00221 00222 // Point Public Data 00223 float x, y, z; 00224 }; 00225 00226 00227 class Normal { 00228 public: 00229 // Normal Public Methods 00230 Normal() { x = y = z = 0.f; } 00231 Normal(float xx, float yy, float zz) 00232 : x(xx), y(yy), z(zz) { 00233 Assert(!HasNaNs()); 00234 } 00235 Normal operator-() const { 00236 return Normal(-x, -y, -z); 00237 } 00238 Normal operator+ (const Normal &n) const { 00239 Assert(!n.HasNaNs()); 00240 return Normal(x + n.x, y + n.y, z + n.z); 00241 } 00242 00243 Normal& operator+=(const Normal &n) { 00244 Assert(!n.HasNaNs()); 00245 x += n.x; y += n.y; z += n.z; 00246 return *this; 00247 } 00248 Normal operator- (const Normal &n) const { 00249 Assert(!n.HasNaNs()); 00250 return Normal(x - n.x, y - n.y, z - n.z); 00251 } 00252 00253 Normal& operator-=(const Normal &n) { 00254 Assert(!n.HasNaNs()); 00255 x -= n.x; y -= n.y; z -= n.z; 00256 return *this; 00257 } 00258 bool HasNaNs() const { 00259 return isnan(x) || isnan(y) || isnan(z); 00260 } 00261 Normal operator*(float f) const { 00262 return Normal(f*x, f*y, f*z); 00263 } 00264 00265 Normal &operator*=(float f) { 00266 x *= f; y *= f; z *= f; 00267 return *this; 00268 } 00269 Normal operator/(float f) const { 00270 Assert(f != 0); 00271 float inv = 1.f/f; 00272 return Normal(x * inv, y * inv, z * inv); 00273 } 00274 00275 Normal &operator/=(float f) { 00276 Assert(f != 0); 00277 float inv = 1.f/f; 00278 x *= inv; y *= inv; z *= inv; 00279 return *this; 00280 } 00281 float LengthSquared() const { return x*x + y*y + z*z; } 00282 float Length() const { return sqrtf(LengthSquared()); } 00283 00284 #ifndef NDEBUG 00285 Normal(const Normal &n) { 00286 Assert(!n.HasNaNs()); 00287 x = n.x; y = n.y; z = n.z; 00288 } 00289 00290 Normal &operator=(const Normal &n) { 00291 Assert(!n.HasNaNs()); 00292 x = n.x; y = n.y; z = n.z; 00293 return *this; 00294 } 00295 #endif // !NDEBUG 00296 explicit Normal(const Vector &v) 00297 : x(v.x), y(v.y), z(v.z) { 00298 Assert(!v.HasNaNs()); 00299 } 00300 float operator[](int i) const { 00301 Assert(i >= 0 && i <= 2); 00302 return (&x)[i]; 00303 } 00304 00305 float &operator[](int i) { 00306 Assert(i >= 0 && i <= 2); 00307 return (&x)[i]; 00308 } 00309 00310 bool operator==(const Normal &n) const { 00311 return x == n.x && y == n.y && z == n.z; 00312 } 00313 bool operator!=(const Normal &n) const { 00314 return x != n.x || y != n.y || z != n.z; 00315 } 00316 00317 // Normal Public Data 00318 float x, y, z; 00319 }; 00320 00321 00322 class Ray { 00323 public: 00324 // Ray Public Methods 00325 Ray() : mint(0.f), maxt(INFINITY), time(0.f), depth(0) { } 00326 Ray(const Point &origin, const Vector &direction, 00327 float start, float end = INFINITY, float t = 0.f, int d = 0) 00328 : o(origin), d(direction), mint(start), maxt(end), time(t), depth(d) { } 00329 Ray(const Point &origin, const Vector &direction, const Ray &parent, 00330 float start, float end = INFINITY) 00331 : o(origin), d(direction), mint(start), maxt(end), 00332 time(parent.time), depth(parent.depth+1) { } 00333 Point operator()(float t) const { return o + d * t; } 00334 bool HasNaNs() const { 00335 return (o.HasNaNs() || d.HasNaNs() || 00336 isnan(mint) || isnan(maxt)); 00337 } 00338 00339 // Ray Public Data 00340 Point o; 00341 Vector d; 00342 mutable float mint, maxt; 00343 float time; 00344 int depth; 00345 }; 00346 00347 00348 class RayDifferential : public Ray { 00349 public: 00350 // RayDifferential Public Methods 00351 RayDifferential() { hasDifferentials = false; } 00352 RayDifferential(const Point &org, const Vector &dir, float start, 00353 float end = INFINITY, float t = 0.f, int d = 0) 00354 : Ray(org, dir, start, end, t, d) { 00355 hasDifferentials = false; 00356 } 00357 RayDifferential(const Point &org, const Vector &dir, const Ray &parent, 00358 float start, float end = INFINITY) 00359 : Ray(org, dir, start, end, parent.time, parent.depth+1) { 00360 hasDifferentials = false; 00361 } 00362 explicit RayDifferential(const Ray &ray) : Ray(ray) { 00363 hasDifferentials = false; 00364 } 00365 bool HasNaNs() const { 00366 return Ray::HasNaNs() || 00367 (hasDifferentials && (rxOrigin.HasNaNs() || ryOrigin.HasNaNs() || 00368 rxDirection.HasNaNs() || ryDirection.HasNaNs())); 00369 } 00370 void ScaleDifferentials(float s) { 00371 rxOrigin = o + (rxOrigin - o) * s; 00372 ryOrigin = o + (ryOrigin - o) * s; 00373 rxDirection = d + (rxDirection - d) * s; 00374 ryDirection = d + (ryDirection - d) * s; 00375 } 00376 00377 // RayDifferential Public Data 00378 bool hasDifferentials; 00379 Point rxOrigin, ryOrigin; 00380 Vector rxDirection, ryDirection; 00381 }; 00382 00383 00384 class BBox { 00385 public: 00386 // BBox Public Methods 00387 BBox() { 00388 pMin = Point( INFINITY, INFINITY, INFINITY); 00389 pMax = Point(-INFINITY, -INFINITY, -INFINITY); 00390 } 00391 BBox(const Point &p) : pMin(p), pMax(p) { } 00392 BBox(const Point &p1, const Point &p2) { 00393 pMin = Point(min(p1.x, p2.x), min(p1.y, p2.y), min(p1.z, p2.z)); 00394 pMax = Point(max(p1.x, p2.x), max(p1.y, p2.y), max(p1.z, p2.z)); 00395 } 00396 friend BBox Union(const BBox &b, const Point &p); 00397 friend BBox Union(const BBox &b, const BBox &b2); 00398 bool Overlaps(const BBox &b) const { 00399 bool x = (pMax.x >= b.pMin.x) && (pMin.x <= b.pMax.x); 00400 bool y = (pMax.y >= b.pMin.y) && (pMin.y <= b.pMax.y); 00401 bool z = (pMax.z >= b.pMin.z) && (pMin.z <= b.pMax.z); 00402 return (x && y && z); 00403 } 00404 bool Inside(const Point &pt) const { 00405 return (pt.x >= pMin.x && pt.x <= pMax.x && 00406 pt.y >= pMin.y && pt.y <= pMax.y && 00407 pt.z >= pMin.z && pt.z <= pMax.z); 00408 } 00409 void Expand(float delta) { 00410 pMin -= Vector(delta, delta, delta); 00411 pMax += Vector(delta, delta, delta); 00412 } 00413 float SurfaceArea() const { 00414 Vector d = pMax - pMin; 00415 return 2.f * (d.x * d.y + d.x * d.z + d.y * d.z); 00416 } 00417 float Volume() const { 00418 Vector d = pMax - pMin; 00419 return d.x * d.y * d.z; 00420 } 00421 int MaximumExtent() const { 00422 Vector diag = pMax - pMin; 00423 if (diag.x > diag.y && diag.x > diag.z) 00424 return 0; 00425 else if (diag.y > diag.z) 00426 return 1; 00427 else 00428 return 2; 00429 } 00430 const Point &operator[](int i) const; 00431 Point &operator[](int i); 00432 Point Lerp(float tx, float ty, float tz) const { 00433 return Point(::Lerp(tx, pMin.x, pMax.x), ::Lerp(ty, pMin.y, pMax.y), 00434 ::Lerp(tz, pMin.z, pMax.z)); 00435 } 00436 Vector Offset(const Point &p) const { 00437 return Vector((p.x - pMin.x) / (pMax.x - pMin.x), 00438 (p.y - pMin.y) / (pMax.y - pMin.y), 00439 (p.z - pMin.z) / (pMax.z - pMin.z)); 00440 } 00441 void BoundingSphere(Point *c, float *rad) const; 00442 bool IntersectP(const Ray &ray, float *hitt0 = NULL, float *hitt1 = NULL) const; 00443 00444 bool operator==(const BBox &b) const { 00445 return b.pMin == pMin && b.pMax == pMax; 00446 } 00447 bool operator!=(const BBox &b) const { 00448 return b.pMin != pMin || b.pMax != pMax; 00449 } 00450 00451 // BBox Public Data 00452 Point pMin, pMax; 00453 }; 00454 00455 00456 00457 // Geometry Inline Functions 00458 inline Vector::Vector(const Point &p) 00459 : x(p.x), y(p.y), z(p.z) { 00460 Assert(!HasNaNs()); 00461 } 00462 00463 00464 inline Vector operator*(float f, const Vector &v) { return v*f; } 00465 inline float Dot(const Vector &v1, const Vector &v2) { 00466 Assert(!v1.HasNaNs() && !v2.HasNaNs()); 00467 return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; 00468 } 00469 00470 00471 inline float AbsDot(const Vector &v1, const Vector &v2) { 00472 Assert(!v1.HasNaNs() && !v2.HasNaNs()); 00473 return fabsf(Dot(v1, v2)); 00474 } 00475 00476 00477 inline Vector Cross(const Vector &v1, const Vector &v2) { 00478 Assert(!v1.HasNaNs() && !v2.HasNaNs()); 00479 double v1x = v1.x, v1y = v1.y, v1z = v1.z; 00480 double v2x = v2.x, v2y = v2.y, v2z = v2.z; 00481 return Vector((v1y * v2z) - (v1z * v2y), 00482 (v1z * v2x) - (v1x * v2z), 00483 (v1x * v2y) - (v1y * v2x)); 00484 } 00485 00486 00487 inline Vector Cross(const Vector &v1, const Normal &v2) { 00488 Assert(!v1.HasNaNs() && !v2.HasNaNs()); 00489 double v1x = v1.x, v1y = v1.y, v1z = v1.z; 00490 double v2x = v2.x, v2y = v2.y, v2z = v2.z; 00491 return Vector((v1y * v2z) - (v1z * v2y), 00492 (v1z * v2x) - (v1x * v2z), 00493 (v1x * v2y) - (v1y * v2x)); 00494 } 00495 00496 00497 inline Vector Cross(const Normal &v1, const Vector &v2) { 00498 Assert(!v1.HasNaNs() && !v2.HasNaNs()); 00499 double v1x = v1.x, v1y = v1.y, v1z = v1.z; 00500 double v2x = v2.x, v2y = v2.y, v2z = v2.z; 00501 return Vector((v1y * v2z) - (v1z * v2y), 00502 (v1z * v2x) - (v1x * v2z), 00503 (v1x * v2y) - (v1y * v2x)); 00504 } 00505 00506 00507 inline Vector Normalize(const Vector &v) { return v / v.Length(); } 00508 inline void CoordinateSystem(const Vector &v1, Vector *v2, Vector *v3) { 00509 if (fabsf(v1.x) > fabsf(v1.y)) { 00510 float invLen = 1.f / sqrtf(v1.x*v1.x + v1.z*v1.z); 00511 *v2 = Vector(-v1.z * invLen, 0.f, v1.x * invLen); 00512 } 00513 else { 00514 float invLen = 1.f / sqrtf(v1.y*v1.y + v1.z*v1.z); 00515 *v2 = Vector(0.f, v1.z * invLen, -v1.y * invLen); 00516 } 00517 *v3 = Cross(v1, *v2); 00518 } 00519 00520 00521 inline float Distance(const Point &p1, const Point &p2) { 00522 return (p1 - p2).Length(); 00523 } 00524 00525 00526 inline float DistanceSquared(const Point &p1, const Point &p2) { 00527 return (p1 - p2).LengthSquared(); 00528 } 00529 00530 00531 inline Point operator*(float f, const Point &p) { 00532 Assert(!p.HasNaNs()); 00533 return p*f; 00534 } 00535 00536 00537 inline Normal operator*(float f, const Normal &n) { 00538 return Normal(f*n.x, f*n.y, f*n.z); 00539 } 00540 00541 00542 inline Normal Normalize(const Normal &n) { 00543 return n / n.Length(); 00544 } 00545 00546 00547 inline Vector::Vector(const Normal &n) 00548 : x(n.x), y(n.y), z(n.z) { 00549 Assert(!n.HasNaNs()); 00550 } 00551 00552 00553 inline float Dot(const Normal &n1, const Vector &v2) { 00554 Assert(!n1.HasNaNs() && !v2.HasNaNs()); 00555 return n1.x * v2.x + n1.y * v2.y + n1.z * v2.z; 00556 } 00557 00558 00559 inline float Dot(const Vector &v1, const Normal &n2) { 00560 Assert(!v1.HasNaNs() && !n2.HasNaNs()); 00561 return v1.x * n2.x + v1.y * n2.y + v1.z * n2.z; 00562 } 00563 00564 00565 inline float Dot(const Normal &n1, const Normal &n2) { 00566 Assert(!n1.HasNaNs() && !n2.HasNaNs()); 00567 return n1.x * n2.x + n1.y * n2.y + n1.z * n2.z; 00568 } 00569 00570 00571 inline float AbsDot(const Normal &n1, const Vector &v2) { 00572 Assert(!n1.HasNaNs() && !v2.HasNaNs()); 00573 return fabsf(n1.x * v2.x + n1.y * v2.y + n1.z * v2.z); 00574 } 00575 00576 00577 inline float AbsDot(const Vector &v1, const Normal &n2) { 00578 Assert(!v1.HasNaNs() && !n2.HasNaNs()); 00579 return fabsf(v1.x * n2.x + v1.y * n2.y + v1.z * n2.z); 00580 } 00581 00582 00583 inline float AbsDot(const Normal &n1, const Normal &n2) { 00584 Assert(!n1.HasNaNs() && !n2.HasNaNs()); 00585 return fabsf(n1.x * n2.x + n1.y * n2.y + n1.z * n2.z); 00586 } 00587 00588 00589 inline Normal Faceforward(const Normal &n, const Vector &v) { 00590 return (Dot(n, v) < 0.f) ? -n : n; 00591 } 00592 00593 00594 inline Normal Faceforward(const Normal &n, const Normal &n2) { 00595 return (Dot(n, n2) < 0.f) ? -n : n; 00596 } 00597 00598 00599 00600 inline Vector Faceforward(const Vector &v, const Vector &v2) { 00601 return (Dot(v, v2) < 0.f) ? -v : v; 00602 } 00603 00604 00605 00606 inline Vector Faceforward(const Vector &v, const Normal &n2) { 00607 return (Dot(v, n2) < 0.f) ? -v : v; 00608 } 00609 00610 00611 inline const Point &BBox::operator[](int i) const { 00612 Assert(i == 0 || i == 1); 00613 return (&pMin)[i]; 00614 } 00615 00616 00617 00618 inline Point &BBox::operator[](int i) { 00619 Assert(i == 0 || i == 1); 00620 return (&pMin)[i]; 00621 } 00622 00623 00624 inline Vector SphericalDirection(float sintheta, 00625 float costheta, float phi) { 00626 return Vector(sintheta * cosf(phi), 00627 sintheta * sinf(phi), 00628 costheta); 00629 } 00630 00631 00632 inline Vector SphericalDirection(float sintheta, float costheta, 00633 float phi, const Vector &x, 00634 const Vector &y, const Vector &z) { 00635 return sintheta * cosf(phi) * x + 00636 sintheta * sinf(phi) * y + costheta * z; 00637 } 00638 00639 00640 inline float SphericalTheta(const Vector &v) { 00641 return acosf(Clamp(v.z, -1.f, 1.f)); 00642 } 00643 00644 00645 inline float SphericalPhi(const Vector &v) { 00646 float p = atan2f(v.y, v.x); 00647 return (p < 0.f) ? p + 2.f*M_PI : p; 00648 } 00649 00650 00651 00652 #endif // PBRT_CORE_GEOMETRY_H