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

iarealight.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 "iarealight.h" // include first
00024 #include "common/math/real.h"
00025 #include "context.h"
00026 #include "hit.h"
00027 #include "iedf.h"
00028 #include "isurfaceshader.h"
00029 #include "ray.h"
00030 #include "scene.h"
00031 #include "settings.h"
00032 #include "statistics.h"
00033 #include "surfacebasis.h"
00034 #include "utilities.h"
00035 
00036 #include <cassert>
00037 #include <cmath>
00038 #include <vector>
00039 
00040 using namespace sheep;
00041 using namespace std;
00042 using namespace toxic;
00043 
00044 IAreaLight::IAreaLight(const Matrix4 &m,
00045                        const ISurfaceShader *surface_shader,
00046                        IntersectionMask intersection_mask /*= INTERSECT_ALL_RAYS*/) :
00047     IBoundedObject(m, surface_shader, intersection_mask),
00048     ILight(true)    // cast shadows
00049 {
00050 }
00051 
00052 void IAreaLight::Finalize(const Context &context) {
00053     // Precompute object surface area.
00054     m_surface_area = ComputeSurfaceArea();
00055 
00056     // Precompute object emission power.
00057     m_power = m_surface_area * m_surface_shader->GetRadiantExitance();
00058 }
00059 
00060 Ray IAreaLight::GeneratePhotonRay(const Context &context) const {
00061     Ray ray(Ray::PHOTON_RAY);
00062     Vector3 normal;
00063 
00064     EvaluateSurface(
00065         Point2(context.m_rng->RandomReal1(), context.m_rng->RandomReal1()),
00066         &ray.m_origin,
00067         &normal);
00068 
00069     // Photon rays will be casted from a point that is slighty shifted along
00070     // the geometric normal to the light surface at the sample location. This
00071     // is necessary to avoid false intersections.
00072     ray.m_origin += 1.0e-8 * normal;
00073 
00074     Vector3 direction;
00075     Real prob;
00076 
00077     GetSurfaceShader()->GetEDF()->Sample(
00078         context,
00079         &direction,
00080         &prob);
00081 
00082     ray.m_direction = SurfaceBasis(normal).TransformToWorld(direction);
00083 
00084     //!\todo And what about prob?
00085 
00086     return ray;
00087 }
00088 
00089 void IAreaLight::ComputeIrradiance(const Context &context,
00090                                    const Scene *scene,
00091                                    const Point3 &point,
00092                                    const Vector3 &geometric_normal,
00093                                    const Vector3 &shading_normal,
00094                                    const ISurfaceSampler::SampleVector &input,
00095                                    IrradianceSampleVector *output) const
00096 {
00097     assert(scene);
00098     assert(geometric_normal.IsUnitLength());
00099     assert(shading_normal.IsUnitLength());
00100     assert(output);
00101 
00102     for(ISurfaceSampler::SampleVector::const_iterator i = input.begin(), e = input.end(); i != e; ++i) {
00103         Point3 sample_point;
00104         Vector3 sample_geometric_normal;
00105 
00106         EvaluateSurface(*i, &sample_point, &sample_geometric_normal);
00107 
00108         Vector3 incoming = sample_point - point;
00109         const Real inv_distance2 = 1.0 / incoming.SquareNorm();
00110 
00111         // Normalize the 'incoming' vector.
00112         incoming *= sqrt(inv_distance2);
00113         assert(incoming.IsUnitLength());
00114 
00115         //!\todo Not sure which normal to use.
00116         const Real cos_theta = shading_normal * incoming;
00117 
00118         if(cos_theta <= 0.0) {
00119             // The surface is not directed toward the light: next sample.
00120             output->push_back(IrradianceSample(Color3(0.0), incoming));
00121             continue;
00122         }
00123 
00124         const Real emitted_radiance = GetSurfaceShader()->GetEDF()->GetEmittedRadiance(
00125             context,
00126             sample_geometric_normal,
00127             -incoming);
00128 
00129         assert(emitted_radiance >= 0.0);
00130 
00131         if(emitted_radiance <= 0.0) {
00132             // The light surface element is not directed toward the point: next sample.
00133             output->push_back(IrradianceSample(Color3(0.0), incoming));
00134             continue;
00135         }
00136 
00137         if(m_cast_shadows) {
00138             ++context.m_statistics->m_shadow_rays;
00139 
00140             const Point3 shifted_sample = sample_point + 1.0e-8 * sample_geometric_normal;
00141 
00142             if(!scene->ArePointsMutuallyVisible(
00143                 context,
00144                 point,
00145                 geometric_normal,
00146                 shifted_sample,
00147                 Ray::SHADOW_RAY))
00148             {
00149                 // Point is in shadow: next sample.
00150                 output->push_back(IrradianceSample(Color3(0.0), incoming));
00151                 continue;
00152             }
00153         }
00154 
00155         const Color3 irradiance = (m_surface_area * cos_theta * emitted_radiance * inv_distance2) *
00156             m_surface_shader->GetRadiantExitance();
00157 
00158         output->push_back(IrradianceSample(irradiance, incoming));
00159     }
00160 }

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