00001 #include "SphericalLight.h"
00002
00003 namespace rcrt
00004 {
00005
00006 SphericalLight::SphericalLight(const RGBColor& power, const float& rad, const Point3D& c, const int& samp):
00007 Light(power, samp),radius(rad),center(c), radius2(rad*rad)
00008 {
00009
00010 }
00011
00012 SphericalLight::~SphericalLight()
00013 {
00014 }
00015
00016
00017 LightSample SphericalLight::illuminate(const Point3D& p, const Vec3D& normal) const
00018 {
00019 Vec3D dir = center - p;
00020 float distSqr = dir * dir;
00021 if(distSqr <= radius2)
00022 {
00023 return LightSample(0,0,0,0);
00024 }
00025 float dist = sqrt(distSqr);
00026 float idistSqr = 1.f/(distSqr);
00027 float cosAlpha = std::sqrt(1.f - radius2 * idistSqr);
00028 dir = dir * 1.f/dist;
00029 Vec3D du, dv;
00030 dir.getCS(du, dv);
00031 const float xi1 = float(rand()) / float(RAND_MAX);
00032 const float xi2 = float(rand()) / float(RAND_MAX);
00033 double cosAng = 1.0 - (1.0-(double)cosAlpha) * xi2;
00034 double sinAng = sqrt(1.0 - cosAng*cosAng);
00035 float t1 = 2.0*M_PI*xi1;
00036 Vec3D sampleDir((du*cos(t1) + dv*sin(t1))*sinAng + dir*cosAng);
00037
00038 const Vec3D vf = p - center;
00039 const float ea = sampleDir * sampleDir;
00040 const float eb = 2.0*vf*sampleDir;
00041 const float ec = vf*vf-radius2+0.00001f;
00042 const float osc = eb*eb-4.0*ea*ec;
00043 float d1;
00044 if(osc < 0) {
00045 d1 = sqrt(ec/ea);
00046 } else {
00047 d1 = (-eb-sqrt(osc))/(2.0*ea);
00048 }
00049
00050 return LightSample(2.f * (1.f - cosAlpha), sampleDir, d1, power);
00051 }
00052
00053 void SphericalLight::illuminate(const Point3D& p, const Vec3D& normal, std::vector<LightSample>& samples,
00054 const int& noSamples, Scene* s) const
00055 {
00056 Vec3D dir(center-p);
00057 const float dist2 = dir * dir;
00058 if(dist2 < radius2)
00059 return;
00060 const float cosThetaMax(sqrt(std::max(0.0f, 1.0f - radius2 / (dist2 * 0.01f + float(sqrt(dist2)) * 0.25f + 1))));
00061 const float scale(2.0f * M_PI * (1.0f - cosThetaMax));
00062 const float weight(scale / noSamples);
00063 for(int i = 0; i < noSamples; i++){
00064 samples.push_back(illuminate(p, normal));
00065 samples.back().setWeight(weight);
00066 }
00067 }
00068
00069 RGBColor SphericalLight::getEmitted(const Vec3D& dir, const Point3D& pos) const
00070 {
00071 return power;
00072 }
00073
00074 void SphericalLight::emitPhoton(Photon* photon) const
00075 {
00076
00077 }
00078
00079 }