2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): 2004-2006, Blender Foundation, full recode
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/render/intern/source/pixelshading.c
36 #include "BLI_utildefines.h"
38 /* External modules: */
39 #include "IMB_imbuf_types.h"
40 #include "IMB_imbuf.h"
42 #include "DNA_camera_types.h"
43 #include "DNA_group_types.h"
44 #include "DNA_material_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_image_types.h"
47 #include "DNA_texture_types.h"
48 #include "DNA_lamp_types.h"
50 #include "BKE_colortools.h"
51 #include "BKE_image.h"
52 #include "BKE_global.h"
53 #include "BKE_material.h"
54 #include "BKE_texture.h"
58 #include "render_types.h"
59 #include "renderpipeline.h"
60 #include "renderdatabase.h"
62 #include "pixelblending.h"
63 #include "rendercore.h"
65 #include "pixelshading.h"
69 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
70 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
71 /* only to be used here in this file, it's for speed */
72 extern struct Render R;
73 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
76 extern float hashvectf[];
78 static void render_lighting_halo(HaloRen *har, float col_r[3])
82 float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
83 float ir, ig, ib, shadfac, soft, lacol[3];
87 copy_v3_v3(rco, har->co);
88 dco[0]=dco[1]=dco[2]= 1.0f/har->rad;
92 for (go=R.lights.first; go; go= go->next) {
95 /* test for lamplayer */
96 if (lar->mode & LA_LAYER) if ((lar->lay & har->lay)==0) continue;
98 /* lampdist cacluation */
99 if (lar->type==LA_SUN || lar->type==LA_HEMI) {
100 copy_v3_v3(lv, lar->vec);
104 lv[0]= rco[0]-lar->co[0];
105 lv[1]= rco[1]-lar->co[1];
106 lv[2]= rco[2]-lar->co[2];
112 /* ld is re-used further on (texco's) */
114 if (lar->mode & LA_QUAD) {
117 t= lar->dist/(lar->dist+lar->ld1*ld);
119 t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
124 lampdist= (lar->dist/(lar->dist+ld));
127 if (lar->mode & LA_SPHERE) {
129 if (t<0.0f) continue;
141 if (lar->mode & LA_TEXTURE) {
144 /* Warning, This is not that nice, and possibly a bit slow,
145 * however some variables were not initialized properly in, unless using shade_input_initialize(...),
146 * we need to do a memset */
147 memset(&shi, 0, sizeof(ShadeInput));
148 /* end warning! - Campbell */
150 copy_v3_v3(shi.co, rco);
152 do_lamp_tex(lar, lv, &shi, lacol, LA_TEXTURE);
155 if (lar->type==LA_SPOT) {
157 if (lar->mode & LA_SQUARE) {
158 if (lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0f) {
161 /* rotate view to lampspace */
162 copy_v3_v3(lvrot, lv);
163 mul_m3_v3(lar->imat, lvrot);
165 x = maxf(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
166 /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
168 inpr= 1.0/(sqrt(1.0f+x*x));
173 inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
177 if (inpr<t) continue;
181 if (t<lar->spotbl && lar->spotbl!=0.0f) {
185 soft= (3.0f*t-2.0f*t*i);
188 if (lar->mode & LA_ONLYSHADOW) {
189 /* if (ma->mode & MA_SHADOW) { */
190 /* dot product positive: front side face! */
191 inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
193 /* testshadowbuf==0.0 : 100% shadow */
194 shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
195 if ( shadfac>0.0f ) {
196 shadfac*= inp*soft*lar->energy;
208 if (lar->mode & LA_ONLYSHADOW) continue;
212 /* dot product and reflectivity*/
214 inp = 1.0 - fabs(dot_v3v3(vn, lv));
216 /* inp= cos(0.5*M_PI-acos(inp)); */
220 if (lar->type==LA_HEMI) {
228 if (i> -0.41f) { /* heuristic valua! */
230 shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
231 if (shadfac==0.0f) continue;
243 if (ir<0.0f) ir= 0.0f;
244 if (ig<0.0f) ig= 0.0f;
245 if (ib<0.0f) ib= 0.0f;
255 * Converts a halo z-buffer value to distance from the camera's near plane
256 * \param z The z-buffer value to convert
257 * \return a distance from the camera's near plane in blender units
259 static float haloZtoDist(int z)
266 zco = (float)z/(float)0x7FFFFF;
267 if (R.r.mode & R_ORTHO)
268 return (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
270 return (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
275 * \param col (float[4]) Store the rgb color here (with alpha)
276 * The alpha is used to blend the color to the background
277 * color_new = (1-alpha)*color_background + color
278 * \param zz The current zbuffer value at the place of this pixel
279 * \param dist Distance of the pixel from the center of the halo squared. Given in pixels
280 * \param xn The x coordinate of the pixel relaticve to the center of the halo. given in pixels
281 * \param yn The y coordinate of the pixel relaticve to the center of the halo. given in pixels
283 int shadeHaloFloat(HaloRen *har, float *col, int zz,
284 float dist, float xn, float yn, short flarec)
287 float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co;
290 if (R.wrld.mode & WO_MIST) {
291 if (har->type & HA_ONLYSKY) {
292 /* stars but no mist */
296 /* a bit patchy... */
297 alpha= mistfactor(-har->co[2], har->co)*har->alfa;
300 else alpha= har->alfa;
305 /* soften the halo if it intersects geometry */
306 if (har->mat && har->mat->mode & MA_HALO_SOFT) {
307 float segment_length, halo_depth, distance_from_z /* , visible_depth */ /* UNUSED */, soften;
309 /* calculate halo depth */
310 segment_length= har->hasize*sasqrt(1.0f - dist/(har->rad*har->rad));
311 halo_depth= 2.0f*segment_length;
313 if (halo_depth < FLT_EPSILON)
316 /* calculate how much of this depth is visible */
317 distance_from_z = haloZtoDist(zz) - haloZtoDist(har->zs);
318 /* visible_depth = halo_depth; */ /* UNUSED */
319 if (distance_from_z < segment_length) {
320 soften= (segment_length + distance_from_z)/halo_depth;
322 /* apply softening to alpha */
330 /* not a soft halo. use the old softening code */
331 /* halo being intersected? */
332 if (har->zs> zz-har->zd) {
333 t= ((float)(zz-har->zs))/(float)har->zd;
334 alpha*= sqrtf(sqrtf(t));
340 /* watch it: not used nicely: flarec is set at zero in pixstruct */
341 if (flarec) har->pixels+= (int)(har->rad-radist);
347 /* per ring an antialised circle */
350 for (a= har->ringc; a>0; a--, ofs+=2) {
352 rc= hashvectf + (ofs % 768);
354 fac= fabsf( rc[1]*(har->rad*fabsf(rc[0]) - radist) );
362 if (har->type & HA_VECT) {
363 dist= fabsf( har->cos*(yn) - har->sin*(xn) )/har->rad;
364 if (dist>1.0f) dist= 1.0f;
366 zn= har->sin*xn - har->cos*yn;
367 yn= har->cos*xn + har->sin*yn;
371 else dist= dist/har->radsq;
373 if (har->type & HA_FLARECIRC) {
375 dist= 0.5+fabs(dist-0.5f);
382 dist= sinf(dist*(float)M_PI_2);
388 else if (har->hard<20) dist*=dist;
399 /* per starpoint an antialiased line */
402 for (a= har->linec; a>0; a--, ofs+=3) {
404 rc= hashvectf + (ofs % 768);
406 fac= fabs( (xn)*rc[0]+(yn)*rc[1]);
415 if (har->starpoints) {
418 angle= atan2(yn, xn);
419 angle*= (1.0f+0.25f*har->starpoints);
424 angle= (co*xn+si*yn)*(co*yn-si*xn);
428 ster= (har->rad)/(ster);
430 if (ster<1.0f) dist*= sqrtf(ster);
434 /* disputable optimize... (ton) */
442 /* The color is either the rgb spec-ed by the user, or extracted from */
450 do_halo_tex(har, xn, yn, col);
461 if (har->type & HA_XALPHA) col[3]= dist*dist;
466 if (har->mat->mode & MA_HALO_SHADE) {
467 /* we test for lights because of preview... */
468 if (R.lights.first) render_lighting_halo(har, col);
471 /* Next, we do the line and ring factor modifications. */
473 Material *ma= har->mat;
475 col[0]+= linef * ma->specr;
476 col[1]+= linef * ma->specg;
477 col[2]+= linef * ma->specb;
479 if (har->type & HA_XALPHA) col[3]+= linef*linef;
483 Material *ma= har->mat;
485 col[0]+= ringf * ma->mirr;
486 col[1]+= ringf * ma->mirg;
487 col[2]+= ringf * ma->mirb;
489 if (har->type & HA_XALPHA) col[3]+= ringf*ringf;
494 /* alpha requires clip, gives black dots */
501 /* ------------------------------------------------------------------------- */
503 /* Only view vector is important here. Result goes to col_r[3] */
504 void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread)
506 float lo[3], zen[3], hor[3], blend, blendm;
509 /* flag indicating if we render the top hemisphere */
512 /* Some view vector stuff. */
513 if (R.wrld.skytype & WO_SKYREAL) {
515 blend = dot_v3v3(view, R.grvec);
517 if (blend<0.0f) skyflag= 0;
521 else if (R.wrld.skytype & WO_SKYPAPER) {
522 blend= 0.5f + 0.5f * view[1];
525 /* the fraction of how far we are above the bottom of the screen */
526 blend= fabs(0.5f + view[1]);
529 copy_v3_v3(hor, &R.wrld.horr);
530 copy_v3_v3(zen, &R.wrld.zenr);
532 /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
533 /* SKYBLEND is active, the texture and color blend are added. */
534 if (R.wrld.skytype & WO_SKYTEX) {
535 copy_v3_v3(lo, view);
536 if (R.wrld.skytype & WO_SKYREAL) {
538 mul_m3_v3(R.imat, lo);
540 SWAP(float, lo[1], lo[2]);
543 do_sky_tex(rco, lo, dxyview, hor, zen, &blend, skyflag, thread);
546 if (blend>1.0f) blend= 1.0f;
549 /* No clipping, no conversion! */
550 if (R.wrld.skytype & WO_SKYBLEND) {
551 col_r[0] = (blendm*hor[0] + blend*zen[0]);
552 col_r[1] = (blendm*hor[1] + blend*zen[1]);
553 col_r[2] = (blendm*hor[2] + blend*zen[2]);
556 /* Done when a texture was grabbed. */
563 /* shade sky according to sun lamps, all parameters are like shadeSkyView except sunsky*/
564 void shadeSunView(float col_r[3], const float view[3])
571 for (go=R.lights.first; go; go= go->next) {
573 if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_SKY)) {
574 float sun_collector[3];
579 normalize_v3_v3(sview, view);
580 mul_m3_v3(R.imat, sview);
587 GetSkyXYZRadiancef(lar->sunsky, sview, colorxyz);
588 xyz_to_rgb(colorxyz[0], colorxyz[1], colorxyz[2], &sun_collector[0], &sun_collector[1], &sun_collector[2],
589 lar->sunsky->sky_colorspace);
591 ramp_blend(lar->sunsky->skyblendtype, col_r, lar->sunsky->skyblendfac, sun_collector);
598 * Stuff the sky color into the collector.
600 void shadeSkyPixel(float collector[4], float fx, float fy, short thread)
602 float view[3], dxyview[2];
606 * 1. Draw an image, if a background image was provided. Stop
607 * 2. get texture and color blend, and combine these.
612 if ((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
614 copy_v3_v3(collector, &R.wrld.horr);
621 /* This one true because of the context of this routine */
622 if (R.wrld.skytype & WO_SKYPAPER) {
623 view[0]= -1.0f + 2.0f*(fx/(float)R.winx);
624 view[1]= -1.0f + 2.0f*(fy/(float)R.winy);
627 dxyview[0]= 1.0f/(float)R.winx;
628 dxyview[1]= 1.0f/(float)R.winy;
631 calc_view_vector(view, fx, fy);
632 fac= normalize_v3(view);
634 if (R.wrld.skytype & WO_SKYTEX) {
635 dxyview[0]= -R.viewdx/fac;
636 dxyview[1]= -R.viewdy/fac;
640 /* get sky color in the collector */
641 shadeSkyView(collector, NULL, view, dxyview, thread);
645 calc_view_vector(view, fx, fy);
646 shadeSunView(collector, view);
649 /* aerial perspective */
650 void shadeAtmPixel(struct SunSky *sunsky, float collector[3], float fx, float fy, float distance)
654 calc_view_vector(view, fx, fy);
656 /*mul_m3_v3(R.imat, view);*/
657 AtmospherePixleShader(sunsky, view, distance, collector);