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 <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
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 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"));
00084 textureList.push_back(Image("texture/moon1polar.ppm"));
00085 textureList.push_back(Image("texture/kristian.ppm"));
00086 textureList.push_back(Image("texture/granite.ppm"));
00087 textureList.push_back(Image("texture/skin.ppm"));
00088 textureList.push_back(Image("texture/spotty.ppm"));
00089 textureList.push_back(Image("texture/bkristia.ppm"));
00090 textureList.push_back(Image("texture/chess-marble.ppm"));
00091 textureList.push_back(Image("texture/glass.ppm"));
00092
00093 surfaceList.push_back(new StandardSurface(Color::seagreen, 0.05, 0.1, 0.05, 0.9, 20, 20, 1.15));
00094 surfaceList.push_back(new StandardSurface(Color::crimson, 0.1, 0.2, 0.9, 0.1, 60, 20, 1.2));
00095 surfaceList.push_back(new StandardSurface(Color::steelblue, 0.1, 0.2, 0.9, 0.1, 60, 20, 1.2));
00096 surfaceList.push_back(new StandardSurface(Color::darkolivegreen));
00097 surfaceList.push_back(new StandardSurface(Color::gold));
00098 surfaceList.push_back(new Texture(textureList[3], 0.1, 0.8, 0.0, 0.0, 20, 20));
00099 surfaceList.push_back(new Texture(textureList[4], 0.9, 0.9, 0.1, 0.1, 20, 20, 1, 3, 3));
00100 surfaceList.push_back(new Texture(textureList[5], 0.1, 0.5, 0.5, 0.1, 20, 20, 1, 2, 2));
00101 surfaceList.push_back(new Texture(textureList[2], 0.1, 0.9, 0.1, 0.1, 20, 20));
00102 surfaceList.push_back(new Texture(textureList[6], 0.1, 0.2, 0.8, 0.8, 20, 20));
00103 surfaceList.push_back(new Texture(textureList[6], 0.1, 0.9, 0.1, 0.1, 20, 20));
00104 surfaceList.push_back(new StandardSurface(Vector4(1, 1, 1), 0.0, 0.1, 0.2, 0.6, 20, 20, 1.33));
00105 surfaceList.push_back(new Texture(textureList[8], 0.9, 0, 0, 0, 20, 20));
00106 surfaceList.push_back(new Texture(textureList[7], 0.1, 0.0, 0.5, 0.5, 20, 20, 1, 3, 3));
00107 surfaceList.push_back(new Texture(textureList[8], 0.1, 0.18, 0.05, 0.9, 60, 20, 1.2));
00108 surfaceList.push_back(new StandardSurface(Vector4(1, 1, 1), 0, 0.8, 0.1, 0, 20, 20, 1.33));
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 objectList.push_back(new Torus(surfaceList[11], CoordSystem3(Vector3(0, 4, 0), Matrix3x3::identity), 2, 1));
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
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
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
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
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
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
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
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
00363
00364
00365
00366 if(!hitObject) return backgroundColor;
00367
00368
00369
00370 Vector3 intersection = ray.direction;
00371 intersection *= hitDist;
00372 intersection += ray.point;
00373
00374
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
00406 for(std::vector<Light *>::iterator i=lightList.begin();
00407 i != lightList.end(); ++i)
00408 {
00409
00410
00411
00412
00413
00414
00415
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
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 double d;
00435 if(dot(normal, lightDirection) < 0) continue;
00436
00437
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
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
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
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();
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
00492
00493
00494 if(enableTransmission && dynamic_cast<const Solid *>(hitObject))
00495 {
00496
00497
00498
00499
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
00569
00570
00571
00572
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
00621 Vector3 intersection = ray.direction;
00622 intersection *= hitDist;
00623 intersection += ray.point;
00624
00625
00626
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
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
00681 return;
00682 }
00683 }
00684 }
00685 }
00686
00687
00688
00689
00690
00691
00692