Blender  V2.59
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.0) c[0] = 1.0;
00072         if (c[0] < 0.0) c[0] = 0.0;
00073         if (c[1] > 1.0) c[1] = 1.0;
00074         if (c[1] < 0.0) c[1] = 0.0;
00075         if (c[2] > 1.0) c[2] = 1.0;
00076         if (c[2] < 0.0) c[2] = 0.0;
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.0)
00089                 return 0;
00090         if (cospsi < -1.0)
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] * exp(lam[1])) *
00121                    (1 + lam[2] * exp(lam[3] * sunsky->theta) + lam[4] * cos(sunsky->theta) * cos(sunsky->theta)));
00122         
00123         num = ((1 + lam[0] * exp(lam[1] / cos(theta))) *
00124                    (1 + lam[2] * exp(lam[3] * gamma) + lam[4] * cos(gamma) * cos(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.0 / 9.0 - T / 120.0) * (M_PI - 2 * sunsky->theta);
00177         sunsky->zenith_Y = (4.0453 * T - 4.9710) * tan(chi) - .2155 * T + 2.4192;
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.00165 * theta3 - 0.00374 * theta2 + 0.00208 * sunsky->theta + 0) * T2 +
00185                 ( -0.02902 * theta3 + 0.06377 * theta2 - 0.03202 * sunsky->theta + 0.00394) * T +
00186                 ( + 0.11693 * theta3 - 0.21196 * theta2 + 0.06052 * sunsky->theta + 0.25885);
00187 
00188         sunsky->zenith_y =
00189                 ( + 0.00275 * theta3 - 0.00610 * theta2 + 0.00316 * sunsky->theta + 0) * T2 +
00190                 ( -0.04214 * theta3 + 0.08970 * theta2 - 0.04153 * sunsky->theta + 0.00515) * T +
00191                 ( + 0.15346 * theta3 - 0.26756 * theta2 + 0.06669 * sunsky->theta + 0.26688);
00192 
00193         
00194         sunsky->perez_Y[0] = 0.17872 * T - 1.46303;
00195         sunsky->perez_Y[1] = -0.35540 * T + 0.42749;
00196         sunsky->perez_Y[2] = -0.02266 * T + 5.32505;
00197         sunsky->perez_Y[3] = 0.12064 * T - 2.57705;
00198         sunsky->perez_Y[4] = -0.06696 * T + 0.37027;
00199 
00200         sunsky->perez_x[0] = -0.01925 * T - 0.25922;
00201         sunsky->perez_x[1] = -0.06651 * T + 0.00081;
00202         sunsky->perez_x[2] = -0.00041 * T + 0.21247;
00203         sunsky->perez_x[3] = -0.06409 * T - 0.89887;
00204         sunsky->perez_x[4] = -0.00325 * T + 0.04517;
00205 
00206         sunsky->perez_y[0] = -0.01669 * T - 0.26078;
00207         sunsky->perez_y[1] = -0.09495 * T + 0.00921;
00208         sunsky->perez_y[2] = -0.00792 * T + 0.21023;
00209         sunsky->perez_y[3] = -0.04405 * T - 1.65369;
00210         sunsky->perez_y[4] = -0.01092 * T + 0.05291;
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.5*M_PI)) {
00252                 hfade = 1.0-(theta*M_1_PI-0.5)*2.0;
00253                 hfade = hfade*hfade*(3.0-2.0*hfade);
00254                 theta = 0.5*M_PI;
00255         }
00256 
00257         if (sunsky->theta>(0.5*M_PI)) {
00258                 if (theta<=0.5*M_PI) {
00259                         nfade = 1.0-(0.5-theta*M_1_PI)*2.0;
00260                         nfade *= 1.0-(sunsky->theta*M_1_PI-0.5)*2.0;
00261                         nfade = nfade*nfade*(3.0-2.0*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-5 * 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.001){
00300                 v[2] = 0.001;
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.0/(cos(theta) + 0.15f*pow(93.885f-theta/M_PI*180.0f,-1.253f));  
00333 
00334         for(i = 0; i < 3; i++)
00335         {
00336                 // Rayleigh Scattering
00337                 fTauR = exp( -m * 0.008735f * pow(fLambda[i], (float)(-4.08f)));
00338 
00339                 // Aerosal (water + dust) attenuation
00340                 fTauA = exp(-m * fBeta * pow(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.544*T - 6.51)*1e-17; 
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.434*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/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 * sqrt(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.0, -, E1);
00480         vec3opv(vTemp1, vTemp1, *, vTemp2);
00481 
00482         fopvec3(vTemp2, 1.0, / , 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 */