Blender V2.61 - r43446

sunsky.c

Go to the documentation of this file.
00001  /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * ***** END GPL LICENSE BLOCK *****
00019  */
00020 
00027 #include "sunsky.h"
00028 #include "math.h"
00029 #include "BLI_math.h"
00030 #include "BKE_global.h"
00031 
00040 #define vec3opv(v1, v2, op, v3) \
00041     v1[0] = (v2[0] op v3[0]); \
00042     v1[1] = (v2[1] op v3[1]);\
00043     v1[2] = (v2[2] op v3[2]);
00044 
00050 #define vec3opf(v1, v2, op, f1)\
00051     v1[0] = (v2[0] op (f1));\
00052     v1[1] = (v2[1] op (f1));\
00053     v1[2] = (v2[2] op (f1));
00054 
00060 #define fopvec3(v1, f1, op, v2)\
00061     v1[0] = ((f1) op v2[0]);\
00062     v1[1] = ((f1) op v2[1]);\
00063     v1[2] = ((f1) op v2[2]);
00064 
00069 void ClipColor(float c[3])
00070 {
00071     if (c[0] > 1.0f) c[0] = 1.0f;
00072     if (c[0] < 0.0f) c[0] = 0.0f;
00073     if (c[1] > 1.0f) c[1] = 1.0f;
00074     if (c[1] < 0.0f) c[1] = 0.0f;
00075     if (c[2] > 1.0f) c[2] = 1.0f;
00076     if (c[2] < 0.0f) c[2] = 0.0f;
00077 }
00078 
00084 static float AngleBetween(float thetav, float phiv, float theta, float phi)
00085 {
00086     float cospsi = sin(thetav) * sin(theta) * cos(phi - phiv) + cos(thetav) * cos(theta);
00087 
00088     if (cospsi > 1.0f)
00089         return 0;
00090     if (cospsi < -1.0f)
00091         return M_PI;
00092 
00093     return acos(cospsi);
00094 }
00095 
00103 static void DirectionToThetaPhi(float *toSun, float *theta, float *phi)
00104 {
00105     *theta = acos(toSun[2]);
00106     if (fabs(*theta) < 1e-5)
00107         *phi = 0;
00108     else
00109         *phi = atan2(toSun[1], toSun[0]);
00110 }
00111 
00116 static float PerezFunction(struct SunSky *sunsky, const float *lam, float theta, float gamma, float lvz)
00117 {
00118     float den, num;
00119     
00120     den = ((1 + lam[0] * expf(lam[1])) *
00121            (1 + lam[2] * expf(lam[3] * sunsky->theta) + lam[4] * cosf(sunsky->theta) * cosf(sunsky->theta)));
00122     
00123     num = ((1 + lam[0] * expf(lam[1] / cosf(theta))) *
00124            (1 + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma)));
00125     
00126     return(lvz * num / den);}
00127 
00141 void InitSunSky(struct SunSky *sunsky, float turb, float *toSun, float horizon_brightness, 
00142                 float spread,float sun_brightness, float sun_size, float back_scatter,
00143                 float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace)
00144 {
00145     float theta2;
00146     float theta3;
00147     float T;
00148     float T2;
00149     float chi;
00150 
00151     sunsky->turbidity = turb;
00152 
00153     sunsky->horizon_brightness = horizon_brightness;
00154     sunsky->spread = spread;
00155     sunsky->sun_brightness = sun_brightness;
00156     sunsky->sun_size = sun_size;
00157     sunsky->backscattered_light = back_scatter;
00158     sunsky->skyblendfac= skyblendfac;
00159     sunsky->skyblendtype= skyblendtype;
00160     sunsky->sky_exposure= -sky_exposure;
00161     sunsky->sky_colorspace= sky_colorspace;
00162     
00163     sunsky->toSun[0] = toSun[0];
00164     sunsky->toSun[1] = toSun[1];
00165     sunsky->toSun[2] = toSun[2];
00166 
00167     DirectionToThetaPhi(sunsky->toSun, &sunsky->theta, &sunsky->phi);
00168 
00169     sunsky->sunSolidAngle = 0.25 * M_PI * 1.39 * 1.39 / (150 * 150);   // = 6.7443e-05
00170 
00171     theta2 = sunsky->theta*sunsky->theta;
00172     theta3 = theta2 * sunsky->theta;
00173     T = turb;
00174     T2 = turb*turb;
00175 
00176     chi = (4.0f / 9.0f - T / 120.0f) * ((float)M_PI - 2.0f * sunsky->theta);
00177     sunsky->zenith_Y = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
00178     sunsky->zenith_Y *= 1000;   // conversion from kcd/m^2 to cd/m^2
00179 
00180     if (sunsky->zenith_Y<=0)
00181         sunsky->zenith_Y = 1e-6;
00182     
00183     sunsky->zenith_x =
00184         ( + 0.00165f * theta3 - 0.00374f * theta2 + 0.00208f * sunsky->theta + 0.0f) * T2 +
00185         ( -0.02902f * theta3 + 0.06377f * theta2 - 0.03202f * sunsky->theta + 0.00394f) * T +
00186         ( + 0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * sunsky->theta + 0.25885f);
00187 
00188     sunsky->zenith_y =
00189         ( + 0.00275f * theta3 - 0.00610f * theta2 + 0.00316f * sunsky->theta + 0.0f) * T2 +
00190         ( -0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * sunsky->theta + 0.00515f) * T +
00191         ( + 0.15346f * theta3 - 0.26756f * theta2 + 0.06669f * sunsky->theta + 0.26688f);
00192 
00193     
00194     sunsky->perez_Y[0] = 0.17872f * T - 1.46303f;
00195     sunsky->perez_Y[1] = -0.35540f * T + 0.42749f;
00196     sunsky->perez_Y[2] = -0.02266f * T + 5.32505f;
00197     sunsky->perez_Y[3] = 0.12064f * T - 2.57705f;
00198     sunsky->perez_Y[4] = -0.06696f * T + 0.37027f;
00199 
00200     sunsky->perez_x[0] = -0.01925f * T - 0.25922f;
00201     sunsky->perez_x[1] = -0.06651f * T + 0.00081f;
00202     sunsky->perez_x[2] = -0.00041f * T + 0.21247f;
00203     sunsky->perez_x[3] = -0.06409f * T - 0.89887f;
00204     sunsky->perez_x[4] = -0.00325f * T + 0.04517f;
00205 
00206     sunsky->perez_y[0] = -0.01669f * T - 0.26078f;
00207     sunsky->perez_y[1] = -0.09495f * T + 0.00921f;
00208     sunsky->perez_y[2] = -0.00792f * T + 0.21023f;
00209     sunsky->perez_y[3] = -0.04405f * T - 1.65369f;
00210     sunsky->perez_y[4] = -0.01092f * T + 0.05291f;
00211     
00212     /* suggested by glome in 
00213      * http://projects.blender.org/tracker/?func=detail&atid=127&aid=8063&group_id=9*/
00214     sunsky->perez_Y[0] *= sunsky->horizon_brightness;
00215     sunsky->perez_x[0] *= sunsky->horizon_brightness;
00216     sunsky->perez_y[0] *= sunsky->horizon_brightness;
00217     
00218     sunsky->perez_Y[1] *= sunsky->spread;
00219     sunsky->perez_x[1] *= sunsky->spread;
00220     sunsky->perez_y[1] *= sunsky->spread;
00221 
00222     sunsky->perez_Y[2] *= sunsky->sun_brightness;
00223     sunsky->perez_x[2] *= sunsky->sun_brightness;
00224     sunsky->perez_y[2] *= sunsky->sun_brightness;
00225     
00226     sunsky->perez_Y[3] *= sunsky->sun_size;
00227     sunsky->perez_x[3] *= sunsky->sun_size;
00228     sunsky->perez_y[3] *= sunsky->sun_size;
00229     
00230     sunsky->perez_Y[4] *= sunsky->backscattered_light;
00231     sunsky->perez_x[4] *= sunsky->backscattered_light;
00232     sunsky->perez_y[4] *= sunsky->backscattered_light;
00233 }
00234 
00244 void GetSkyXYZRadiance(struct SunSky* sunsky, float theta, float phi, float color_out[3])
00245 {
00246     float gamma;
00247     float x,y,Y,X,Z;
00248     float hfade=1, nfade=1;
00249 
00250 
00251     if (theta>(0.5f*(float)M_PI)) {
00252         hfade = 1.0f-(theta*(float)M_1_PI-0.5f)*2.0f;
00253         hfade = hfade*hfade*(3.0f-2.0f*hfade);
00254         theta = 0.5*M_PI;
00255     }
00256 
00257     if (sunsky->theta>(0.5f*(float)M_PI)) {
00258         if (theta<=0.5f*(float)M_PI) {
00259             nfade = 1.0f-(0.5f-theta*(float)M_1_PI)*2.0f;
00260             nfade *= 1.0f-(sunsky->theta*(float)M_1_PI-0.5f)*2.0f;
00261             nfade = nfade*nfade*(3.0f-2.0f*nfade);
00262         }
00263     }
00264 
00265     gamma = AngleBetween(theta, phi, sunsky->theta, sunsky->phi);
00266     
00267     // Compute xyY values
00268     x = PerezFunction(sunsky, sunsky->perez_x, theta, gamma, sunsky->zenith_x);
00269     y = PerezFunction(sunsky, sunsky->perez_y, theta, gamma, sunsky->zenith_y);
00270     Y = 6.666666667e-5f * nfade * hfade * PerezFunction(sunsky, sunsky->perez_Y, theta, gamma, sunsky->zenith_Y);
00271 
00272     if(sunsky->sky_exposure!=0.0f)
00273         Y = 1.0 - exp(Y*sunsky->sky_exposure);
00274     
00275     X = (x / y) * Y;
00276     Z = ((1 - x - y) / y) * Y;
00277 
00278     color_out[0] = X;
00279     color_out[1] = Y;
00280     color_out[2] = Z;
00281 }
00282 
00291 void GetSkyXYZRadiancef(struct SunSky* sunsky, const float varg[3], float color_out[3])
00292 {
00293     float   theta, phi;
00294     float   v[3];
00295 
00296     copy_v3_v3(v, (float*)varg);
00297     normalize_v3(v);
00298 
00299     if (v[2] < 0.001f) {
00300         v[2] = 0.001f;
00301         normalize_v3(v);
00302     }
00303 
00304     DirectionToThetaPhi(v, &theta, &phi);
00305     GetSkyXYZRadiance(sunsky, theta, phi, color_out);
00306 }
00307 
00316 static void ComputeAttenuatedSunlight(float theta, int turbidity, float fTau[3])
00317 {
00318     float fBeta ;
00319     float fTauR, fTauA;
00320     float m ;
00321     float fAlpha;
00322 
00323     int i;
00324     float fLambda[3]; 
00325     fLambda[0] = 0.65f; 
00326     fLambda[1] = 0.57f; 
00327     fLambda[2] = 0.475f;
00328 
00329     fAlpha = 1.3f;
00330     fBeta = 0.04608365822050f * turbidity - 0.04586025928522f;
00331     
00332     m =  1.0f/(cosf(theta) + 0.15f*powf(93.885f-theta/(float)M_PI*180.0f,-1.253f));
00333 
00334     for(i = 0; i < 3; i++)
00335     {
00336         // Rayleigh Scattering
00337         fTauR = expf( -m * 0.008735f * powf(fLambda[i], (float)(-4.08f)));
00338 
00339         // Aerosal (water + dust) attenuation
00340         fTauA = exp(-m * fBeta * powf(fLambda[i], -fAlpha));
00341 
00342         fTau[i] = fTauR * fTauA; 
00343     }
00344 }
00345 
00358 void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float rayf,
00359                             float inscattf, float extincf, float disf)
00360 {
00361     const float pi = 3.14159265358f;
00362     const float n = 1.003f; // refractive index
00363     const float N = 2.545e25;
00364     const float pn = 0.035f;
00365     const float T = 2.0f;
00366     float fTemp, fTemp2, fTemp3, fBeta, fBetaDash;
00367     float c = (6.544f*T - 6.51f)*1e-17f;
00368     float K[3] = {0.685f, 0.679f, 0.670f};
00369     float vBetaMieTemp[3];
00370     
00371     float fLambda[3],fLambda2[3], fLambda4[3];
00372     float vLambda2[3];
00373     float vLambda4[3];
00374     
00375     int i;
00376 
00377     sunSky->atm_SunIntensity = sun_intens;
00378     sunSky->atm_BetaMieMultiplier  = mief;
00379     sunSky->atm_BetaRayMultiplier = rayf;
00380     sunSky->atm_InscatteringMultiplier = inscattf;
00381     sunSky->atm_ExtinctionMultiplier = extincf;
00382     sunSky->atm_DistanceMultiplier = disf;
00383         
00384     sunSky->atm_HGg=0.8;
00385 
00386     fLambda[0]  = 1/650e-9f; 
00387     fLambda[1]  = 1/570e-9f;
00388     fLambda[2]  = 1/475e-9f;
00389     for (i=0; i < 3; i++)
00390     {
00391         fLambda2[i] = fLambda[i]*fLambda[i];
00392         fLambda4[i] = fLambda2[i]*fLambda2[i];
00393     }
00394 
00395     vLambda2[0] = fLambda2[0];
00396     vLambda2[1] = fLambda2[1];
00397     vLambda2[2] = fLambda2[2];
00398  
00399     vLambda4[0] = fLambda4[0];
00400     vLambda4[1] = fLambda4[1];
00401     vLambda4[2] = fLambda4[2];
00402 
00403     // Rayleigh scattering constants.
00404     fTemp = pi*pi*(n*n-1)*(n*n-1)*(6+3*pn)/(6-7*pn)/N;
00405     fBeta = 8*fTemp*pi/3;
00406         
00407     vec3opf(sunSky->atm_BetaRay, vLambda4, *, fBeta);
00408     fBetaDash = fTemp/2;
00409     vec3opf(sunSky->atm_BetaDashRay, vLambda4,*, fBetaDash);
00410     
00411 
00412     // Mie scattering constants.
00413     fTemp2 = 0.434f*c*(2*pi)*(2*pi)*0.5f;
00414     vec3opf(sunSky->atm_BetaDashMie, vLambda2, *, fTemp2);
00415     
00416     fTemp3 = 0.434f*c*pi*(2*pi)*(2*pi);
00417     
00418     vec3opv(vBetaMieTemp, K, *, fLambda);
00419     vec3opf(sunSky->atm_BetaMie, vBetaMieTemp,*, fTemp3);
00420     
00421 }
00422 
00432 void AtmospherePixleShader( struct SunSky* sunSky, float view[3], float s, float rgb[3])
00433 {
00434     float costheta;
00435     float Phase_1;
00436     float Phase_2;
00437     float sunColor[3];
00438     
00439     float E[3];
00440     float E1[3];
00441     
00442     
00443     float I[3];
00444     float fTemp;
00445     float vTemp1[3], vTemp2[3];
00446 
00447     float sunDirection[3];
00448     
00449     s *= sunSky->atm_DistanceMultiplier;
00450     
00451     sunDirection[0] = sunSky->toSun[0];
00452     sunDirection[1] = sunSky->toSun[1];
00453     sunDirection[2] = sunSky->toSun[2];
00454     
00455     costheta = dot_v3v3(view, sunDirection); // cos(theta)
00456     Phase_1 = 1 + (costheta * costheta); // Phase_1
00457     
00458     vec3opf(sunSky->atm_BetaRay, sunSky->atm_BetaRay, *, sunSky->atm_BetaRayMultiplier);
00459     vec3opf(sunSky->atm_BetaMie, sunSky->atm_BetaMie, *, sunSky->atm_BetaMieMultiplier);
00460     vec3opv(sunSky->atm_BetaRM, sunSky->atm_BetaRay, +, sunSky->atm_BetaMie);
00461     
00462     //e^(-(beta_1 + beta_2) * s) = E1
00463     vec3opf(E1, sunSky->atm_BetaRM, *, -s/(float)M_LN2);
00464     E1[0] = exp(E1[0]);
00465     E1[1] = exp(E1[1]);
00466     E1[2] = exp(E1[2]);
00467 
00468     copy_v3_v3(E, E1);
00469         
00470     //Phase2(theta) = (1-g^2)/(1+g-2g*cos(theta))^(3/2)
00471     fTemp = 1 + sunSky->atm_HGg - 2 * sunSky->atm_HGg * costheta;
00472     fTemp = fTemp * sqrtf(fTemp);
00473     Phase_2 = (1 - sunSky->atm_HGg * sunSky->atm_HGg)/fTemp;
00474     
00475     vec3opf(vTemp1, sunSky->atm_BetaDashRay, *, Phase_1);
00476     vec3opf(vTemp2, sunSky->atm_BetaDashMie, *, Phase_2);   
00477 
00478     vec3opv(vTemp1, vTemp1, +, vTemp2);
00479     fopvec3(vTemp2, 1.0f, -, E1);
00480     vec3opv(vTemp1, vTemp1, *, vTemp2);
00481 
00482     fopvec3(vTemp2, 1.0f, / , sunSky->atm_BetaRM);
00483 
00484     vec3opv(I, vTemp1, *, vTemp2);
00485         
00486     vec3opf(I, I, *, sunSky->atm_InscatteringMultiplier);
00487     vec3opf(E, E, *, sunSky->atm_ExtinctionMultiplier);
00488         
00489     //scale to color sun
00490     ComputeAttenuatedSunlight(sunSky->theta, sunSky->turbidity, sunColor);
00491     vec3opv(E, E, *, sunColor);
00492 
00493     vec3opf(I, I, *, sunSky->atm_SunIntensity);
00494 
00495     vec3opv(rgb, rgb, *, E);
00496     vec3opv(rgb, rgb, +, I);
00497 }
00498 
00499 #undef vec3opv
00500 #undef vec3opf
00501 #undef fopvec3
00502 
00503 /* EOF */