00001 #include "AreaLight.h"
00002 #include <limits>
00003 #include "../math/Matrix4D.h"
00004
00005 using namespace std;
00006
00007 namespace rcrt
00008 {
00009
00010 AreaLight::AreaLight(const RGBColor& p, const Point3D& pos,
00011 const Vec3D& dir1, const Vec3D& dir2, const Vec3D& no):Light(p), base(pos),
00012 span1(dir1), span2(dir2),
00013 normal(
00014 ((dir1.crossP(dir2)).normalize() * no < 0 ?
00015 dir1.crossP(dir2) * -1
00016 : dir1.crossP(dir2))
00017 .normalized()
00018 ),
00019 area(normal.norm()), object("arealight"), material(this),
00020 tri1(pos, pos+dir1, pos+dir1+dir2, normal,&object),
00021 tri2(pos+dir1+dir2, pos+dir2, pos, normal,&object)
00022
00023 {
00024 minSamples = 4;
00025 cout << "area = " << area << " light samplecount = " << minSamples << endl;
00026 object.setWorldMatrix(Matrix4D::identity());
00027 object.setMaterial(&material);
00028 triList.push_back(&tri1);
00029 triList.push_back(&tri2);
00030 object.setPrimitives(&triList);
00031 aspect = span2.norm()/span1.norm();
00032 }
00033
00034 AreaLight::~AreaLight()
00035 {
00036 }
00037
00038
00039
00040
00041 LightSample AreaLight::illuminate(const Point3D& p, const Vec3D& no) const
00042 {
00043 const Point3D loc(getRandomPosition());
00044 return getSample(p,no,loc);
00045 }
00046
00047 void AreaLight::illuminate(const Point3D& p, const Vec3D& no, std::vector<LightSample>& samples,
00048 const int& noSamples, Scene* s) const
00049 {
00050 if(noSamples == 1){
00051 samples.push_back(getSample(p,no,base+0.5*span1+0.5*span2,s));
00052 } else if (noSamples == 4) {
00053 samples.push_back(getSample(p,no,base+0.125*span1+0.375*span2,s));
00054 samples.push_back(getSample(p,no,base+0.625*span1+0.125*span2,s));
00055 samples.push_back(getSample(p,no,base+0.875*span1+0.625*span2,s));
00056 samples.push_back(getSample(p,no,base+0.375*span1+0.875*span2,s));
00057 }
00058 int sampY = (int)floor(sqrt(noSamples*aspect));
00059 int sampX = (int)ceil(noSamples/sampY);
00060 float weight = 1.0f/(sampY*sampX);
00061 float uDist = 1.0f/sampX;
00062 float vDist = 1.0f/sampY;
00063 for(float u = 0.5; u < sampX; u++){
00064 for(float v = 0.5; v < sampY; v++){
00065 float xi1 = (float(rand()) / float(RAND_MAX) - 0.5) * uDist/4;
00066 float xi2 = (float(rand()) / float(RAND_MAX) - 0.5) * vDist/4;
00067
00068 LightSample ls = getSample(
00069 p,no,base + (u*uDist+xi1)*span1 + (v*vDist+xi2)*span2,s);
00070
00071 if(ls.weight() != 0)
00072 ls.setWeight(weight);
00073 samples.push_back(ls);
00074 }
00075 }
00076 }
00077
00078
00079 Point3D AreaLight::getRandomPosition() const
00080 {
00081
00082 float xi1 = float(rand()) / float(RAND_MAX);
00083 float xi2 = float(rand()) / float(RAND_MAX);
00084 return base + xi1 * span1 + xi2 * span2;
00085 }
00086
00087 Object* AreaLight::getObject()
00088 {
00089 return &object;
00090 }
00091
00092 RGBColor AreaLight::getEmitted(const Vec3D& dir, const Point3D& pos) const
00093 {
00094 float cosN = dir * normal;
00095 if (cosN < std::numeric_limits<float>::epsilon()){
00096 return 0;
00097 }
00098
00099 return power * area * cosN;
00100 }
00101
00102
00103 void AreaLight::emitPhoton(Photon* photon) const
00104 {
00105 float xi1 = float(rand()) / float(RAND_MAX);
00106 float xi2 = float(rand()) / float(RAND_MAX);
00107 float z2 = xi2 * 2.0f * M_PI;
00108 Vec3D outDir(span1.normalized() * cos(z2) + span2.normalized() * sin(z2) * sqrt(1-xi1) + normal * sqrt(xi1));
00109
00110
00111
00112
00113 outDir.normalize();
00114
00115
00116
00117 photon->setDir(outDir);
00118 photon->setPos((base + span1 * xi1 + span2 * xi2)+normal*0.000001f);
00119 photon->setPower(power * area * (photon->getDir() * normal));
00120 }
00121
00122 }