00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <lights/bglight.h>
00022 #include <core_api/background.h>
00023 #include <core_api/texture.h>
00024 #include <utilities/sample_utils.h>
00025
00026 __BEGIN_YAFRAY
00027
00028 #define MAX_VSAMPLES 360
00029 #define MAX_USAMPLES 720
00030 #define MIN_SAMPLES 4
00031
00032 #define SMPL_OFF 0.4999f
00033
00034 #define sigma 0.000001f
00035
00036 #define addOff(v) (v + SMPL_OFF)
00037 #define clampSample(s, m) std::max(0, std::min((int)(v), m - 1))
00038
00039 #define multPdf(p0, p1) (p0 * p1)
00040 #define calcPdf(p0, p1, s) std::max( sigma, multPdf(p0, p1) * (float)M_1_2PI * clampZero(sinSample(s)) )
00041 #define calcInvPdf(p0, p1, s) std::max( sigma, (float)M_2PI * sinSample(s) * clampZero(multPdf(p0, p1)) )
00042
00043 inline float clampZero(float val)
00044 {
00045 if(val > 0.f) return 1.f / val;
00046 else return 0.f;
00047 }
00048
00049 inline float sinSample(float s)
00050 {
00051 return fSin(s * M_PI);
00052 }
00053
00054 bgLight_t::bgLight_t(background_t *bg, int sampl):light_t(LIGHT_SINGULAR), samples(sampl), background(bg)
00055 {
00056 initIS();
00057 }
00058
00059 bgLight_t::~bgLight_t()
00060 {
00061 for(int i = 0; i < vDist->count; i++) delete uDist[i];
00062 delete[] uDist;
00063 delete vDist;
00064 }
00065
00066 void bgLight_t::initIS()
00067 {
00068 float *fu = new float[MAX_USAMPLES];
00069 float *fv = new float[MAX_VSAMPLES];
00070 float inu = 0, inv = 0;
00071 float fx = 0.f, fy = 0.f;
00072 float sintheta = 0.f;
00073 int nu = 0, nv = MAX_VSAMPLES;
00074
00075 ray_t ray;
00076 ray.from = point3d_t(0.f);
00077
00078 inv = 1.f / (float)nv;
00079
00080 uDist = new pdf1D_t*[nv];
00081
00082 for (int y = 0; y < nv; y++)
00083 {
00084 fy = ((float)y + 0.5f) * inv;
00085
00086 sintheta = sinSample(fy);
00087
00088 nu = MIN_SAMPLES + (int)(sintheta * (MAX_USAMPLES - MIN_SAMPLES));
00089 inu = 1.f / (float)nu;
00090
00091 for(int x = 0; x < nu; x++)
00092 {
00093 fx = ((float)x + 0.5f) * inu;
00094
00095 invSpheremap(fx, fy, ray.dir);
00096
00097 fu[x] = background->eval(ray).energy() * sintheta;
00098 }
00099
00100 uDist[y] = new pdf1D_t(fu, nu);
00101
00102 fv[y] = uDist[y]->integral;
00103 }
00104
00105 vDist = new pdf1D_t(fv, nv);
00106
00107 delete[] fv;
00108 delete[] fu;
00109 }
00110
00111 void bgLight_t::init(scene_t &scene)
00112 {
00113 bound_t w=scene.getSceneBound();
00114 worldCenter = 0.5 * (w.a + w.g);
00115 worldRadius = 0.5 * (w.g - w.a).length();
00116 aPdf = worldRadius * worldRadius;
00117 iaPdf = 1.f / aPdf;
00118 worldPIFactor = (M_2PI * aPdf);
00119 }
00120
00121 inline float bgLight_t::CalcFromSample(float s1, float s2, float &u, float &v, bool inv) const
00122 {
00123 int iv;
00124 float pdf1 = 0.f, pdf2 = 0.f;
00125
00126 v = vDist->Sample(s2, &pdf2);
00127
00128 iv = clampSample(addOff(v), vDist->count);
00129
00130 u = uDist[iv]->Sample(s1, &pdf1);
00131
00132 u *= uDist[iv]->invCount;
00133 v *= vDist->invCount;
00134
00135 if(inv)return calcInvPdf(pdf1, pdf2, v);
00136
00137 return calcPdf(pdf1, pdf2, v);
00138 }
00139
00140 inline float bgLight_t::CalcFromDir(const vector3d_t &dir, float &u, float &v, bool inv) const
00141 {
00142 int iv, iu;
00143 float invInt;
00144 float pdf1 = 0.f, pdf2 = 0.f;
00145
00146 spheremap(dir, u, v);
00147
00148 u = u * 0.5f + 0.5f;
00149 v = v * 0.5f + 0.5f;
00150
00151 iv = clampSample(addOff(v * vDist->count), vDist->count);
00152 iu = clampSample(addOff(u * uDist[iv]->count), uDist[iv]->count);
00153
00154 invInt = uDist[iv]->invIntegral * vDist->invIntegral;
00155
00156 pdf1 = uDist[iv]->func[iu] * invInt;
00157 pdf2 = vDist->func[iv] * invInt;
00158
00159 if(inv)return calcInvPdf(pdf1, pdf2, v);
00160
00161 return calcPdf(pdf1, pdf2, v);
00162
00163 }
00164
00165 void bgLight_t::sample_dir(float s1, float s2, vector3d_t &dir, float &pdf, bool inv) const
00166 {
00167 float u = 0.f, v = 0.f;
00168
00169 pdf = CalcFromSample(s1, s2, u, v, inv);
00170
00171 invSpheremap(u, v, dir);
00172 }
00173
00174
00175 float bgLight_t::dir_pdf(const vector3d_t dir) const
00176 {
00177 float u = 0.f, v = 0.f;
00178
00179 return CalcFromDir(dir, u, v);
00180 }
00181
00182 bool bgLight_t::illumSample(const surfacePoint_t &sp, lSample_t &s, ray_t &wi) const
00183 {
00184 float u = 0.f, v = 0.f;
00185 vector3d_t U, V;
00186
00187 wi.tmax = -1.0;
00188
00189 s.pdf = CalcFromSample(s.s1, s.s2, u, v, false);
00190
00191 invSpheremap(u, v, wi.dir);
00192
00193 s.col = background->eval(wi);
00194
00195 return true;
00196 }
00197
00198 bool bgLight_t::intersect(const ray_t &ray, PFLOAT &t, color_t &col, float &ipdf) const
00199 {
00200 float u = 0.f, v = 0.f;
00201 ray_t tr = ray;
00202
00203 ipdf = CalcFromDir(tr.dir, u, v, true);
00204
00205 invSpheremap(u, v, tr.dir);
00206
00207 col = background->eval(tr);
00208
00209 return true;
00210 }
00211
00212 color_t bgLight_t::totalEnergy() const
00213 {
00214 color_t energy = background->eval(ray_t(point3d_t(0,0,0), vector3d_t(0.5, 0.5, 0.5))) * worldPIFactor;
00215 return energy;
00216 }
00217
00218 color_t bgLight_t::emitPhoton(float s1, float s2, float s3, float s4, ray_t &ray, float &ipdf) const
00219 {
00220 color_t pcol;
00221 vector3d_t U, V;
00222 vector3d_t offs;
00223 float u, v;
00224
00225 sample_dir(s3, s4, ray.dir, ipdf, true);
00226
00227 pcol = background->eval(ray);
00228 ray.dir = -ray.dir;
00229
00230 createCS(ray.dir, U, V);
00231 ShirleyDisk(s1, s2, u, v);
00232
00233 offs = u*U + v*V;
00234
00235 ray.from = worldCenter + worldRadius*(offs - ray.dir);
00236
00237 return pcol * aPdf;
00238 }
00239
00240 color_t bgLight_t::emitSample(vector3d_t &wo, lSample_t &s) const
00241 {
00242 color_t pcol;
00243 vector3d_t U, V;
00244 vector3d_t offs;
00245 float u, v;
00246
00247 sample_dir(s.s1, s.s2, wo, s.dirPdf, true);
00248
00249 pcol = background->eval(ray_t(point3d_t(0,0,0), wo));
00250 wo = -wo;
00251
00252 createCS(wo, U, V);
00253 ShirleyDisk(s.s1, s.s2, u, v);
00254
00255 offs = u*U + v*V;
00256
00257 s.sp->P = worldCenter + worldRadius*offs - worldRadius*wo;
00258 s.sp->N = s.sp->Ng = wo;
00259 s.areaPdf = 1.f;
00260 s.flags = flags;
00261
00262 return pcol;
00263 }
00264
00265 float bgLight_t::illumPdf(const surfacePoint_t &sp, const surfacePoint_t &sp_light) const
00266 {
00267 vector3d_t dir = (sp_light.P - sp.P).normalize();
00268 return dir_pdf(dir);
00269 }
00270
00271 void bgLight_t::emitPdf(const surfacePoint_t &sp, const vector3d_t &wo, float &areaPdf, float &dirPdf, float &cos_wo) const
00272 {
00273 vector3d_t wi = wo;
00274 wi.normalize();
00275 cos_wo = wi.z;
00276 wi = -wi;
00277 dirPdf = dir_pdf(wi);
00278 areaPdf = 1.f;
00279 }
00280
00281 __END_YAFRAY
00282