00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "iarealight.h"
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 ) :
00047 IBoundedObject(m, surface_shader, intersection_mask),
00048 ILight(true)
00049 {
00050 }
00051
00052 void IAreaLight::Finalize(const Context &context) {
00053
00054 m_surface_area = ComputeSurfaceArea();
00055
00056
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
00070
00071
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
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
00112 incoming *= sqrt(inv_distance2);
00113 assert(incoming.IsUnitLength());
00114
00115
00116 const Real cos_theta = shading_normal * incoming;
00117
00118 if(cos_theta <= 0.0) {
00119
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
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
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 }