00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "renderer.h"
00024 #include "common/math/customdistribution.h"
00025 #include "common/misc/minmax.h"
00026 #include "context.h"
00027 #include "hit.h"
00028 #include "ibdf.h"
00029 #include "icamera.h"
00030 #include "iedf.h"
00031 #include "iobject.h"
00032 #include "isurfaceshader.h"
00033 #include "photonmap.h"
00034 #include "scene.h"
00035 #include "settings.h"
00036 #include "statistics.h"
00037 #include "surfacebasis.h"
00038 #include "surfacesamplerfactory.h"
00039 #include "utilities.h"
00040
00041 #include "common/misc/pentiumrtsc.h"
00042
00043 #include <cmath>
00044 #include <iostream>
00045
00046 using namespace sheep;
00047 using namespace toxic;
00048
00049 Renderer::Renderer() :
00050 m_scene(0),
00051 m_camera(0),
00052 m_global_pm(0),
00053 m_caustics_pm(0),
00054 m_framebuffer(0),
00055 m_pixel_ss(0),
00056 m_arealight_ss(0),
00057 m_primary_fg_hss(0),
00058 m_secondary_fg_hss(0)
00059 #ifdef ENABLE_WHITTED_SAMPLING_CACHE
00060 , m_prev_pixels(0)
00061 #endif
00062 {
00063 }
00064
00065 Renderer::~Renderer() {
00066 cleanup();
00067 }
00068
00069 void Renderer::SetScene(const Scene *scene) {
00070 assert(scene);
00071 m_scene = scene;
00072 }
00073
00074 void Renderer::SetCamera(const ICamera *camera) {
00075 assert(camera);
00076 m_camera = camera;
00077 }
00078
00079 void Renderer::SetGlobalPhotonMap(const PhotonMap *global_pm) {
00080 assert(global_pm);
00081 m_global_pm = global_pm;
00082 }
00083
00084 void Renderer::SetCausticsPhotonMap(const PhotonMap *caustics_pm) {
00085 assert(caustics_pm);
00086 m_caustics_pm = caustics_pm;
00087 }
00088
00089 void Renderer::SetFramebuffer(Framebuffer *framebuffer) {
00090 assert(framebuffer);
00091 m_framebuffer = framebuffer;
00092
00093 ResetRenderArea();
00094 }
00095
00096 void Renderer::SetRenderArea(int x0, int y0, int x1, int y1) {
00097 assert(m_framebuffer);
00098
00099 const int xmax = m_framebuffer->GetWidth() - 1;
00100 const int ymax = m_framebuffer->GetHeight() - 1;
00101
00102 if(x0 < 0) x0 = 0;
00103 if(x0 > xmax) x0 = xmax;
00104 if(y0 < 0) y0 = 0;
00105 if(y0 > ymax) y0 = ymax;
00106
00107 if(x1 < 0) x1 = 0;
00108 if(x1 > xmax) x1 = xmax;
00109 if(y1 < 0) y1 = 0;
00110 if(y1 > ymax) y1 = ymax;
00111
00112 assert(x1 >= x0);
00113 assert(y1 >= y0);
00114
00115 m_area_x0 = x0;
00116 m_area_y0 = y0;
00117 m_area_x1 = x1;
00118 m_area_y1 = y1;
00119 }
00120
00121 void Renderer::ResetRenderArea() {
00122 assert(m_framebuffer);
00123
00124 m_area_x0 = 0;
00125 m_area_y0 = 0;
00126 m_area_x1 = m_framebuffer->GetWidth() - 1;
00127 m_area_y1 = m_framebuffer->GetHeight() - 1;
00128 }
00129
00130 void Renderer::Restart(const Context &context) {
00131 cleanup();
00132
00133 m_x = m_area_x0;
00134 m_y = m_area_y0;
00135 m_completed_pixels = 0;
00136
00137
00138
00139 m_area_pixels =
00140 (m_area_x1 - m_area_x0 + 1) *
00141 (m_area_y1 - m_area_y0 + 1);
00142
00143 assert(m_area_pixels > 0);
00144 m_inv_area_pixels = 1.0 / m_area_pixels;
00145
00146
00147 m_pixel_ss = 0;
00148 #ifdef ENABLE_WHITTED_SAMPLING_CACHE
00149 m_prev_pixels = 0;
00150 #endif // ENABLE_WHITTED_SAMPLING_CACHE
00151 switch(context.m_settings->m_rendering.m_pixel_sampling.m_algorithm) {
00152
00153 case Settings::Rendering::PixelSampling::SUPERSAMPLING:
00154 m_pixel_ss = SurfaceSamplerFactory::Create(
00155 context.m_settings->m_rendering.m_pixel_sampling.m_supersampling
00156 );
00157 break;
00158
00159 case Settings::Rendering::PixelSampling::WHITTED_ADAPTIVE_SAMPLING:
00160 #ifdef ENABLE_WHITTED_SAMPLING_CACHE
00161 m_prev_pixels = new Color3[m_framebuffer->GetWidth() + 2];
00162 #endif // ENABLE_WHITTED_SAMPLING_CACHE
00163 break;
00164 default:
00165 assert(!"Internal failure.");
00166 }
00167
00168 if(context.m_settings->m_rendering.m_components.m_direct_lighting.m_enabled) {
00169
00170 m_arealight_ss = SurfaceSamplerFactory::Create(
00171 context.m_settings->m_rendering.m_components.m_direct_lighting.m_arealight_sampling
00172 );
00173
00174 m_irradiance_samples.reserve(m_arealight_ss->GetSampleCount());
00175 } else {
00176 m_arealight_ss = 0;
00177 }
00178
00179 if(context.m_settings->m_rendering.m_components.m_indirect_lighting.m_enabled) {
00180
00181 m_primary_fg_hss = SurfaceSamplerFactory::Create(
00182 context.m_settings->m_rendering.m_components.m_indirect_lighting.m_primary_fg
00183 );
00184
00185
00186 if(context.m_settings->m_rendering.m_components.m_indirect_lighting.m_secondary_fg.m_enabled) {
00187 m_secondary_fg_hss = SurfaceSamplerFactory::Create(
00188 context.m_settings->m_rendering.m_components.m_indirect_lighting.m_secondary_fg
00189 );
00190 } else {
00191 m_secondary_fg_hss = 0;
00192 }
00193 } else {
00194 m_primary_fg_hss = 0;
00195 m_secondary_fg_hss = 0;
00196 }
00197 }
00198
00199 void Renderer::RenderNextPixel(const Context &context) {
00200 assert(m_scene);
00201 assert(m_camera);
00202 assert(m_framebuffer);
00203
00204 if(!IsRenderComplete()) {
00205 render_pixel(context);
00206
00207 ++context.m_statistics->m_total_pixels;
00208
00209 ++m_completed_pixels;
00210
00211 if(m_x < m_area_x1)
00212 ++m_x;
00213 else {
00214 m_x = m_area_x0;
00215 ++m_y;
00216 }
00217 }
00218 }
00219
00220 void Renderer::Annotate(const Context &context) {
00221 m_scene->GetRootObject()->Annotate(context, m_camera, m_framebuffer);
00222 }
00223
00224 void Renderer::cleanup() {
00225 delete m_pixel_ss;
00226 delete m_arealight_ss;
00227 delete m_primary_fg_hss;
00228 delete m_secondary_fg_hss;
00229
00230 #ifdef ENABLE_WHITTED_SAMPLING_CACHE
00231 delete [] m_prev_pixels;
00232 #endif // ENABLE_WHITTED_SAMPLING_CACHE
00233 }
00234
00235 void Renderer::render_pixel(const Context &context) {
00236
00237
00238
00239
00240 switch(context.m_settings->m_rendering.m_pixel_sampling.m_algorithm) {
00241
00242 case Settings::Rendering::PixelSampling::SUPERSAMPLING:
00243 render_pixel_supersampling(context);
00244 break;
00245
00246 case Settings::Rendering::PixelSampling::WHITTED_ADAPTIVE_SAMPLING:
00247 render_pixel_whitted(context);
00248 break;
00249 default:
00250 assert(!"Internal failure.");
00251 }
00252
00253
00254
00255
00256
00257
00258
00259 }
00260
00261 void Renderer::render_pixel_supersampling(const Context &context) {
00262 const Point2 pixel_center = m_framebuffer->ConvertToNDC(m_x, m_y);
00263 const Real pixel_width = m_framebuffer->GetPixelWidth();
00264 const Real pixel_height = m_framebuffer->GetPixelHeight();
00265
00266 m_pixel_ss->GenerateNewSamples(context);
00267
00268 for(ISurfaceSampler::SampleVector::iterator i = m_pixel_ss->m_samples.begin(),
00269 e = m_pixel_ss->m_samples.end(); i != e; ++i)
00270 {
00271 i->m_x = pixel_center.m_x + (i->m_x - 0.5) * pixel_width;
00272 i->m_y = pixel_center.m_y + (i->m_y - 0.5) * pixel_height;
00273 }
00274
00275 Color3 radiance(0.0);
00276
00277 for(ISurfaceSampler::SampleVector::const_iterator i = m_pixel_ss->m_samples.begin(),
00278 e = m_pixel_ss->m_samples.end(); i != e; ++i)
00279 {
00280
00281 const Ray ray = m_camera->ComputeRay(context, *i);
00282 radiance += trace(context, ray, 0);
00283 }
00284
00285 radiance *= m_pixel_ss->GetInvSampleCount();
00286
00287
00288 m_framebuffer->SetPixel(m_x, m_y, radiance);
00289 }
00290
00291 void Renderer::render_pixel_whitted(const Context &context) {
00292 const Point2 pixel_center = m_framebuffer->ConvertToNDC(m_x, m_y);
00293
00294 const Real half_pix_w = 0.5 * m_framebuffer->GetPixelWidth();
00295 const Real half_pix_h = 0.5 * m_framebuffer->GetPixelHeight();
00296
00297 const Point2 v0(pixel_center.m_x - half_pix_w, pixel_center.m_y + half_pix_h);
00298 const Point2 v1(pixel_center.m_x + half_pix_w, pixel_center.m_y + half_pix_h);
00299 const Point2 v2(pixel_center.m_x + half_pix_w, pixel_center.m_y - half_pix_h);
00300 const Point2 v3(pixel_center.m_x - half_pix_w, pixel_center.m_y - half_pix_h);
00301
00302 #ifdef ENABLE_WHITTED_SAMPLING_CACHE
00303 Color3 r0, r1, r2, r3;
00304
00305 if(m_y == m_area_y0) {
00306 if(m_x == m_area_x0) {
00307
00308
00309 r0 = trace(context, m_camera->ComputeRay(context, v0), 0);
00310 r1 = trace(context, m_camera->ComputeRay(context, v1), 0);
00311 r2 = trace(context, m_camera->ComputeRay(context, v2), 0);
00312 r3 = trace(context, m_camera->ComputeRay(context, v3), 0);
00313
00314 m_prev_pixels[0] = r1;
00315 m_prev_pixels[m_x + 1] = r3;
00316 m_prev_pixels[m_x + 2] = r2;
00317 } else {
00318
00319
00320 r0 = m_prev_pixels[0];
00321 r1 = trace(context, m_camera->ComputeRay(context, v1), 0);
00322 r2 = trace(context, m_camera->ComputeRay(context, v2), 0);
00323 r3 = m_prev_pixels[m_x + 1];
00324
00325 m_prev_pixels[0] = r1;
00326 m_prev_pixels[m_x + 2] = r2;
00327 }
00328 } else {
00329 if(m_x == m_area_x0) {
00330
00331
00332 r0 = m_prev_pixels[m_x + 1];
00333 r1 = m_prev_pixels[m_x + 2];
00334 r2 = trace(context, m_camera->ComputeRay(context, v2), 0);
00335 r3 = trace(context, m_camera->ComputeRay(context, v3), 0);
00336
00337 m_prev_pixels[0] = r1;
00338 m_prev_pixels[m_x + 1] = r3;
00339 m_prev_pixels[m_x + 2] = r2;
00340 } else {
00341
00342
00343 r0 = m_prev_pixels[0];
00344 r1 = m_prev_pixels[m_x + 2];
00345 r2 = trace(context, m_camera->ComputeRay(context, v2), 0);
00346 r3 = m_prev_pixels[m_x + 1];
00347
00348 m_prev_pixels[0] = r1;
00349 m_prev_pixels[m_x + 2] = r2;
00350 }
00351 }
00352 #else
00353 const Color3 r0 = trace(context, m_camera->ComputeRay(context, v0), 0);
00354 const Color3 r1 = trace(context, m_camera->ComputeRay(context, v1), 0);
00355 const Color3 r2 = trace(context, m_camera->ComputeRay(context, v2), 0);
00356 const Color3 r3 = trace(context, m_camera->ComputeRay(context, v3), 0);
00357 #endif // ENABLE_WHITTED_SAMPLING_CACHE
00358
00359 const Color3 radiance = whitted_recursive_sampling(
00360 context,
00361 pixel_center,
00362 v0, v1, v2, v3,
00363 r0, r1, r2, r3,
00364 0
00365 );
00366
00367
00368 m_framebuffer->SetPixel(m_x, m_y, radiance);
00369 }
00370
00371 namespace {
00372 inline
00373 Real contrast(const Color3 &c0, const Color3 &c1) {
00374 return fabs(c0.Luminance() - c1.Luminance());
00375 }
00376 }
00377
00378 Color3 Renderer::whitted_recursive_sampling(const Context &context,
00379 const Point2 ¢er,
00380 const Point2 &v0,
00381 const Point2 &v1,
00382 const Point2 &v2,
00383 const Point2 &v3,
00384 const Color3 &r0,
00385 const Color3 &r1,
00386 const Color3 &r2,
00387 const Color3 &r3,
00388 int recursion_level)
00389 {
00390 assert(recursion_level >= 0);
00391 assert(recursion_level <=
00392 context.m_settings->m_rendering.m_pixel_sampling.m_whitted_adaptive_sampling.m_max_depth);
00393
00394 const Real contrast_threshold =
00395 context.m_settings->m_rendering.m_pixel_sampling.m_whitted_adaptive_sampling.m_contrast_threshold;
00396 const int max_depth =
00397 context.m_settings->m_rendering.m_pixel_sampling.m_whitted_adaptive_sampling.m_max_depth;
00398
00399 if(recursion_level < max_depth &&
00400 (contrast(r0, r1) > contrast_threshold ||
00401 contrast(r1, r2) > contrast_threshold ||
00402 contrast(r2, r3) > contrast_threshold ||
00403 contrast(r3, r0) > contrast_threshold ||
00404 contrast(r0, r2) > contrast_threshold ||
00405 contrast(r1, r3) > contrast_threshold))
00406 {
00407 const Point2 v4(center.m_x, v0.m_y);
00408 const Point2 v5(v1.m_x, center.m_y);
00409 const Point2 v6(center.m_x, v2.m_y);
00410 const Point2 v7(v3.m_x, center.m_y);
00411
00412 const Color3 rc = trace(context, m_camera->ComputeRay(context, center), 0);
00413 const Color3 r4 = trace(context, m_camera->ComputeRay(context, v4), 0);
00414 const Color3 r5 = trace(context, m_camera->ComputeRay(context, v5), 0);
00415 const Color3 r6 = trace(context, m_camera->ComputeRay(context, v6), 0);
00416 const Color3 r7 = trace(context, m_camera->ComputeRay(context, v7), 0);
00417
00418 const Real half_subpix_w = 0.5 * (center.m_x - v0.m_x);
00419 const Real half_subpix_h = 0.5 * (v0.m_y - center.m_y);
00420
00421 assert(half_subpix_w > 0.0);
00422 assert(half_subpix_h > 0.0);
00423
00424 const int new_recursion_level = recursion_level + 1;
00425
00426 const Color3 spr0 = whitted_recursive_sampling(
00427 context,
00428 Point2(v0.m_x + half_subpix_w, v0.m_y - half_subpix_h),
00429 v0, v4, center, v7,
00430 r0, r4, rc, r7,
00431 new_recursion_level
00432 );
00433
00434 const Color3 spr1 = whitted_recursive_sampling(
00435 context,
00436 Point2(v1.m_x - half_subpix_w, v1.m_y - half_subpix_h),
00437 v4, v1, v5, center,
00438 r4, r1, r5, rc,
00439 new_recursion_level
00440 );
00441
00442 const Color3 spr2 = whitted_recursive_sampling(
00443 context,
00444 Point2(v2.m_x - half_subpix_w, v2.m_y + half_subpix_h),
00445 center, v5, v2, v6,
00446 rc, r5, r2, r6,
00447 new_recursion_level
00448 );
00449
00450 const Color3 spr3 = whitted_recursive_sampling(
00451 context,
00452 Point2(v3.m_x + half_subpix_w, v3.m_y + half_subpix_h),
00453 v7, center, v6, v3,
00454 r7, rc, r6, r3,
00455 new_recursion_level
00456 );
00457
00458 return (1.0 / 4.0) * (spr0 + spr1 + spr2 + spr3);
00459 } else return (1.0 / 4.0) * (r0 + r1 + r2 + r3);
00460 }
00461
00462 Color3 Renderer::trace(const Context &context, const Ray &ray, int recursion_level) {
00463 assert(ray.m_direction.IsUnitLength());
00464
00465 #ifdef _DEBUG
00466 if(context.m_settings->m_rendering.m_components.m_specular_reflections.m_enabled) {
00467 assert(recursion_level >= 0);
00468 assert(recursion_level <=
00469 context.m_settings->m_rendering.m_components.m_specular_reflections.m_max_depth);
00470 } else assert(recursion_level == 0);
00471 #endif // _DEBUG
00472
00473 switch(recursion_level) {
00474 case 0:
00475 ++context.m_statistics->m_primary_rays;
00476 break;
00477 default:
00478 ++context.m_statistics->m_secondary_rays;
00479 }
00480
00481 Hit hit;
00482
00483 if(!m_scene->Trace(context, ray, &hit)) {
00484
00485 return m_scene->GetBackgroundColor();
00486 }
00487
00488 const Vector3 outgoing = -ray.m_direction;
00489
00490
00491 Point3 point;
00492 Vector3 geometric_normal, shading_normal;
00493 hit.ExtractIntersection(ray, &point, &geometric_normal, &shading_normal);
00494 const ISurfaceShader *surface_shader = hit.m_object->GetSurfaceShader();
00495
00496 ShadingData shadingdata;
00497 surface_shader->Shade(hit, &shadingdata);
00498
00499
00500
00501
00502
00503 Color3 radiance(0.0);
00504
00505
00506 if(context.m_settings->m_rendering.m_components.m_direct_lighting.m_enabled) {
00507
00508 if(surface_shader->GetEDF()) {
00509
00510 radiance +=
00511 surface_shader->GetRadiantExitance() / surface_shader->GetRadiantExitance().Average();
00512
00513
00514
00515 }
00516
00517 radiance +=
00518 compute_direct_illumination(
00519 context,
00520 point,
00521 geometric_normal,
00522 shading_normal,
00523 outgoing,
00524 surface_shader,
00525 shadingdata
00526 );
00527 }
00528
00529
00530 if(context.m_settings->m_rendering.m_components.m_indirect_lighting.m_enabled) {
00531 if(context.m_settings->m_rendering.m_components.m_indirect_lighting.m_primary_fg.m_enabled) {
00532 radiance +=
00533 final_gathering(
00534 context,
00535 point,
00536 geometric_normal,
00537 shading_normal,
00538 outgoing,
00539 shadingdata
00540 );
00541 } else {
00542 radiance +=
00543 compute_indirect_illumination(
00544 context,
00545 point,
00546 geometric_normal,
00547 shading_normal,
00548 outgoing,
00549 shadingdata
00550 );
00551 }
00552 }
00553
00554
00555 if(context.m_settings->m_rendering.m_components.m_specular_reflections.m_enabled) {
00556 if(recursion_level < context.m_settings->m_rendering.m_components.m_specular_reflections.m_max_depth) {
00557 radiance +=
00558 compute_specular_reflections(
00559 context,
00560 point,
00561 geometric_normal,
00562 shading_normal,
00563 outgoing,
00564 shadingdata,
00565 recursion_level
00566 );
00567 }
00568 }
00569
00570
00571 if(context.m_settings->m_rendering.m_components.m_caustics.m_enabled) {
00572 radiance +=
00573 compute_caustics(
00574 context,
00575 point,
00576 geometric_normal,
00577 shading_normal,
00578 outgoing,
00579 shadingdata
00580 );
00581 }
00582
00583 return radiance;
00584 }
00585
00586 Color3 Renderer::compute_direct_illumination(const Context &context,
00587 const Point3 &point,
00588 const Vector3 &geometric_normal,
00589 const Vector3 &shading_normal,
00590 const Vector3 &outgoing,
00591 const ISurfaceShader *surface_shader,
00592 const ShadingData &shadingdata)
00593 {
00594 assert(geometric_normal.IsUnitLength());
00595 assert(shading_normal.IsUnitLength());
00596 assert(outgoing.IsUnitLength());
00597 assert(surface_shader);
00598
00599 if(!shadingdata.m_bdf->IsDiffuse() || shadingdata.m_reflectance.IsBlack())
00600 return Color3(0.0);
00601
00602
00603
00604 const SurfaceBasis surfacebasis(shading_normal);
00605 const Vector3 local_outgoing = surfacebasis.TransformToLocal(outgoing);
00606
00607
00608 Color3 total_radiance = m_scene->GetAmbientIllumination();
00609
00610
00611
00612 for(int i = 0; i < m_scene->GetLightCount(); ++i) {
00613 const ILight *light = m_scene->GetLight(i);
00614
00615
00616 m_irradiance_samples.clear();
00617 m_arealight_ss->GenerateNewSamples(context);
00618
00619
00620 light->ComputeIrradiance(
00621 context,
00622 m_scene,
00623 point,
00624 geometric_normal,
00625 shading_normal,
00626 m_arealight_ss->m_samples,
00627 &m_irradiance_samples
00628 );
00629
00630 assert(m_irradiance_samples.size() <= m_arealight_ss->m_samples.size());
00631
00632 Color3 radiance(0.0);
00633
00634 for(ILight::IrradianceSampleVector::const_iterator i = m_irradiance_samples.begin(),
00635 e = m_irradiance_samples.end(); i != e; ++i)
00636 {
00637 const ILight::IrradianceSample &sample = *i;
00638
00639 if(sample.m_irradiance.IsBlack())
00640 continue;
00641
00642
00643 const Real bsdf_value =
00644 shadingdata.m_bdf->Evaluate(
00645 context,
00646 surfacebasis.TransformToLocal(sample.m_direction),
00647 local_outgoing
00648 );
00649
00650
00651 radiance += bsdf_value * sample.m_irradiance;
00652 }
00653
00654 if(m_irradiance_samples.size() > 1)
00655 radiance /= m_irradiance_samples.size();
00656
00657 total_radiance += radiance;
00658 }
00659
00660 return shadingdata.m_reflectance * total_radiance;
00661 }
00662
00663 Color3 Renderer::compute_specular_reflections(const Context &context,
00664 const Point3 &point,
00665 const Vector3 &geometric_normal,
00666 const Vector3 &shading_normal,
00667 const Vector3 &outgoing,
00668 const ShadingData &shadingdata,
00669 int recursion_level)
00670 {
00671 assert(geometric_normal.IsUnitLength());
00672 assert(shading_normal.IsUnitLength());
00673 assert(outgoing.IsUnitLength());
00674 assert(recursion_level >= 0);
00675 assert(recursion_level <
00676 context.m_settings->m_rendering.m_components.m_specular_reflections.m_max_depth);
00677
00678 if(!shadingdata.m_bdf->IsSpecular() || shadingdata.m_reflectance.IsBlack())
00679 return Color3(0.0);
00680
00681
00682
00683 const SurfaceBasis surfacebasis(shading_normal);
00684 const Vector3 local_outgoing = surfacebasis.TransformToLocal(outgoing);
00685
00686 Vector3 scattereddir;
00687
00688 const Real bsdf_value =
00689 shadingdata.m_bdf->EvaluateSpecular(
00690 context,
00691 local_outgoing,
00692 &scattereddir
00693 );
00694
00695 if(bsdf_value == 0.0)
00696 return Color3(0.0);
00697
00698
00699
00700
00701 const Point3 shifted_point = point + 1.0e-8 * geometric_normal;
00702
00703 const Color3 radiance =
00704 trace(
00705 context,
00706 Ray(Ray::REFLECTED_RAY, shifted_point, surfacebasis.TransformToWorld(scattereddir)),
00707 recursion_level + 1
00708 );
00709
00710
00711 return bsdf_value * shadingdata.m_reflectance * radiance;
00712 }
00713
00714 Color3 Renderer::final_gathering(const Context &context,
00715 const Point3 &point,
00716 const Vector3 &geometric_normal,
00717 const Vector3 &shading_normal,
00718 const Vector3 &outgoing,
00719 const ShadingData &shadingdata,
00720 bool is_secondary ) const
00721 {
00722 assert(geometric_normal.IsUnitLength());
00723 assert(shading_normal.IsUnitLength());
00724 assert(outgoing.IsUnitLength());
00725
00726
00727
00728
00729
00730
00731 const SurfaceBasis surfacebasis(shading_normal);
00732
00733 Ray reflected_ray(is_secondary ? Ray::SECONDARY_FG_RAY : Ray::PRIMARY_FG_RAY);
00734 reflected_ray.m_origin = point + 1.0e-8 * geometric_normal;
00735
00736 ISurfaceSampler::SampleVector::const_iterator i, e;
00737
00738 if(is_secondary) {
00739 m_secondary_fg_hss->GenerateNewSamples(context);
00740
00741 i = m_secondary_fg_hss->m_samples.begin();
00742 e = m_secondary_fg_hss->m_samples.end();
00743
00744 context.m_statistics->m_secondary_final_gathering_rays +=
00745 m_secondary_fg_hss->m_samples.size();
00746 } else {
00747 m_primary_fg_hss->GenerateNewSamples(context);
00748
00749 i = m_primary_fg_hss->m_samples.begin();
00750 e = m_primary_fg_hss->m_samples.end();
00751
00752 context.m_statistics->m_primary_final_gathering_rays +=
00753 m_primary_fg_hss->m_samples.size();
00754 }
00755
00756 Color3 radiance(0.0);
00757 int samples = 0;
00758
00759 for(; i != e; ++i) {
00760
00761 const Vector3 direction = CosineHemisphereSampling(i->m_x, i->m_y);
00762
00763
00764 reflected_ray.NewId();
00765 reflected_ray.m_direction = surfacebasis.TransformToWorld(direction);
00766 assert(reflected_ray.m_direction.IsUnitLength());
00767
00768
00769 Hit hit;
00770 if(m_scene->Trace(context, reflected_ray, &hit))
00771 ++samples;
00772 else continue;
00773
00774
00775 Point3 point2;
00776 Vector3 geometric_normal2, shading_normal2;
00777 hit.ExtractIntersection(reflected_ray, &point2, &geometric_normal2, &shading_normal2);
00778 const ISurfaceShader *surface_shader2 = hit.m_object->GetSurfaceShader();
00779
00780 ShadingData shadingdata2;
00781 surface_shader2->Shade(hit, &shadingdata2);
00782
00783 if( !is_secondary &&
00784 context.m_settings->m_rendering.m_components.m_indirect_lighting.m_secondary_fg.m_enabled &&
00785 hit.m_abscissa <
00786 context.m_settings->m_rendering.m_components.m_indirect_lighting.m_secondary_fg.m_distance_threshold)
00787 {
00788
00789
00790 radiance +=
00791 final_gathering(
00792 context,
00793 point2,
00794 geometric_normal2,
00795 shading_normal2,
00796 -reflected_ray.m_direction,
00797 shadingdata2,
00798 true
00799 );
00800 } else {
00801 radiance +=
00802 compute_indirect_illumination(
00803 context,
00804 point2,
00805 geometric_normal2,
00806 shading_normal2,
00807 -reflected_ray.m_direction,
00808 shadingdata2
00809 );
00810 }
00811 }
00812
00813 if(samples > 1)
00814 radiance /= samples;
00815
00816 return shadingdata.m_reflectance * radiance;
00817 }
00818
00819 Color3 Renderer::compute_caustics(const Context &context,
00820 const Point3 &point,
00821 const Vector3 &geometric_normal,
00822 const Vector3 &shading_normal,
00823 const Vector3 &outgoing,
00824 const ShadingData &shadingdata) const
00825 {
00826 assert(geometric_normal.IsUnitLength());
00827 assert(shading_normal.IsUnitLength());
00828 assert(outgoing.IsUnitLength());
00829
00830 if(!shadingdata.m_bdf->IsDiffuse())
00831 return Color3(0.0);
00832
00833 return m_caustics_pm->ComputeRadiance(
00834 context,
00835 point,
00836 geometric_normal,
00837 outgoing,
00838 shadingdata,
00839 context.m_settings->m_rendering.m_components.m_caustics.m_radiance_est.m_max_distance,
00840 context.m_settings->m_rendering.m_components.m_caustics.m_radiance_est.m_max_photons
00841 );
00842 }
00843
00844 Color3 Renderer::compute_indirect_illumination(const Context &context,
00845 const Point3 &point,
00846 const Vector3 &geometric_normal,
00847 const Vector3 &shading_normal,
00848 const Vector3 &outgoing,
00849 const ShadingData &shadingdata) const
00850 {
00851 assert(geometric_normal.IsUnitLength());
00852 assert(shading_normal.IsUnitLength());
00853 assert(outgoing.IsUnitLength());
00854
00855 if(context.m_settings->m_rendering.m_components.m_indirect_lighting.m_radiance_precomp.m_enabled) {
00856 return
00857 m_global_pm->GetPrecomputedRadiance(
00858 point,
00859 geometric_normal,
00860 shadingdata,
00861 context.m_settings->m_rendering.m_components.m_indirect_lighting.m_radiance_precomp.m_max_search_dist
00862 );
00863 } else {
00864
00865 return
00866 m_global_pm->ComputeRadiance(
00867 context,
00868 point,
00869 geometric_normal,
00870 outgoing,
00871 shadingdata,
00872 context.m_settings->m_rendering.m_components.m_indirect_lighting.m_radiance_est.m_max_distance,
00873 context.m_settings->m_rendering.m_components.m_indirect_lighting.m_radiance_est.m_max_photons
00874 );
00875 }
00876 }