world.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #include <float.h>
00021 #include <vector>
00022 
00023 #include <archon/util/random.H>
00024 #include <archon/util/color.H>
00025 #include <archon/util/image.H>
00026 
00027 #include "light.H"
00028 #include "object.H"
00029 #include "world.H"
00030 
00031 #if ! defined M_PI
00032 #define M_E           2.7182818284590452353602874713526625  /* e */
00033 #define M_LOG2E       1.4426950408889634073599246810018922  /* log_2 e */
00034 #define M_LOG10E      0.4342944819032518276511289189166051  /* log_10 e */
00035 #define M_LN2         0.6931471805599453094172321214581766  /* log_e 2 */
00036 #define M_LN10        2.3025850929940456840179914546843642  /* log_e 10 */
00037 #define M_PI          3.1415926535897932384626433832795029  /* pi */
00038 #define M_PI_2        1.5707963267948966192313216916397514  /* pi/2 */
00039 #define M_PI_4        0.7853981633974483096156608458198757  /* pi/4 */
00040 #define M_1_PI        0.3183098861837906715377675267450287  /* 1/pi */
00041 #define M_2_PI        0.6366197723675813430755350534900574  /* 2/pi */
00042 #define M_2_SQRTPI    1.1283791670955125738961589031215452  /* 2/sqrt(pi) */
00043 #define M_SQRT2       1.4142135623730950488016887242096981  /* sqrt(2) */
00044 #define M_SQRT1_2     0.7071067811865475244008443621048490  /* 1/sqrt(2) */
00045 #endif
00046 
00047 namespace Archon
00048 {
00049   using namespace Utilities;
00050   using namespace Math;
00051 
00052   namespace Raytracer
00053   {
00054     World::World(const Vector4 &backgroundColor,
00055                  double significanceThreshold,
00056                  int maxDepth,
00057                  bool enableTransmission,
00058                  unsigned photonsInEstimate,
00059                  bool showOnlyPhotonMap):
00060       globalAmbientIntencity(0.4),
00061       backgroundColor(backgroundColor),
00062       significanceThreshold(significanceThreshold),
00063       maxDepth(maxDepth),
00064       enableTransmission(enableTransmission),
00065       photonsInEstimate(photonsInEstimate),
00066       showOnlyPhotonMap(showOnlyPhotonMap) {}
00067 
00068     World::World(double globalAmbientIntencity,
00069                  const Vector4 &backgroundColor,
00070                  double significanceThreshold,
00071                  int maxDepth,
00072                  bool enableTransmission,
00073                  unsigned photonsInEstimate,
00074                  bool showOnlyPhotonMap):
00075       globalAmbientIntencity(globalAmbientIntencity),
00076       backgroundColor(backgroundColor),
00077       significanceThreshold(significanceThreshold),
00078       maxDepth(maxDepth),
00079       enableTransmission(enableTransmission),
00080       photonsInEstimate(photonsInEstimate),
00081       showOnlyPhotonMap(showOnlyPhotonMap)
00082     {
00083       textureList.push_back(Image("texture/leafpolar.ppm"));     // 0
00084       textureList.push_back(Image("texture/moon1polar.ppm"));    // 1
00085       textureList.push_back(Image("texture/kristian.ppm"));      // 2
00086       textureList.push_back(Image("texture/granite.ppm"));       // 3
00087       textureList.push_back(Image("texture/skin.ppm"));          // 4
00088       textureList.push_back(Image("texture/spotty.ppm"));        // 5
00089       textureList.push_back(Image("texture/bkristia.ppm"));      // 6
00090       textureList.push_back(Image("texture/chess-marble.ppm"));  // 7
00091       textureList.push_back(Image("texture/glass.ppm"));         // 8
00092 
00093       surfaceList.push_back(new StandardSurface(Color::seagreen,  0.05, 0.1, 0.05, 0.9, 20, 20, 1.15));    // 0
00094       surfaceList.push_back(new StandardSurface(Color::crimson,   0.1, 0.2, 0.9, 0.1, 60, 20, 1.2));    // 1
00095       surfaceList.push_back(new StandardSurface(Color::steelblue, 0.1, 0.2, 0.9, 0.1, 60, 20, 1.2));    // 2
00096       surfaceList.push_back(new StandardSurface(Color::darkolivegreen));                                // 3
00097       surfaceList.push_back(new StandardSurface(Color::gold));                                          // 4
00098       surfaceList.push_back(new Texture(textureList[3], 0.1, 0.8, 0.0, 0.0, 20, 20));                   // 5
00099       surfaceList.push_back(new Texture(textureList[4], 0.9, 0.9, 0.1, 0.1, 20, 20, 1, 3, 3));          // 6
00100       surfaceList.push_back(new Texture(textureList[5], 0.1, 0.5, 0.5, 0.1, 20, 20, 1, 2, 2));          // 7
00101       surfaceList.push_back(new Texture(textureList[2], 0.1, 0.9, 0.1, 0.1, 20, 20));                   // 8
00102       surfaceList.push_back(new Texture(textureList[6], 0.1, 0.2, 0.8, 0.8, 20, 20));                   // 9
00103       surfaceList.push_back(new Texture(textureList[6], 0.1, 0.9, 0.1, 0.1, 20, 20));                   // 10
00104       surfaceList.push_back(new StandardSurface(Vector4(1, 1, 1), 0.0, 0.1, 0.2, 0.6, 20, 20, 1.33));  // 11
00105       surfaceList.push_back(new Texture(textureList[8], 0.9, 0, 0, 0, 20, 20));                         // 12
00106       surfaceList.push_back(new Texture(textureList[7], 0.1, 0.0, 0.5, 0.5, 20, 20, 1, 3, 3));          // 13
00107       surfaceList.push_back(new Texture(textureList[8], 0.1, 0.18, 0.05, 0.9, 60, 20, 1.2));            // 14
00108       surfaceList.push_back(new StandardSurface(Vector4(1, 1, 1), 0, 0.8, 0.1, 0, 20, 20, 1.33));  // 15
00109 
00110 
00111       //    objectList.push_back(new Sphere(surfaceList[7], Vector3(-1.5,  1.5, -3), Vector3::unitY, -Vector3::unitZ, 1));
00112       //    objectList.push_back(new Sphere(surfaceList[6], Vector3( 0,    0.5, -2), Vector3::unitY, -Vector3::unitZ, 1));
00113       //    objectList.push_back(new Sphere(surfaceList[5], Vector3( 1.5, -0.5, -1), Vector3::unitY, -Vector3::unitZ, 1));
00114       //    objectList.push_back(new Sphere(surfaceList[0], Vector3(-3, 1.6, 1.7), Vector3::unitY, -Vector3::unitZ, 1.2));
00115       //    objectList.push_back(new Sphere(surfaceList[2], Vector3(0.5, 0, 0), Vector3::unitY, -Vector3::unitZ, 1));
00116       //objectList.push_back(new Sphere(surfaceList[11], Vector3(0, 4, 0), Vector3::unitY, -Vector3::unitZ, 2));
00117 
00118       //    objectList.push_back(new Torus(surfaceList[1], Vector3(-1, 3, -2), Vector3::unitY, Vector3::unitX, 2, 0.8));
00119       objectList.push_back(new Torus(surfaceList[11], CoordSystem3(Vector3(0, 4, 0), Matrix3x3::identity), 2, 1));
00120 
00121       // box
00122       /*
00123         {
00124         Vector3 v0(-1, -1, -1);
00125         Vector3 v1(-1, -1,  1);
00126         Vector3 v2( 1, -1,  1);
00127         Vector3 v3( 1, -1, -1);
00128         Vector3 v4(-1,  1, -1);
00129         Vector3 v5(-1,  1,  1);
00130         Vector3 v6( 1,  1,  1);
00131         Vector3 v7( 1,  1, -1);
00132 
00133         CoordSystem3 modelSystem(Vector3::zero, Matrix3x3::identity);
00134         modelSystem.origin += Vector3(0.7, 2, 3.4);
00135         //     modelSystem.origin += normalize(Vector3(0, 1, 5) - modelSystem.origin)*1;
00136         modelSystem.basis.rotateRect(Vector3(0, 1, 0), M_PI/4);
00137         modelSystem.basis.rotateRect(Vector3(1, 0, 0), M_PI/4);
00138         //modelSystem.basis *= 0.5;
00139 
00140         vertexList.push_back(new Vector3(modelSystem * v0));
00141         vertexList.push_back(new Vector3(modelSystem * v1));
00142         vertexList.push_back(new Vector3(modelSystem * v2));
00143         vertexList.push_back(new Vector3(modelSystem * v3));
00144         vertexList.push_back(new Vector3(modelSystem * v4));
00145         vertexList.push_back(new Vector3(modelSystem * v5));
00146         vertexList.push_back(new Vector3(modelSystem * v6));
00147         vertexList.push_back(new Vector3(modelSystem * v7));
00148 
00149         std::vector<Vector3 *> left;
00150         left.push_back(vertexList[0]);
00151         left.push_back(vertexList[1]);
00152         left.push_back(vertexList[5]);
00153         left.push_back(vertexList[4]);
00154 
00155         std::vector<Vector3 *> right;
00156         right.push_back(vertexList[2]);
00157         right.push_back(vertexList[3]);
00158         right.push_back(vertexList[7]);
00159         right.push_back(vertexList[6]);
00160 
00161         std::vector<Vector3 *> down;
00162         down.push_back(vertexList[3]);
00163         down.push_back(vertexList[2]);
00164         down.push_back(vertexList[1]);
00165         down.push_back(vertexList[0]);
00166 
00167         std::vector<Vector3 *> up;
00168         up.push_back(vertexList[4]);
00169         up.push_back(vertexList[5]);
00170         up.push_back(vertexList[6]);
00171         up.push_back(vertexList[7]);
00172 
00173         std::vector<Vector3 *> far;
00174         far.push_back(vertexList[0]);
00175         far.push_back(vertexList[4]);
00176         far.push_back(vertexList[7]);
00177         far.push_back(vertexList[3]);
00178 
00179         std::vector<Vector3 *> near;
00180         near.push_back(vertexList[1]);
00181         near.push_back(vertexList[2]);
00182         near.push_back(vertexList[6]);
00183         near.push_back(vertexList[5]);
00184 
00185 
00186         std::vector<Polygon *> box1;
00187         box1.push_back(new Polygon(surfaceList[14],  left,  Vector2::zero, Vector2::unitX));
00188         box1.push_back(new Polygon(surfaceList[14],  right, Vector2::zero, Vector2::unitX));
00189         box1.push_back(new Polygon(surfaceList[14],  down,  Vector2::zero, Vector2::unitX));
00190         box1.push_back(new Polygon(surfaceList[14],  up,    Vector2::zero, Vector2::unitX));
00191         box1.push_back(new Polygon(surfaceList[14],  far,   Vector2::zero, Vector2::unitX));
00192         box1.push_back(new Polygon(surfaceList[14],  near,  Vector2::zero, Vector2::unitX));
00193 
00194         objectList.push_back(new ConvexPolyhedron(box1));
00195         }
00196       */
00197       // floor
00198       {
00199         Vector3 v0(-1, 0, -1);
00200         Vector3 v1(-1, 0,  1);
00201         Vector3 v2( 1, 0,  1);
00202         Vector3 v3( 1, 0, -1);
00203 
00204         CoordSystem3 modelSystem(Vector3(0, 0, 0), Matrix3x3::identity);
00205         modelSystem.origin += Vector3(0, 0, 0);
00206         modelSystem.basis *= 5;
00207 
00208         const int n = vertexList.size();
00209 
00210         vertexList.push_back(new Vector3(modelSystem(v1)));
00211         vertexList.push_back(new Vector3(modelSystem(v2)));
00212         vertexList.push_back(new Vector3(modelSystem(v3)));
00213         vertexList.push_back(new Vector3(modelSystem(v0)));
00214 
00215         std::vector<Vector3 *> floor;
00216         floor.push_back(vertexList[n + 0]);
00217         floor.push_back(vertexList[n + 1]);
00218         floor.push_back(vertexList[n + 2]);
00219         floor.push_back(vertexList[n + 3]);
00220 
00221         objectList.push_back(new Polygon(surfaceList[15], floor, Vector2(0, 0), Vector2(1, 0)));
00222       }
00223 
00224       // right wall
00225       {
00226         Vector3 v0(-1, 0, -1);
00227         Vector3 v1(-1, 0,  1);
00228         Vector3 v2( 1, 0,  1);
00229         Vector3 v3( 1, 0, -1);
00230 
00231         CoordSystem3 modelSystem(Vector3(0, 0, 0), Matrix3x3::identity);
00232         modelSystem.origin += Vector3(5, 5, 0);
00233         modelSystem.basis.roll(M_PI/2);
00234         modelSystem.basis *= 5;
00235 
00236         const int n = vertexList.size();
00237 
00238         vertexList.push_back(new Vector3(modelSystem(v1)));
00239         vertexList.push_back(new Vector3(modelSystem(v2)));
00240         vertexList.push_back(new Vector3(modelSystem(v3)));
00241         vertexList.push_back(new Vector3(modelSystem(v0)));
00242 
00243         std::vector<Vector3 *> polygon;
00244         polygon.push_back(vertexList[n + 0]);
00245         polygon.push_back(vertexList[n + 1]);
00246         polygon.push_back(vertexList[n + 2]);
00247         polygon.push_back(vertexList[n + 3]);
00248 
00249         objectList.push_back(new Polygon(surfaceList[15], polygon, Vector2(0, 0), Vector2(1, 0)));
00250       }
00251 
00252 
00253       // background
00254       /*
00255         {
00256         Vector3 v0(-1, 0, -1);
00257         Vector3 v1(-1, 0,  1);
00258         Vector3 v2( 1, 0,  1);
00259         Vector3 v3( 1, 0, -1);
00260 
00261         CoordSystem3 modelSystem(Vector3(0, 1, 5), Matrix3x3::identity);
00262         modelSystem.basis.pitchRect(M_PI/2-M_PI/10);
00263         modelSystem.origin += modelSystem.basis.z * -10;
00264         modelSystem.origin += modelSystem.basis.y * -40;
00265         modelSystem.basis *= 25;
00266 
00267         const int n = vertexList.size();
00268 
00269         vertexList.push_back(new Vector3(modelSystem.transform(v1)));
00270         vertexList.push_back(new Vector3(modelSystem.transform(v2)));
00271         vertexList.push_back(new Vector3(modelSystem.transform(v3)));
00272         vertexList.push_back(new Vector3(modelSystem.transform(v0)));
00273 
00274         std::vector<Vector3 *> background;
00275         background.push_back(vertexList[n + 0]);
00276         background.push_back(vertexList[n + 1]);
00277         background.push_back(vertexList[n + 2]);
00278         background.push_back(vertexList[n + 3]);
00279 
00280         objectList.push_back(new Polygon(surfaceList[12], background, Vector2::zero, Vector2::unitX));
00281         }
00282       */
00283 
00284       //    lightList.push_back(new Light(Vector3(10, 0, 0), Color::darkmagenta));
00285       //    lightList.push_back(new Light(Vector3(10, 10, 0), Color::darkred * 1.2));
00286       //    lightList.push_back(new Light(Vector3(0, 0, 10), Color::goldenrod * 1.2));
00287 
00288       // lightList.push_back(new Light(Vector3(-7, 10, 5), Color::white));
00289       // lightList.push_back(new Light(Vector3( 0,  5, 5), Color::white));
00290       // lightList.push_back(new Light(Vector3( 7, 10, 5), Color::white));
00291       lightList.push_back(new Light(Vector3(0, 8, -2), Color::red));
00292       lightList.push_back(new Light(Vector3(-2, 8, 0), Color::lime));
00293       lightList.push_back(new Light(Vector3(0, 8, 2), Color::blue));
00294     }
00295 
00296 
00297 
00298     World::~World()
00299     {
00300       for(std::vector<Light   *>::iterator i =   lightList.begin();
00301           i !=   lightList.end(); ++i) delete *i;
00302       for(std::vector<Object  *>::iterator i =  objectList.begin();
00303           i !=  objectList.end(); ++i) delete *i;
00304       for(std::vector<Vector3 *>::iterator i =  vertexList.begin();
00305           i !=  vertexList.end(); ++i) delete *i;
00306       for(std::vector<Surface *>::iterator i = surfaceList.begin();
00307           i != surfaceList.end(); ++i) delete *i;
00308     }
00309 
00310 
00311     Vector4 World::trace(const Line3 &ray,
00312                        const Object *originObject,
00313                        const Object::Part *originPart,
00314                        int depth, double significance,
00315                        bool transmission)
00316     {
00317       /*
00318        * Determine the object which is hit first by 'ray' taking the
00319        * origin point and direction of 'ray' into account. At the same
00320        * time, determine the "part" of that object which was hit, and
00321        * the distance from the ray origin to the point of intersection.
00322        *
00323        * Note: We pass to the intersection methods a reference to the
00324        * object and object-part wherefrom the ray originates. This
00325        * enables the individual type of object to discriminate reliably
00326        * between the originating intersection point and the intersection
00327        * point of interrest. It also enables some types of objects to
00328        * reduce the cost of the intersection operation. Especially
00329        * convex objects need not check for external intersection against
00330        * themselves, like concave objects do.
00331        */
00332       const Object *hitObject = 0;
00333       const Object::Part *hitPart = 0;
00334       double hitDist = 0;
00335       if(transmission)
00336       {
00337         const Solid *s = dynamic_cast<const Solid *>(originObject);
00338         if(!s) throw InternalErrorException("Transmission initiated "
00339                                             "on non-solid object");
00340         hitObject = originObject;
00341         s->interiorIntersect(ray, originPart, hitDist, hitPart);
00342       }
00343       else
00344       {
00345         // Search for the nearest intersection
00346         const Object::Part *p;
00347         double d;
00348         for(std::vector<Object *>::iterator i=objectList.begin();
00349             i != objectList.end(); ++i)
00350         {
00351           if((*i)->intersect(ray, originObject, originPart, d, &p) &&
00352              (!hitObject || d < hitDist))
00353           {
00354             hitDist = d;
00355             hitPart = p;
00356             hitObject = *i;
00357           }
00358         }
00359       }
00360 
00361       /*
00362        * If the ray hits nothing, we think of the light as coming from
00363        * the "background" and therefore default to a fixed background
00364        * color.
00365        */
00366       if(!hitObject) return backgroundColor;
00367 
00368 
00369       // Determine the intersection point
00370       Vector3 intersection = ray.direction;
00371       intersection *= hitDist;
00372       intersection += ray.point;
00373 
00374       // Fetch surface, normal and possibly texture coordinates from the intersected object-part
00375       const Surface *surface = hitPart->getSurface();
00376       Vector3 normal;
00377       Vector2 texturePoint;
00378       if(dynamic_cast<const Texture *>(surface))
00379         hitPart->map(intersection, normal, texturePoint);
00380       else
00381         hitPart->map(intersection, normal);
00382       Vector4 surfaceColor;
00383       surface->getColor(texturePoint, surfaceColor);
00384 
00385       std::vector<const KDTree::Element *> nearest;
00386       double radius;
00387       causticPhotonMap.findNearest(intersection, photonsInEstimate, 30, radius, nearest);
00388 
00389       radius/=60;
00390 
00391       Vector4 color = Color::black;
00392 
00393       if(nearest.size() == photonsInEstimate)
00394       {
00395         Vector3 caustic(0, 0, 0);
00396         for(unsigned i=0; i<photonsInEstimate; ++i) caustic += ((Photon *)nearest[i])->power;
00397         caustic *= surface->getDiffuseReflection() / (M_PI * M_PI * radius * radius);
00398         color[0] = caustic[0] * surfaceColor[0];
00399         color[1] = caustic[1] * surfaceColor[1];
00400         color[2] = caustic[2] * surfaceColor[2];
00401       }
00402 
00403       if(showOnlyPhotonMap) return nearest.size() < photonsInEstimate ? Color::black : Color::white * (1 - (atan(radius*10) / (M_PI/2)));
00404 
00405       // Add up color contributions from visible light sources.
00406       for(std::vector<Light *>::iterator i=lightList.begin();
00407           i != lightList.end(); ++i)
00408       {
00409         /*
00410          * When testing for eclipsed light sources we actually generate
00411          * a ray from the intersection point towards the light source,
00412          * and test for intersection between that line and all the
00413          * objects in the world. We can terminate the check imediately,
00414          * though, as soon as we encounter an intersection, because this
00415          * guarantees eclipse.
00416          */
00417         Vector3 lightDirection = (*i)->getPosition();
00418         lightDirection -= intersection;
00419         const double lightDist = lightDirection.length();
00420         lightDirection.normalize();
00421         const Line3 rayToLight(intersection, lightDirection);
00422 
00423         /*
00424          * Since in practice it always is so, that the intersected object
00425          * shadows at least half of the world space from the point of
00426          * view of the intersection point, it generally pays to check
00427          * for eclipse by this object before checking other objects.
00428          *
00429          * Note that this check will be particularly simple for convex
00430          * objects since in this case, if the angle between the surface
00431          * normal and the light direction is greater than 90 degrees,
00432          * then the light source is eclipsed.
00433          */
00434         double d;
00435         if(dot(normal, lightDirection) < 0) continue;
00436 
00437         // Check for eclipse by other objects.
00438         bool eclipsed = false;
00439         for(std::vector<Object *>::iterator j=objectList.begin();
00440             j != objectList.end(); ++j)
00441         {
00442           if((*j)->intersect(rayToLight, hitObject, hitPart, d) &&
00443              d < lightDist)
00444           {
00445             eclipsed = true;
00446             break;
00447           }
00448         }
00449         if(eclipsed) continue;
00450 
00451         // Add color contribution to pixel
00452         Vector4 c = surface->shade(**i, normal,
00453                                  transmission ? ray.direction : -ray.direction,
00454                                  lightDirection, surfaceColor);
00455         color[0] += c[0];
00456         color[1] += c[1];
00457         color[2] += c[2];
00458       }
00459 
00460       // Add diffuse reflection of ambient light
00461       const double ambientReflection =
00462         surface->getAmbientReflection() * globalAmbientIntencity;
00463       color[0] += surfaceColor[0] * ambientReflection;
00464       color[1] += surfaceColor[1] * ambientReflection;
00465       color[2] += surfaceColor[2] * ambientReflection;
00466 
00467       /*
00468        * Follow specular reflection
00469        */
00470       const double specularReflection =
00471         surface->getSpecularReflection();
00472       const double reflectionSignificance =
00473         significance * specularReflection;
00474       if(depth < maxDepth && reflectionSignificance > significanceThreshold)
00475       {
00476         Vector3 reflectedDirection = normal;
00477         reflectedDirection *= -2 * dot(ray.direction, normal);
00478         reflectedDirection += ray.direction;
00479         reflectedDirection.normalize(); // In theory not needed, but for the sake of stability
00480 
00481         const Vector4 c =
00482           trace(Line3(intersection, reflectedDirection), hitObject, hitPart,
00483                 depth + 1, reflectionSignificance, transmission);
00484 
00485         color[0] += c[0] * surfaceColor[0] * specularReflection;
00486         color[1] += c[1] * surfaceColor[1] * specularReflection;
00487         color[2] += c[2] * surfaceColor[2] * specularReflection;
00488       }
00489 
00490       /*
00491        * Note: We currently cannot allow thin objects to be transparent
00492        * due to lack of a consistent way to deal with such.
00493        */
00494       if(enableTransmission && dynamic_cast<const Solid *>(hitObject))
00495       {
00496         /*
00497          * Follow specular refraction into the surface
00498          * The determination of the direction vector of the refraction
00499          * is based on: http://www.acm.org/crossroads/xrds3-4/raytracing.html
00500          */
00501         const double specularRefraction =
00502           surface->getSpecularRefraction();
00503         const double refractionSignificance =
00504           significance * specularRefraction;
00505         if(depth < maxDepth && refractionSignificance > significanceThreshold)
00506         {
00507           const double cosine = dot(ray.direction, transmission ? -normal : normal);
00508           const double n = transmission ? 1 / surface->getRefractiveIndex() : surface->getRefractiveIndex();
00509           const double a = 1 - (1 - cosine*cosine) / (n*n);
00510 
00511           if(a > 0)
00512           {
00513             Vector3 v = transmission ? -normal : normal;
00514             v *= (cosine/n + sqrt(a));
00515             Vector3 refractedDirection = ray.direction;
00516             refractedDirection /= n;
00517             refractedDirection -= v;
00518             refractedDirection.normalize();
00519 
00520             const Vector4 c =
00521               trace(Line3(intersection, refractedDirection),
00522                     hitObject, hitPart,
00523                     depth + 1, refractionSignificance, !transmission);
00524 
00525             color[0] += c[0] * surfaceColor[0] * specularRefraction;
00526             color[1] += c[1] * surfaceColor[1] * specularRefraction;
00527             color[2] += c[2] * surfaceColor[2] * specularRefraction;
00528           }
00529         }
00530       }
00531 
00532       return color;
00533     }
00534 
00535     void World::photonTrace(unsigned totalPhotons)
00536     {
00537       double totalEmission = 0;
00538       for(std::vector<Light *>::iterator i=lightList.begin();
00539           i != lightList.end(); ++i)
00540       {
00541         const Vector4 &c = (*i)->getColor();
00542         totalEmission+=sqrt(c[0]*c[0] + c[1]*c[1] + c[1]*c[1]);
00543       }
00544     
00545       for(std::vector<Light *>::iterator i=lightList.begin();
00546           i != lightList.end(); ++i)
00547       {
00548         const Vector4 &c = (*i)->getColor();
00549         const double emission = sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]);
00550         const unsigned numberPhotons = unsigned(emission/totalEmission*totalPhotons);
00551 
00552         Vector3 power;
00553         power[0] = c[0];
00554         power[1] = c[1];
00555         power[2] = c[2];
00556         power *= 240.0 / numberPhotons;
00557 
00558         for(unsigned j=0; j<numberPhotons; j++)
00559         {
00560           Vector3 v;
00561           drawUnitVector3(v[0], v[1], v[2]);
00562           Line3 ray((*i)->getPosition(), v);
00563           photonTrace(ray, photons, 0, 0, 0, false, true, power);
00564         }  
00565       }
00566 
00567       /*
00568         photons.push_back(Photon(Vector3(0, 0, 0), Vector3(1, 1, 1)));
00569         photons.push_back(Photon(Vector3(1, 0, 0), Vector3(1, 1, 1)));
00570         photons.push_back(Photon(Vector3(2, 0, 0), Vector3(1, 1, 1)));
00571         photons.push_back(Photon(Vector3(3, 0, 0), Vector3(1, 1, 1)));
00572         photons.push_back(Photon(Vector3(4, 0, 0), Vector3(1, 1, 1)));
00573       */
00574 
00575       std::cout << "Number of photons in map: " << photons.size() << "\n";
00576 
00577       for(std::vector<Photon>::iterator i=photons.begin();
00578           i != photons.end(); ++i) causticPhotonMap.insert(&*i);
00579 
00580       causticPhotonMap.balanceTree();
00581     }
00582 
00583     void World::photonTrace(const Line3 &ray, std::vector<Photon> &photons,
00584                             const Object *originObject,
00585                             const Object::Part *originPart,
00586                             int depth, bool transmission, 
00587                             bool caustic, const Vector3 &power)
00588     {
00589       const Object *hitObject = 0;
00590       const Object::Part *hitPart = 0;
00591       double hitDist = 0;
00592 
00593       if(transmission)
00594       {
00595         const Solid *s = dynamic_cast<const Solid *>(originObject);
00596         if(!s) throw InternalErrorException("Transmission initiated "
00597                                             "on non-solid object");
00598         hitObject = originObject;
00599         s->interiorIntersect(ray, originPart, hitDist, hitPart);
00600       }
00601       else
00602       {
00603         const Object::Part *p;
00604         double d;
00605         for(std::vector<Object *>::iterator i=objectList.begin();
00606             i != objectList.end(); ++i)
00607         {
00608           if((*i)->intersect(ray, originObject, originPart, d, &p) &&
00609              (!hitObject || d < hitDist))
00610           {
00611             hitDist = d;
00612             hitPart = p;
00613             hitObject = *i;
00614           }
00615         }
00616       }
00617 
00618       if(!hitObject) return;
00619 
00620       // Determine the intersection point
00621       Vector3 intersection = ray.direction;
00622       intersection *= hitDist;
00623       intersection += ray.point;
00624 
00625 
00626       // Fetch surface normal from the intersected object-part
00627       const Surface *surface = hitPart->getSurface();
00628       Vector3 normal;
00629       hitPart->map(intersection, normal);
00630 
00631 
00632       double r = Utilities::drawFloat();
00633       if((r-=surface->getDiffuseReflection())<0)
00634       {
00635         if(caustic && depth>=1)
00636           photons.push_back(Photon(intersection, power));
00637 
00638         if(caustic) return;
00639         // else random direction
00640       }
00641       else if((r-=surface->getSpecularReflection())<0)
00642       {
00643         Vector3 reflectedDirection = normal;
00644         reflectedDirection *= -2 * dot(ray.direction, normal);
00645         reflectedDirection += ray.direction;
00646 
00647         photonTrace(Line3(intersection, reflectedDirection), photons, hitObject, hitPart,
00648                     depth + 1, transmission, caustic, power);
00649       }
00650       else if((r-=surface->getSpecularRefraction())<0)
00651       {
00652         const double cosine = dot(ray.direction, transmission ? -normal : normal);
00653         const double n = transmission ? 1 / surface->getRefractiveIndex() : surface->getRefractiveIndex();
00654         const double a = 1 - (1 - cosine*cosine) / (n*n);
00655 
00656         if(a > 0)
00657         {
00658           Vector3 v = transmission ? -normal : normal;
00659           v *= (cosine/n + sqrt(a));
00660           Vector3 refractedDirection = ray.direction;
00661           refractedDirection /= n;
00662           refractedDirection -= v;
00663 
00664           photonTrace(Line3(intersection, refractedDirection), photons,
00665                       hitObject, hitPart, depth + 1, !transmission, 
00666                       caustic, power);
00667         }
00668         else
00669         {
00670           Vector3 reflectedDirection = normal;
00671           reflectedDirection *= -2 * dot(ray.direction, normal);
00672           reflectedDirection += ray.direction;
00673 
00674           photonTrace(Line3(intersection, reflectedDirection), photons, hitObject, hitPart,
00675                       depth + 1, transmission, caustic, power);
00676         }
00677       }
00678       else
00679       {
00680         // Absorbed.
00681         return;
00682       }
00683     }
00684   }
00685 }
00686 
00687 
00688 
00689 
00690 
00691 
00692 

Generated on Sun Jul 30 22:55:51 2006 for Archon by  doxygen 1.4.4