Blender  V2.59
pixelshading.c
Go to the documentation of this file.
00001 /*
00002  *
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version. 
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * Contributor(s): 2004-2006, Blender Foundation, full recode
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 #include <float.h>
00033 #include <math.h>
00034 #include <string.h>
00035 
00036 #include "BLI_math.h"
00037 #include "BLI_utildefines.h"
00038 
00039 /* External modules: */
00040 #include "IMB_imbuf_types.h"
00041 #include "IMB_imbuf.h"
00042 
00043 #include "DNA_camera_types.h"
00044 #include "DNA_group_types.h"
00045 #include "DNA_material_types.h"
00046 #include "DNA_object_types.h"
00047 #include "DNA_image_types.h"
00048 #include "DNA_texture_types.h"
00049 #include "DNA_lamp_types.h"
00050 
00051 #include "BKE_colortools.h"
00052 #include "BKE_image.h"
00053 #include "BKE_global.h"
00054 #include "BKE_material.h"
00055 #include "BKE_texture.h"
00056 
00057 
00058 /* own module */
00059 #include "render_types.h"
00060 #include "renderpipeline.h"
00061 #include "renderdatabase.h"
00062 #include "texture.h"
00063 #include "pixelblending.h"
00064 #include "rendercore.h"
00065 #include "shadbuf.h"
00066 #include "pixelshading.h"
00067 #include "shading.h"
00068 #include "sunsky.h"
00069 
00070 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00071 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
00072 /* only to be used here in this file, it's for speed */
00073 extern struct Render R;
00074 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00075 
00076 
00077 extern float hashvectf[];
00078 
00079 static void render_lighting_halo(HaloRen *har, float *colf)
00080 {
00081         GroupObject *go;
00082         LampRen *lar;
00083         float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
00084         float ir, ig, ib, shadfac, soft, lacol[3];
00085         
00086         ir= ig= ib= 0.0;
00087         
00088         VECCOPY(rco, har->co);  
00089         dco[0]=dco[1]=dco[2]= 1.0/har->rad;
00090         
00091         vn= har->no;
00092         
00093         for(go=R.lights.first; go; go= go->next) {
00094                 lar= go->lampren;
00095                 
00096                 /* test for lamplayer */
00097                 if(lar->mode & LA_LAYER) if((lar->lay & har->lay)==0) continue;
00098                 
00099                 /* lampdist cacluation */
00100                 if(lar->type==LA_SUN || lar->type==LA_HEMI) {
00101                         VECCOPY(lv, lar->vec);
00102                         lampdist= 1.0;
00103                 }
00104                 else {
00105                         lv[0]= rco[0]-lar->co[0];
00106                         lv[1]= rco[1]-lar->co[1];
00107                         lv[2]= rco[2]-lar->co[2];
00108                         ld= sqrt(lv[0]*lv[0]+lv[1]*lv[1]+lv[2]*lv[2]);
00109                         lv[0]/= ld;
00110                         lv[1]/= ld;
00111                         lv[2]/= ld;
00112                         
00113                         /* ld is re-used further on (texco's) */
00114                         
00115                         if(lar->mode & LA_QUAD) {
00116                                 t= 1.0;
00117                                 if(lar->ld1>0.0)
00118                                         t= lar->dist/(lar->dist+lar->ld1*ld);
00119                                 if(lar->ld2>0.0)
00120                                         t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
00121                                 
00122                                 lampdist= t;
00123                         }
00124                         else {
00125                                 lampdist= (lar->dist/(lar->dist+ld));
00126                         }
00127                         
00128                         if(lar->mode & LA_SPHERE) {
00129                                 t= lar->dist - ld;
00130                                 if(t<0.0) continue;
00131                                 
00132                                 t/= lar->dist;
00133                                 lampdist*= (t);
00134                         }
00135                         
00136                 }
00137                 
00138                 lacol[0]= lar->r;
00139                 lacol[1]= lar->g;
00140                 lacol[2]= lar->b;
00141                 
00142                 if(lar->mode & LA_TEXTURE) {
00143                         ShadeInput shi;
00144                         
00145                         /* Warning, This is not that nice, and possibly a bit slow,
00146                         however some variables were not initialized properly in, unless using shade_input_initialize(...), we need to do a memset */
00147                         memset(&shi, 0, sizeof(ShadeInput)); 
00148                         /* end warning! - Campbell */
00149                         
00150                         VECCOPY(shi.co, rco);
00151                         shi.osatex= 0;
00152                         do_lamp_tex(lar, lv, &shi, lacol, LA_TEXTURE);
00153                 }
00154                 
00155                 if(lar->type==LA_SPOT) {
00156                         
00157                         if(lar->mode & LA_SQUARE) {
00158                                 if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0) {
00159                                         float x, lvrot[3];
00160                                         
00161                                         /* rotate view to lampspace */
00162                                         VECCOPY(lvrot, lv);
00163                                         mul_m3_v3(lar->imat, lvrot);
00164                                         
00165                                         x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
00166                                         /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
00167                                         
00168                                         inpr= 1.0/(sqrt(1.0+x*x));
00169                                 }
00170                                 else inpr= 0.0;
00171                         }
00172                         else {
00173                                 inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
00174                         }
00175                         
00176                         t= lar->spotsi;
00177                         if(inpr<t) continue;
00178                         else {
00179                                 t= inpr-t;
00180                                 i= 1.0;
00181                                 soft= 1.0;
00182                                 if(t<lar->spotbl && lar->spotbl!=0.0) {
00183                                         /* soft area */
00184                                         i= t/lar->spotbl;
00185                                         t= i*i;
00186                                         soft= (3.0*t-2.0*t*i);
00187                                         inpr*= soft;
00188                                 }
00189                                 if(lar->mode & LA_ONLYSHADOW) {
00190                                         /* if(ma->mode & MA_SHADOW) { */
00191                                         /* dot product positive: front side face! */
00192                                         inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
00193                                         if(inp>0.0) {
00194                                                 /* testshadowbuf==0.0 : 100% shadow */
00195                                                 shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
00196                                                 if( shadfac>0.0 ) {
00197                                                         shadfac*= inp*soft*lar->energy;
00198                                                         ir -= shadfac;
00199                                                         ig -= shadfac;
00200                                                         ib -= shadfac;
00201                                                         
00202                                                         continue;
00203                                                 }
00204                                         }
00205                                         /* } */
00206                                 }
00207                                 lampdist*=inpr;
00208                         }
00209                         if(lar->mode & LA_ONLYSHADOW) continue;
00210                         
00211                 }
00212                 
00213                 /* dot product and  reflectivity*/
00214                 
00215                 inp= 1.0-fabs(vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]);
00216                 
00217                 /* inp= cos(0.5*M_PI-acos(inp)); */
00218                 
00219                 i= inp;
00220                 
00221                 if(lar->type==LA_HEMI) {
00222                         i= 0.5*i+0.5;
00223                 }
00224                 if(i>0.0) {
00225                         i*= lampdist;
00226                 }
00227                 
00228                 /* shadow  */
00229                 if(i> -0.41) {                  /* heuristic valua! */
00230                         shadfac= 1.0;
00231                         if(lar->shb) {
00232                                 shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
00233                                 if(shadfac==0.0) continue;
00234                                 i*= shadfac;
00235                         }
00236                 }
00237                 
00238                 if(i>0.0) {
00239                         ir+= i*lacol[0];
00240                         ig+= i*lacol[1];
00241                         ib+= i*lacol[2];
00242                 }
00243         }
00244         
00245         if(ir<0.0) ir= 0.0;
00246         if(ig<0.0) ig= 0.0;
00247         if(ib<0.0) ib= 0.0;
00248 
00249         colf[0]*= ir;
00250         colf[1]*= ig;
00251         colf[2]*= ib;
00252         
00253 }
00254 
00255 
00261 static float haloZtoDist(int z)
00262 {
00263         float zco = 0;
00264 
00265         if(z >= 0x7FFFFF)
00266                 return 10e10;
00267         else {
00268                 zco = (float)z/(float)0x7FFFFF;
00269                 if(R.r.mode & R_ORTHO)
00270                         return (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
00271                 else
00272                         return (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
00273         }
00274 }
00275 
00285 int shadeHaloFloat(HaloRen *har,  float *col, int zz, 
00286                                         float dist, float xn,  float yn, short flarec)
00287 {
00288         /* fill in col */
00289         float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co;
00290         int a;
00291    
00292         if(R.wrld.mode & WO_MIST) {
00293                 if(har->type & HA_ONLYSKY) {
00294                         /* stars but no mist */
00295                         alpha= har->alfa;
00296                 }
00297                 else {
00298                         /* a bit patchy... */
00299                         alpha= mistfactor(-har->co[2], har->co)*har->alfa;
00300                 }
00301         }
00302         else alpha= har->alfa;
00303         
00304         if(alpha==0.0)
00305                 return 0;
00306 
00307         /* soften the halo if it intersects geometry */
00308         if(har->mat && har->mat->mode & MA_HALO_SOFT) {
00309                 float segment_length, halo_depth, distance_from_z, visible_depth, soften;
00310                 
00311                 /* calculate halo depth */
00312                 segment_length= har->hasize*sasqrt(1.0f - dist/(har->rad*har->rad));
00313                 halo_depth= 2.0f*segment_length;
00314 
00315                 if(halo_depth < FLT_EPSILON)
00316                         return 0;
00317 
00318                 /* calculate how much of this depth is visible */
00319                 distance_from_z = haloZtoDist(zz) - haloZtoDist(har->zs);
00320                 visible_depth = halo_depth;
00321                 if(distance_from_z < segment_length) {
00322                         soften= (segment_length + distance_from_z)/halo_depth;
00323 
00324                         /* apply softening to alpha */
00325                         if(soften < 1.0f)
00326                                 alpha *= soften;
00327                         if(alpha <= 0.0f)
00328                                 return 0;
00329                 }
00330         }
00331         else {
00332                 /* not a soft halo. use the old softening code */
00333                 /* halo being intersected? */
00334                 if(har->zs> zz-har->zd) {
00335                         t= ((float)(zz-har->zs))/(float)har->zd;
00336                         alpha*= sqrt(sqrt(t));
00337                 }
00338         }
00339 
00340         radist= sqrt(dist);
00341 
00342         /* watch it: not used nicely: flarec is set at zero in pixstruct */
00343         if(flarec) har->pixels+= (int)(har->rad-radist);
00344 
00345         if(har->ringc) {
00346                 float *rc, fac;
00347                 int ofs;
00348                 
00349                 /* per ring an antialised circle */
00350                 ofs= har->seed;
00351                 
00352                 for(a= har->ringc; a>0; a--, ofs+=2) {
00353                         
00354                         rc= hashvectf + (ofs % 768);
00355                         
00356                         fac= fabs( rc[1]*(har->rad*fabs(rc[0]) - radist) );
00357                         
00358                         if(fac< 1.0) {
00359                                 ringf+= (1.0-fac);
00360                         }
00361                 }
00362         }
00363 
00364         if(har->type & HA_VECT) {
00365                 dist= fabs( har->cos*(yn) - har->sin*(xn) )/har->rad;
00366                 if(dist>1.0) dist= 1.0;
00367                 if(har->tex) {
00368                         zn= har->sin*xn - har->cos*yn;
00369                         yn= har->cos*xn + har->sin*yn;
00370                         xn= zn;
00371                 }
00372         }
00373         else dist= dist/har->radsq;
00374 
00375         if(har->type & HA_FLARECIRC) {
00376                 
00377                 dist= 0.5+fabs(dist-0.5);
00378                 
00379         }
00380 
00381         if(har->hard>=30) {
00382                 dist= sqrt(dist);
00383                 if(har->hard>=40) {
00384                         dist= sin(dist*M_PI_2);
00385                         if(har->hard>=50) {
00386                                 dist= sqrt(dist);
00387                         }
00388                 }
00389         }
00390         else if(har->hard<20) dist*=dist;
00391 
00392         if(dist < 1.0f)
00393                 dist= (1.0f-dist);
00394         else
00395                 dist= 0.0f;
00396         
00397         if(har->linec) {
00398                 float *rc, fac;
00399                 int ofs;
00400                 
00401                 /* per starpoint an antialiased line */
00402                 ofs= har->seed;
00403                 
00404                 for(a= har->linec; a>0; a--, ofs+=3) {
00405                         
00406                         rc= hashvectf + (ofs % 768);
00407                         
00408                         fac= fabs( (xn)*rc[0]+(yn)*rc[1]);
00409                         
00410                         if(fac< 1.0f )
00411                                 linef+= (1.0f-fac);
00412                 }
00413                 
00414                 linef*= dist;
00415         }
00416 
00417         if(har->starpoints) {
00418                 float ster, angle;
00419                 /* rotation */
00420                 angle= atan2(yn, xn);
00421                 angle*= (1.0+0.25*har->starpoints);
00422                 
00423                 co= cos(angle);
00424                 si= sin(angle);
00425                 
00426                 angle= (co*xn+si*yn)*(co*yn-si*xn);
00427                 
00428                 ster= fabs(angle);
00429                 if(ster>1.0) {
00430                         ster= (har->rad)/(ster);
00431                         
00432                         if(ster<1.0) dist*= sqrt(ster);
00433                 }
00434         }
00435 
00436         /* disputable optimize... (ton) */
00437         if(dist<=0.00001)
00438                 return 0;
00439         
00440         dist*= alpha;
00441         ringf*= dist;
00442         linef*= alpha;
00443         
00444         /* The color is either the rgb spec-ed by the user, or extracted from   */
00445         /* the texture                                                           */
00446         if(har->tex) {
00447                 col[0]= har->r; 
00448                 col[1]= har->g; 
00449                 col[2]= har->b;
00450                 col[3]= dist;
00451                 
00452                 do_halo_tex(har, xn, yn, col);
00453                 
00454                 col[0]*= col[3];
00455                 col[1]*= col[3];
00456                 col[2]*= col[3];
00457                 
00458         }
00459         else {
00460                 col[0]= dist*har->r;
00461                 col[1]= dist*har->g;
00462                 col[2]= dist*har->b;
00463                 if(har->type & HA_XALPHA) col[3]= dist*dist;
00464                 else col[3]= dist;
00465         }
00466 
00467         if(har->mat) {
00468                 if(har->mat->mode & MA_HALO_SHADE) {
00469                         /* we test for lights because of preview... */
00470                         if(R.lights.first) render_lighting_halo(har, col);
00471                 }
00472 
00473                 /* Next, we do the line and ring factor modifications. */
00474                 if(linef!=0.0) {
00475                         Material *ma= har->mat;
00476                         
00477                         col[0]+= linef * ma->specr;
00478                         col[1]+= linef * ma->specg;
00479                         col[2]+= linef * ma->specb;
00480                         
00481                         if(har->type & HA_XALPHA) col[3]+= linef*linef;
00482                         else col[3]+= linef;
00483                 }
00484                 if(ringf!=0.0) {
00485                         Material *ma= har->mat;
00486 
00487                         col[0]+= ringf * ma->mirr;
00488                         col[1]+= ringf * ma->mirg;
00489                         col[2]+= ringf * ma->mirb;
00490                         
00491                         if(har->type & HA_XALPHA) col[3]+= ringf*ringf;
00492                         else col[3]+= ringf;
00493                 }
00494         }
00495         
00496         /* alpha requires clip, gives black dots */
00497         if(col[3] > 1.0f)
00498                 col[3]= 1.0f;
00499 
00500         return 1;
00501 }
00502 
00503 /* ------------------------------------------------------------------------- */
00504 
00505 /* Only view vector is important here. Result goes to colf[3] */
00506 void shadeSkyView(float *colf, float *rco, float *view, float *dxyview, short thread)
00507 {
00508         float lo[3], zen[3], hor[3], blend, blendm;
00509         int skyflag;
00510         
00511         /* flag indicating if we render the top hemisphere */
00512         skyflag = WO_ZENUP;
00513         
00514         /* Some view vector stuff. */
00515         if(R.wrld.skytype & WO_SKYREAL) {
00516                 
00517                 blend= view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2];
00518                 
00519                 if(blend<0.0) skyflag= 0;
00520                 
00521                 blend= fabs(blend);
00522         }
00523         else if(R.wrld.skytype & WO_SKYPAPER) {
00524                 blend= 0.5+ 0.5*view[1];
00525         }
00526         else {
00527                 /* the fraction of how far we are above the bottom of the screen */
00528                 blend= fabs(0.5+ view[1]);
00529         }
00530 
00531         VECCOPY(hor, &R.wrld.horr);
00532         VECCOPY(zen, &R.wrld.zenr);
00533 
00534         /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If           */
00535         /* SKYBLEND is active, the texture and color blend are added.           */
00536         if(R.wrld.skytype & WO_SKYTEX) {
00537                 VECCOPY(lo, view);
00538                 if(R.wrld.skytype & WO_SKYREAL) {
00539                         
00540                         mul_m3_v3(R.imat, lo);
00541                         
00542                         SWAP(float, lo[1],  lo[2]);
00543                         
00544                 }
00545                 do_sky_tex(rco, lo, dxyview, hor, zen, &blend, skyflag, thread);
00546         }
00547         
00548         if(blend>1.0) blend= 1.0;
00549         blendm= 1.0-blend;
00550         
00551         /* No clipping, no conversion! */
00552         if(R.wrld.skytype & WO_SKYBLEND) {
00553                 colf[0] = (blendm*hor[0] + blend*zen[0]);
00554                 colf[1] = (blendm*hor[1] + blend*zen[1]);
00555                 colf[2] = (blendm*hor[2] + blend*zen[2]);
00556         } else {
00557                 /* Done when a texture was grabbed. */
00558                 colf[0]= hor[0];
00559                 colf[1]= hor[1];
00560                 colf[2]= hor[2];
00561         }
00562 }
00563 
00564 /* shade sky according to sun lamps, all parameters are like shadeSkyView except sunsky*/
00565 void shadeSunView(float *colf, float *view)
00566 {
00567         GroupObject *go;
00568         LampRen *lar;
00569         float sview[3];
00570         int do_init= 1;
00571         
00572         for(go=R.lights.first; go; go= go->next) {
00573                 lar= go->lampren;
00574                 if(lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_SKY)){
00575                         float sun_collector[3];
00576                         float colorxyz[3];
00577                         
00578                         if(do_init) {
00579                                 
00580                                 VECCOPY(sview, view);
00581                                 normalize_v3(sview);
00582                                 mul_m3_v3(R.imat, sview);
00583                                 if (sview[2] < 0.0)
00584                                         sview[2] = 0.0;
00585                                 normalize_v3(sview);
00586                                 do_init= 0;
00587                         }
00588                         
00589                         GetSkyXYZRadiancef(lar->sunsky, sview, colorxyz);
00590                         xyz_to_rgb(colorxyz[0], colorxyz[1], colorxyz[2], &sun_collector[0], &sun_collector[1], &sun_collector[2], 
00591                                            lar->sunsky->sky_colorspace);
00592                         
00593                         ramp_blend(lar->sunsky->skyblendtype, colf, colf+1, colf+2, lar->sunsky->skyblendfac, sun_collector);
00594                 }
00595         }
00596 }
00597 
00598 
00599 /*
00600   Stuff the sky color into the collector.
00601  */
00602 void shadeSkyPixel(float *collector, float fx, float fy, short thread) 
00603 {
00604         float view[3], dxyview[2];
00605 
00606         /*
00607           The rules for sky:
00608           1. Draw an image, if a background image was provided. Stop
00609           2. get texture and color blend, and combine these.
00610         */
00611 
00612         float fac;
00613 
00614         if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
00615                 /* 1. solid color */
00616                 VECCOPY(collector, &R.wrld.horr);
00617 
00618                 collector[3] = 0.0f;
00619         } 
00620         else {
00621                 /* 2. */
00622 
00623                 /* This one true because of the context of this routine  */
00624                 if(R.wrld.skytype & WO_SKYPAPER) {
00625                         view[0]= -1.0f + 2.0f*(fx/(float)R.winx);
00626                         view[1]= -1.0f + 2.0f*(fy/(float)R.winy);
00627                         view[2]= 0.0;
00628                         
00629                         dxyview[0]= 1.0f/(float)R.winx;
00630                         dxyview[1]= 1.0f/(float)R.winy;
00631                 }
00632                 else {
00633                         calc_view_vector(view, fx, fy);
00634                         fac= normalize_v3(view);
00635                         
00636                         if(R.wrld.skytype & WO_SKYTEX) {
00637                                 dxyview[0]= -R.viewdx/fac;
00638                                 dxyview[1]= -R.viewdy/fac;
00639                         }
00640                 }
00641                 
00642                 /* get sky color in the collector */
00643                 shadeSkyView(collector, NULL, view, dxyview, thread);
00644                 collector[3] = 0.0f;
00645         }
00646         
00647         calc_view_vector(view, fx, fy);
00648         shadeSunView(collector, view);
00649 }
00650 
00651 /* aerial perspective */
00652 void shadeAtmPixel(struct SunSky *sunsky, float *collector, float fx, float fy, float distance)
00653 {
00654         float view[3];
00655                 
00656         calc_view_vector(view, fx, fy);
00657         normalize_v3(view);
00658         /*mul_m3_v3(R.imat, view);*/
00659         AtmospherePixleShader(sunsky, view, distance, collector);
00660 }
00661 
00662 /* eof */