Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

renderer.cpp

Go to the documentation of this file.
00001 /*
00002     toxic - A Global Illumination Renderer
00003     Copyright (C) 2003-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of toxic.
00007 
00008     toxic is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     toxic is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with toxic; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "renderer.h"   // include first
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  // ENABLE_WHITTED_SAMPLING_CACHE
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     // Precompute some values.
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     // Initialize pixel surface sampler.
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     // Supersampling.
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     // Whitted adaptive sampling.
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         // Initialize area light surface sampler.
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         // Initialize primary final gathering hemisphere sampler.
00181         m_primary_fg_hss = SurfaceSamplerFactory::Create(
00182             context.m_settings->m_rendering.m_components.m_indirect_lighting.m_primary_fg
00183         );
00184 
00185         // Initialize secondary final gathering hemisphere sampler.
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 /*  static PentiumRTSC timer;
00237 
00238     timer.Start();*/
00239 
00240     switch(context.m_settings->m_rendering.m_pixel_sampling.m_algorithm) {
00241     // Supersampling.
00242     case Settings::Rendering::PixelSampling::SUPERSAMPLING:
00243         render_pixel_supersampling(context);
00244         break;
00245     // Whitted adaptive sampling.
00246     case Settings::Rendering::PixelSampling::WHITTED_ADAPTIVE_SAMPLING:
00247         render_pixel_whitted(context);
00248         break;
00249     default:
00250         assert(!"Internal failure.");
00251     }
00252 
00253 /*  timer.Stop();
00254 
00255     m_framebuffer->SetPixel(
00256         m_x, m_y,
00257         Color3(static_cast<Real>(timer.GetResult()))
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         // Trace a ray through the pixel to compute the radiance received from this direction.
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     // Store the radiance into the framebuffer.
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             // First line, first column.
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             // First line, any column.
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             // Any line, first column.
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             // Any line, any column (the most common case).
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   // recursion level
00365     );
00366 
00367     // Store the radiance into the framebuffer.
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 &center,
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         // The ray did not hit any object: return the background color.
00485         return m_scene->GetBackgroundColor();
00486     }
00487 
00488     const Vector3 outgoing = -ray.m_direction;
00489 
00490     // Extract intersection data.
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 // False colors rendering.
00500 //srand(int(hit.m_object));
00501 //return Color3(Real(rand() % 256) / 255.0, Real(rand() % 256) / 255.0, Real(rand() % 256) / 255.0);
00502 
00503     Color3 radiance(0.0);
00504 
00505     // Add direct lighting.
00506     if(context.m_settings->m_rendering.m_components.m_direct_lighting.m_enabled) {
00507         //!\todo Add an option to enable or disable direct incoming light.
00508         if(surface_shader->GetEDF()) {
00509             //!\todo This is a hack.
00510             radiance +=
00511                 surface_shader->GetRadiantExitance() / surface_shader->GetRadiantExitance().Average();
00512 //          radiance +=
00513 //              surface_shader->GetEDF()->GetEmittedRadiance(context, normal, outgoing) *
00514 //              surface_shader->GetRadiantExitance();
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     // Add indirect lighting.
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     // Add specular reflections.
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     // Add caustics.
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     // Build an orthonormal basis around the normal vector.
00603     //!\todo Move to caller.
00604     const SurfaceBasis surfacebasis(shading_normal);
00605     const Vector3 local_outgoing = surfacebasis.TransformToLocal(outgoing);
00606 
00607     // Start with ambient illumination.
00608     Color3 total_radiance = m_scene->GetAmbientIllumination();
00609 
00610     //!\todo Choose lights based on their occlusion-free contribution to the
00611     //! point being illuminated.
00612     for(int i = 0; i < m_scene->GetLightCount(); ++i) {
00613         const ILight *light = m_scene->GetLight(i);
00614 
00615         //!\todo Avoid generating samples for point lights.
00616         m_irradiance_samples.clear();
00617         m_arealight_ss->GenerateNewSamples(context);
00618 
00619         // Compute irradiance due to this light source.
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             // Evaluate the BSDF. 'bsdf_value' is expressed in sr^-1.
00643             const Real bsdf_value =
00644                 shadingdata.m_bdf->Evaluate(
00645                     context,
00646                     surfacebasis.TransformToLocal(sample.m_direction),
00647                     local_outgoing
00648                 );
00649 
00650             // Compute and accumulate the reflected radiance due to this light source.
00651             radiance += bsdf_value * sample.m_irradiance;
00652         }
00653 
00654         if(m_irradiance_samples.size() > 1)
00655             radiance /= m_irradiance_samples.size();    //!\todo Precompute the division.
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     // Build an orthonormal basis around the normal vector.
00682     //!\todo Move to caller.
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     // Reflected rays will be casted from a point that is slighty shifted along
00699     // the geometric normal to the surface at the intersection point. This
00700     // is necessary to avoid false intersections.
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     //!\todo Warning: units inconsistency.
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 /*= false*/) const
00721 {
00722     assert(geometric_normal.IsUnitLength());
00723     assert(shading_normal.IsUnitLength());
00724     assert(outgoing.IsUnitLength());
00725 
00726 //  if(is_secondary)
00727 //      return Color3(100.0, 0.0, 100.0);
00728 
00729     // Build an orthonormal basis around the normal vector.
00730     //!\todo Move to caller.
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         // Compute the direction of the reflected ray in local space.
00761         const Vector3 direction = CosineHemisphereSampling(i->m_x, i->m_y);
00762 
00763         // Compute the direction of the reflected ray in world space.
00764         reflected_ray.NewId();
00765         reflected_ray.m_direction = surfacebasis.TransformToWorld(direction);
00766         assert(reflected_ray.m_direction.IsUnitLength());
00767 
00768         // Trace the ray.
00769         Hit hit;
00770         if(m_scene->Trace(context, reflected_ray, &hit))
00771             ++samples;
00772         else continue;  // next cell
00773 
00774         // Extract intersection data.
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             // Distance along this final gathering ray is below the threshold:
00789             // we must perform a secondary, simpler final gathering.
00790             radiance +=
00791                 final_gathering(
00792                     context,
00793                     point2,
00794                     geometric_normal2,
00795                     shading_normal2,
00796                     -reflected_ray.m_direction,
00797                     shadingdata2,
00798                     true    // secondary final gathering
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         //!\todo Let the user choose between exact and approximate radiance computation.
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 }

Generated on Tue May 11 01:31:52 2004 for toxic by doxygen 1.3.6