00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <core_api/light.h>
00022 #include <core_api/surface.h>
00023 #include <core_api/environment.h>
00024 #include <core_api/object3d.h>
00025 #include <utilities/sample_utils.h>
00026
00027 __BEGIN_YAFRAY
00028
00037 class sphereLight_t : public light_t
00038 {
00039 public:
00040 sphereLight_t(const point3d_t &c, PFLOAT rad, const color_t &col, CFLOAT inte, int nsam);
00041 ~sphereLight_t();
00042 virtual void init(scene_t &scene);
00043 virtual color_t totalEnergy() const;
00044 virtual color_t emitPhoton(float s1, float s2, float s3, float s4, ray_t &ray, float &ipdf) const;
00045 virtual color_t emitSample(vector3d_t &wo, lSample_t &s) const;
00046 virtual bool diracLight() const { return false; }
00047 virtual bool illumSample(const surfacePoint_t &sp, float s1, float s2, color_t &col, float &ipdf, ray_t &wi) const;
00048 virtual bool illumSample(const surfacePoint_t &sp, lSample_t &s, ray_t &wi) const;
00049 virtual bool illuminate(const surfacePoint_t &sp, color_t &col, ray_t &wi)const { return false; }
00050 virtual bool canIntersect(){ return false; }
00051 virtual bool intersect(const ray_t &ray, PFLOAT &t, color_t &col, float &ipdf);
00052 virtual float illumPdf(const surfacePoint_t &sp, const surfacePoint_t &sp_light) const;
00053 virtual void emitPdf(const surfacePoint_t &sp, const vector3d_t &wo, float &areaPdf, float &dirPdf, float &cos_wo) const;
00054 virtual int nSamples() const { return samples; }
00055 static light_t *factory(paraMap_t ¶ms, renderEnvironment_t &render);
00056 protected:
00057 point3d_t center;
00058 PFLOAT radius, square_radius, square_radius_epsilon;
00059 color_t color;
00060 int samples;
00061 unsigned int objID;
00062 float area, invArea;
00063 };
00064
00065 sphereLight_t::sphereLight_t(const point3d_t &c, PFLOAT rad, const color_t &col, CFLOAT inte, int nsam):
00066 center(c), radius(rad), samples(nsam)
00067 {
00068 color = col*inte;
00069 square_radius = radius*radius;
00070 square_radius_epsilon = square_radius * 1.000003815;
00071 area = square_radius * 4.0 * M_PI;
00072 invArea = 1.f/area;
00073 }
00074
00075 sphereLight_t::~sphereLight_t(){ }
00076
00077 void sphereLight_t::init(scene_t &scene)
00078 {
00079 if(objID)
00080 {
00081 object3d_t *obj = scene.getObject(objID);
00082 if(obj) obj->setLight(this);
00083 else std::cout << "areaLight_t::init(): invalid object ID given!\n";
00084 }
00085 }
00086
00087 color_t sphereLight_t::totalEnergy() const { return color * area ; }
00088
00089 inline bool sphereIntersect(const ray_t &ray, const point3d_t &c, PFLOAT R2, PFLOAT &d1, PFLOAT &d2)
00090 {
00091 vector3d_t vf=ray.from-c;
00092 PFLOAT ea=ray.dir*ray.dir;
00093 PFLOAT eb=2.0*vf*ray.dir;
00094 PFLOAT ec=vf*vf-R2;
00095 PFLOAT osc=eb*eb-4.0*ea*ec;
00096 if(osc<0){ d1 = fSqrt(ec/ea); return false; }
00097 osc=fSqrt(osc);
00098 d1=(-eb-osc)/(2.0*ea);
00099 d2=(-eb+osc)/(2.0*ea);
00100 return true;
00101 }
00102
00103 bool sphereLight_t::illumSample(const surfacePoint_t &sp, float s1, float s2, color_t &col, float &ipdf, ray_t &wi) const
00104 {
00105 static bool debug=true;
00106 vector3d_t cdir = center - sp.P;
00107 PFLOAT dist_sqr = cdir.lengthSqr();
00108 if(dist_sqr <= square_radius)
00109 {
00110 if(debug) std::cout << "radius to small!?\n";
00111 debug=false;
00112 return false;
00113 }
00114 PFLOAT dist = fSqrt(dist_sqr);
00115 PFLOAT idist_sqr = 1.f/(dist_sqr);
00116 PFLOAT cosAlpha = fSqrt(1.f - square_radius * idist_sqr);
00117 cdir *= 1.f/dist;
00118 vector3d_t du, dv;
00119 createCS(cdir, du, dv);
00120
00121 wi.dir = sampleCone(cdir, du, dv, cosAlpha, s1, s2);
00122 PFLOAT d1, d2;
00123 if( !sphereIntersect(wi, center, square_radius_epsilon, d1, d2) )
00124 {
00125 if(debug){ std::cout << "missed the sphere!?\n"; debug=false; }
00126
00127 }
00128 wi.tmax = d1;
00129
00130
00131 ipdf = 2.f * (1.f - cosAlpha);
00132 col = color;
00133 return true;
00134 }
00135
00136 bool sphereLight_t::illumSample(const surfacePoint_t &sp, lSample_t &s, ray_t &wi) const
00137 {
00138 vector3d_t cdir = center - sp.P;
00139 PFLOAT dist_sqr = cdir.lengthSqr();
00140 if(dist_sqr <= square_radius) return false;
00141
00142 PFLOAT dist = fSqrt(dist_sqr);
00143 PFLOAT idist_sqr = 1.f/(dist_sqr);
00144 PFLOAT cosAlpha = fSqrt(1.f - square_radius * idist_sqr);
00145 cdir *= 1.f/dist;
00146 vector3d_t du, dv;
00147 createCS(cdir, du, dv);
00148
00149 wi.dir = sampleCone(cdir, du, dv, cosAlpha, s.s1, s.s2);
00150 PFLOAT d1, d2;
00151 if( !sphereIntersect(wi, center, square_radius_epsilon, d1, d2) )
00152 {
00153 return false;
00154 }
00155 wi.tmax = d1;
00156
00157
00158 s.pdf = 1.f / (2.f * (1.f - cosAlpha));
00159 s.col = color;
00160 s.flags = flags;
00161 if(s.sp)
00162 {
00163 s.sp->P = wi.from + d1 * wi.dir;
00164 s.sp->N = s.sp->Ng = (s.sp->P - center).normalize();
00165 }
00166 return true;
00167 }
00168
00169 bool sphereLight_t::intersect(const ray_t &ray, PFLOAT &t, color_t &col, float &ipdf)
00170 {
00171 PFLOAT d1, d2;
00172 if( sphereIntersect(ray, center, square_radius, d1, d2) )
00173 {
00174 vector3d_t cdir = center - ray.from;
00175 PFLOAT dist_sqr = cdir.lengthSqr();
00176 if(dist_sqr <= square_radius) return false;
00177
00178 PFLOAT idist_sqr = 1.f/(dist_sqr);
00179 PFLOAT cosAlpha = fSqrt(1.f - square_radius * idist_sqr);
00180 ipdf = 2.f * (1.f - cosAlpha);
00181 return true;
00182 }
00183 return false;
00184 }
00185
00186 float sphereLight_t::illumPdf(const surfacePoint_t &sp, const surfacePoint_t &sp_light) const
00187 {
00188 vector3d_t cdir = center - sp.P;
00189 PFLOAT dist_sqr = cdir.lengthSqr();
00190 if(dist_sqr <= square_radius) return 0.f;
00191 PFLOAT idist_sqr = 1.f/(dist_sqr);
00192 PFLOAT cosAlpha = fSqrt(1.f - square_radius * idist_sqr);
00193 return 1.f / (2.f * (1.f - cosAlpha));
00194 }
00195
00196 void sphereLight_t::emitPdf(const surfacePoint_t &sp, const vector3d_t &wo, float &areaPdf, float &dirPdf, float &cos_wo) const
00197 {
00198 areaPdf = invArea * M_PI;
00199 cos_wo = wo*sp.N;
00201 dirPdf = cos_wo > 0 ? cos_wo : 0.f;
00202 }
00203
00204 color_t sphereLight_t::emitPhoton(float s1, float s2, float s3, float s4, ray_t &ray, float &ipdf) const
00205 {
00206 vector3d_t sdir = SampleSphere(s3, s4);
00207 ray.from = center + radius*sdir;
00208 vector3d_t du, dv;
00209 createCS(sdir, du, dv);
00210 ray.dir = SampleCosHemisphere(sdir, du, dv, s1, s2);
00211 ipdf = area;
00212 return color;
00213 }
00214
00215 color_t sphereLight_t::emitSample(vector3d_t &wo, lSample_t &s) const
00216 {
00217 vector3d_t sdir = SampleSphere(s.s3, s.s4);
00218 s.sp->P = center + radius*sdir;
00219 s.sp->N = s.sp->Ng = sdir;
00220 vector3d_t du, dv;
00221 createCS(sdir, du, dv);
00222 wo = SampleCosHemisphere(sdir, du, dv, s.s1, s.s2);
00223 s.dirPdf = std::fabs(sdir * wo);
00224 s.areaPdf = invArea * M_PI;
00225 s.flags = flags;
00226 return color;
00227 }
00228
00229 light_t *sphereLight_t::factory(paraMap_t ¶ms,renderEnvironment_t &render)
00230 {
00231 point3d_t from(0.0);
00232 color_t color(1.0);
00233 CFLOAT power = 1.0;
00234 float radius = 1.f;
00235 int samples = 4;
00236 int object = 0;
00237
00238 params.getParam("from",from);
00239 params.getParam("color",color);
00240 params.getParam("power",power);
00241 params.getParam("radius",radius);
00242 params.getParam("samples",samples);
00243 params.getParam("object", object);
00244
00245 sphereLight_t *light = new sphereLight_t(from, radius, color, power, samples);
00246 light->objID = (unsigned int)object;
00247 return light;
00248 }
00249
00250 extern "C"
00251 {
00252 YAFRAYPLUGIN_EXPORT void registerPlugin(renderEnvironment_t &render)
00253 {
00254 render.registerFactory("spherelight", sphereLight_t::factory);
00255 }
00256 }
00257
00258 __END_YAFRAY