3 * ***** BEGIN GPL LICENSE BLOCK *****
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20 * All rights reserved.
22 * Contributor(s): 2004-2006, Blender Foundation, full recode
24 * ***** END GPL LICENSE BLOCK *****
29 #include "BLI_arithb.h"
31 /* External modules: */
32 #include "IMB_imbuf_types.h"
33 #include "IMB_imbuf.h"
34 #include "MTC_matrixops.h"
35 #include "MTC_vectorops.h"
37 #include "DNA_camera_types.h"
38 #include "DNA_group_types.h"
39 #include "DNA_material_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_image_types.h"
42 #include "DNA_texture_types.h"
43 #include "DNA_lamp_types.h"
45 #include "BKE_image.h"
46 #include "BKE_global.h"
47 #include "BKE_texture.h"
48 #include "BKE_utildefines.h"
51 #include "render_types.h"
52 #include "renderpipeline.h"
53 #include "renderdatabase.h"
55 #include "pixelblending.h"
56 #include "rendercore.h"
58 #include "pixelshading.h"
60 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
61 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
62 /* only to be used here in this file, it's for speed */
63 extern struct Render R
;
64 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
67 extern float hashvectf
[];
69 static void render_lighting_halo(HaloRen
*har
, float *colf
)
73 float i
, inp
, inpr
, rco
[3], dco
[3], lv
[3], lampdist
, ld
, t
, *vn
;
74 float ir
, ig
, ib
, shadfac
, soft
, lacol
[3];
78 VECCOPY(rco
, har
->co
);
79 dco
[0]=dco
[1]=dco
[2]= 1.0/har
->rad
;
83 for(go
=R
.lights
.first
; go
; go
= go
->next
) {
86 /* test for lamplayer */
87 if(lar
->mode
& LA_LAYER
) if((lar
->lay
& har
->lay
)==0) continue;
89 /* lampdist cacluation */
90 if(lar
->type
==LA_SUN
|| lar
->type
==LA_HEMI
) {
91 VECCOPY(lv
, lar
->vec
);
95 lv
[0]= rco
[0]-lar
->co
[0];
96 lv
[1]= rco
[1]-lar
->co
[1];
97 lv
[2]= rco
[2]-lar
->co
[2];
98 ld
= sqrt(lv
[0]*lv
[0]+lv
[1]*lv
[1]+lv
[2]*lv
[2]);
103 /* ld is re-used further on (texco's) */
105 if(lar
->mode
& LA_QUAD
) {
108 t
= lar
->dist
/(lar
->dist
+lar
->ld1
*ld
);
110 t
*= lar
->distkw
/(lar
->distkw
+lar
->ld2
*ld
*ld
);
115 lampdist
= (lar
->dist
/(lar
->dist
+ld
));
118 if(lar
->mode
& LA_SPHERE
) {
132 if(lar
->mode
& LA_TEXTURE
) {
134 VECCOPY(shi
.co
, rco
);
136 do_lamp_tex(lar
, lv
, &shi
, lacol
);
139 if(lar
->type
==LA_SPOT
) {
141 if(lar
->mode
& LA_SQUARE
) {
142 if(lv
[0]*lar
->vec
[0]+lv
[1]*lar
->vec
[1]+lv
[2]*lar
->vec
[2]>0.0) {
145 /* rotate view to lampspace */
147 MTC_Mat3MulVecfl(lar
->imat
, lvrot
);
149 x
= MAX2(fabs(lvrot
[0]/lvrot
[2]) , fabs(lvrot
[1]/lvrot
[2]));
150 /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
152 inpr
= 1.0/(sqrt(1.0+x
*x
));
157 inpr
= lv
[0]*lar
->vec
[0]+lv
[1]*lar
->vec
[1]+lv
[2]*lar
->vec
[2];
166 if(t
<lar
->spotbl
&& lar
->spotbl
!=0.0) {
170 soft
= (3.0*t
-2.0*t
*i
);
173 if(lar
->mode
& LA_ONLYSHADOW
) {
174 /* if(ma->mode & MA_SHADOW) { */
175 /* dot product positive: front side face! */
176 inp
= vn
[0]*lv
[0] + vn
[1]*lv
[1] + vn
[2]*lv
[2];
178 /* testshadowbuf==0.0 : 100% shadow */
179 shadfac
= testshadowbuf(lar
->shb
, rco
, dco
, dco
, inp
);
181 shadfac
*= inp
*soft
*lar
->energy
;
193 if(lar
->mode
& LA_ONLYSHADOW
) continue;
197 /* dot product and reflectivity*/
199 inp
= 1.0-fabs(vn
[0]*lv
[0] + vn
[1]*lv
[1] + vn
[2]*lv
[2]);
201 /* inp= cos(0.5*M_PI-acos(inp)); */
205 if(lar
->type
==LA_HEMI
) {
213 if(i
> -0.41) { /* heuristic valua! */
216 shadfac
= testshadowbuf(lar
->shb
, rco
, dco
, dco
, inp
);
217 if(shadfac
==0.0) continue;
241 * Converts a halo z-buffer value to distance from the camera's near plane
242 * @param z The z-buffer value to convert
243 * @return a distance from the camera's near plane in blender units
245 static float haloZtoDist(int z
)
252 zco
= (float)z
/(float)0x7FFFFF;
253 if(R
.r
.mode
& R_ORTHO
)
254 return (R
.winmat
[3][2] - zco
*R
.winmat
[3][3])/(R
.winmat
[2][2]);
256 return (R
.winmat
[3][2])/(R
.winmat
[2][2] - R
.winmat
[2][3]*zco
);
261 * @param col (float[4]) Store the rgb color here (with alpha)
262 * The alpha is used to blend the color to the background
263 * color_new = (1-alpha)*color_background + color
264 * @param zz The current zbuffer value at the place of this pixel
265 * @param dist Distance of the pixel from the center of the halo squared. Given in pixels
266 * @param xn The x coordinate of the pixel relaticve to the center of the halo. given in pixels
267 * @param yn The y coordinate of the pixel relaticve to the center of the halo. given in pixels
269 int shadeHaloFloat(HaloRen
*har
, float *col
, int zz
,
270 float dist
, float xn
, float yn
, short flarec
)
273 float t
, zn
, radist
, ringf
=0.0f
, linef
=0.0f
, alpha
, si
, co
;
276 if(R
.wrld
.mode
& WO_MIST
) {
277 if(har
->type
& HA_ONLYSKY
) {
278 /* stars but no mist */
282 /* a bit patchy... */
283 alpha
= mistfactor(-har
->co
[2], har
->co
)*har
->alfa
;
286 else alpha
= har
->alfa
;
291 /* soften the halo if it intersects geometry */
292 if(har
->mat
->mode
& MA_HALO_SOFT
) {
293 float segment_length
, halo_depth
, distance_from_z
, visible_depth
, soften
;
295 /* calculate halo depth */
296 segment_length
= har
->hasize
*sasqrt(1.0f
- dist
/(har
->rad
*har
->rad
));
297 halo_depth
= 2.0f
*segment_length
;
299 if(halo_depth
< FLT_EPSILON
)
302 /* calculate how much of this depth is visible */
303 distance_from_z
= haloZtoDist(zz
) - haloZtoDist(har
->zs
);
304 visible_depth
= halo_depth
;
305 if(distance_from_z
< segment_length
) {
306 soften
= (segment_length
+ distance_from_z
)/halo_depth
;
308 /* apply softening to alpha */
316 /* not a soft halo. use the old softening code */
317 /* halo being intersected? */
318 if(har
->zs
> zz
-har
->zd
) {
319 t
= ((float)(zz
-har
->zs
))/(float)har
->zd
;
320 alpha
*= sqrt(sqrt(t
));
326 /* watch it: not used nicely: flarec is set at zero in pixstruct */
327 if(flarec
) har
->pixels
+= (int)(har
->rad
-radist
);
333 /* per ring an antialised circle */
336 for(a
= har
->ringc
; a
>0; a
--, ofs
+=2) {
338 rc
= hashvectf
+ (ofs
% 768);
340 fac
= fabs( rc
[1]*(har
->rad
*fabs(rc
[0]) - radist
) );
348 if(har
->type
& HA_VECT
) {
349 dist
= fabs( har
->cos
*(yn
) - har
->sin
*(xn
) )/har
->rad
;
350 if(dist
>1.0) dist
= 1.0;
352 zn
= har
->sin
*xn
- har
->cos
*yn
;
353 yn
= har
->cos
*xn
+ har
->sin
*yn
;
357 else dist
= dist
/har
->radsq
;
359 if(har
->type
& HA_FLARECIRC
) {
361 dist
= 0.5+fabs(dist
-0.5);
368 dist
= sin(dist
*M_PI_2
);
374 else if(har
->hard
<20) dist
*=dist
;
385 /* per starpoint an antialiased line */
388 for(a
= har
->linec
; a
>0; a
--, ofs
+=3) {
390 rc
= hashvectf
+ (ofs
% 768);
392 fac
= fabs( (xn
)*rc
[0]+(yn
)*rc
[1]);
401 if(har
->starpoints
) {
404 angle
= atan2(yn
, xn
);
405 angle
*= (1.0+0.25*har
->starpoints
);
410 angle
= (co
*xn
+si
*yn
)*(co
*yn
-si
*xn
);
414 ster
= (har
->rad
)/(ster
);
416 if(ster
<1.0) dist
*= sqrt(ster
);
420 /* disputable optimize... (ton) */
428 /* The color is either the rgb spec-ed by the user, or extracted from */
436 do_halo_tex(har
, xn
, yn
, col
);
447 if(har
->type
& HA_XALPHA
) col
[3]= dist
*dist
;
452 if(har
->mat
->mode
& MA_HALO_SHADE
) {
453 /* we test for lights because of preview... */
454 if(R
.lights
.first
) render_lighting_halo(har
, col
);
457 /* Next, we do the line and ring factor modifications. */
459 Material
*ma
= har
->mat
;
461 col
[0]+= linef
* ma
->specr
;
462 col
[1]+= linef
* ma
->specg
;
463 col
[2]+= linef
* ma
->specb
;
465 if(har
->type
& HA_XALPHA
) col
[3]+= linef
*linef
;
469 Material
*ma
= har
->mat
;
471 col
[0]+= ringf
* ma
->mirr
;
472 col
[1]+= ringf
* ma
->mirg
;
473 col
[2]+= ringf
* ma
->mirb
;
475 if(har
->type
& HA_XALPHA
) col
[3]+= ringf
*ringf
;
480 /* alpha requires clip, gives black dots */
487 /* ------------------------------------------------------------------------- */
489 static void fillBackgroundImage(float *collector
, float fx
, float fy
)
497 float dx
= 1.0f
/(float)R
.winx
;
498 float dy
= 1.0f
/(float)R
.winy
;
500 image_sample(R
.backbuf
, fx
*dx
, fy
*dy
, dx
, dy
, collector
);
504 /* Only view vector is important here. Result goes to colf[3] */
505 void shadeSkyView(float *colf
, float *rco
, float *view
, float *dxyview
)
507 float lo
[3], zen
[3], hor
[3], blend
, blendm
, new_ang
;
510 /* flag indicating if we render the top hemisphere */
513 /* Some view vector stuff. */
514 if(R
.wrld
.skytype
& WO_SKYREAL
) {
515 new_ang
= (acos(view
[1]) * M_PI_2
) / (M_PI_2
+ M_PI
* (R
.wrld
.add_angle
) / 180.f
);
516 new_ang
= cos(new_ang
);
517 blend
= view
[0]*R
.grvec
[0] + new_ang
*R
.grvec
[1] + view
[2]*R
.grvec
[2];
523 else if(R
.wrld
.skytype
& WO_SKYPAPER
) {
524 blend
= 0.5+ 0.5*view
[1];
527 /* the fraction of how far we are above the bottom of the screen */
528 blend
= fabs(0.5+ view
[1]);
531 hor
[0]= R
.wrld
.horr
; hor
[1]= R
.wrld
.horg
; hor
[2]= R
.wrld
.horb
;
532 zen
[0]= R
.wrld
.zenr
; zen
[1]= R
.wrld
.zeng
; zen
[2]= R
.wrld
.zenb
;
534 /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
535 /* SKYBLEND is active, the texture and color blend are added. */
536 if(R
.wrld
.skytype
& WO_SKYTEX
) {
538 if(R
.wrld
.skytype
& WO_SKYREAL
) {
540 MTC_Mat3MulVecfl(R
.imat
, lo
);
542 SWAP(float, lo
[1], lo
[2]);
545 do_sky_tex(rco
, lo
, dxyview
, hor
, zen
, &blend
, skyflag
);
548 if(blend
>1.0) blend
= 1.0;
551 /* No clipping, no conversion! */
552 if(R
.wrld
.skytype
& WO_SKYBLEND
) {
553 colf
[0] = (blendm
*hor
[0] + blend
*zen
[0]);
554 colf
[1] = (blendm
*hor
[1] + blend
*zen
[1]);
555 colf
[2] = (blendm
*hor
[2] + blend
*zen
[2]);
557 /* Done when a texture was grabbed. */
565 Stuff the sky color into the collector.
567 void shadeSkyPixel(float *collector
, float fx
, float fy
)
569 float view
[3], dxyview
[2];
573 1. Draw an image, if a background image was provided. Stop
574 2. get texture and color blend, and combine these.
579 /* 1. Do a backbuffer image: */
580 if(R
.r
.bufflag
& 1) {
581 fillBackgroundImage(collector
, fx
, fy
);
584 else if((R
.wrld
.skytype
& (WO_SKYBLEND
+WO_SKYTEX
))==0) {
586 collector
[0] = R
.wrld
.horr
;
587 collector
[1] = R
.wrld
.horg
;
588 collector
[2] = R
.wrld
.horb
;
594 /* This one true because of the context of this routine */
595 if(R
.wrld
.skytype
& WO_SKYPAPER
) {
596 view
[0]= -1.0f
+ 2.0f
*(fx
/(float)R
.winx
);
597 view
[1]= -1.0f
+ 2.0f
*(fy
/(float)R
.winy
);
600 dxyview
[0]= 1.0f
/(float)R
.winx
;
601 dxyview
[1]= 1.0f
/(float)R
.winy
;
604 calc_view_vector(view
, fx
, fy
);
605 fac
= Normalize(view
);
607 if(R
.wrld
.skytype
& WO_SKYTEX
) {
608 dxyview
[0]= -R
.viewdx
/fac
;
609 dxyview
[1]= -R
.viewdy
/fac
;
613 /* get sky color in the collector */
614 shadeSkyView(collector
, NULL
, view
, dxyview
);