Patch #8034: "soft" option for halos, which avoids ugly intersections
[plumiferos.git] / source / blender / render / intern / source / pixelshading.c
blobdb265bd462a83b3bc162efe2dedfa8e1642ceb49
1 /**
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 *****
27 #include <float.h>
28 #include <math.h>
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"
50 /* own module */
51 #include "render_types.h"
52 #include "renderpipeline.h"
53 #include "renderdatabase.h"
54 #include "texture.h"
55 #include "pixelblending.h"
56 #include "rendercore.h"
57 #include "shadbuf.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)
71 GroupObject *go;
72 LampRen *lar;
73 float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
74 float ir, ig, ib, shadfac, soft, lacol[3];
76 ir= ig= ib= 0.0;
78 VECCOPY(rco, har->co);
79 dco[0]=dco[1]=dco[2]= 1.0/har->rad;
81 vn= har->no;
83 for(go=R.lights.first; go; go= go->next) {
84 lar= go->lampren;
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);
92 lampdist= 1.0;
94 else {
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]);
99 lv[0]/= ld;
100 lv[1]/= ld;
101 lv[2]/= ld;
103 /* ld is re-used further on (texco's) */
105 if(lar->mode & LA_QUAD) {
106 t= 1.0;
107 if(lar->ld1>0.0)
108 t= lar->dist/(lar->dist+lar->ld1*ld);
109 if(lar->ld2>0.0)
110 t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
112 lampdist= t;
114 else {
115 lampdist= (lar->dist/(lar->dist+ld));
118 if(lar->mode & LA_SPHERE) {
119 t= lar->dist - ld;
120 if(t<0.0) continue;
122 t/= lar->dist;
123 lampdist*= (t);
128 lacol[0]= lar->r;
129 lacol[1]= lar->g;
130 lacol[2]= lar->b;
132 if(lar->mode & LA_TEXTURE) {
133 ShadeInput shi;
134 VECCOPY(shi.co, rco);
135 shi.osatex= 0;
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) {
143 float x, lvrot[3];
145 /* rotate view to lampspace */
146 VECCOPY(lvrot, lv);
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));
154 else inpr= 0.0;
156 else {
157 inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
160 t= lar->spotsi;
161 if(inpr<t) continue;
162 else {
163 t= inpr-t;
164 i= 1.0;
165 soft= 1.0;
166 if(t<lar->spotbl && lar->spotbl!=0.0) {
167 /* soft area */
168 i= t/lar->spotbl;
169 t= i*i;
170 soft= (3.0*t-2.0*t*i);
171 inpr*= soft;
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];
177 if(inp>0.0) {
178 /* testshadowbuf==0.0 : 100% shadow */
179 shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
180 if( shadfac>0.0 ) {
181 shadfac*= inp*soft*lar->energy;
182 ir -= shadfac;
183 ig -= shadfac;
184 ib -= shadfac;
186 continue;
189 /* } */
191 lampdist*=inpr;
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)); */
203 i= inp;
205 if(lar->type==LA_HEMI) {
206 i= 0.5*i+0.5;
208 if(i>0.0) {
209 i*= lampdist;
212 /* shadow */
213 if(i> -0.41) { /* heuristic valua! */
214 shadfac= 1.0;
215 if(lar->shb) {
216 shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
217 if(shadfac==0.0) continue;
218 i*= shadfac;
222 if(i>0.0) {
223 ir+= i*lacol[0];
224 ig+= i*lacol[1];
225 ib+= i*lacol[2];
229 if(ir<0.0) ir= 0.0;
230 if(ig<0.0) ig= 0.0;
231 if(ib<0.0) ib= 0.0;
233 colf[0]*= ir;
234 colf[1]*= ig;
235 colf[2]*= ib;
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)
247 float zco = 0;
249 if(z >= 0x7FFFFF)
250 return 10e10;
251 else {
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]);
255 else
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)
272 /* fill in col */
273 float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co;
274 int a;
276 if(R.wrld.mode & WO_MIST) {
277 if(har->type & HA_ONLYSKY) {
278 /* stars but no mist */
279 alpha= har->alfa;
281 else {
282 /* a bit patchy... */
283 alpha= mistfactor(-har->co[2], har->co)*har->alfa;
286 else alpha= har->alfa;
288 if(alpha==0.0)
289 return 0;
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)
300 return 0;
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 */
309 if(soften < 1.0f)
310 alpha *= soften;
311 if(alpha <= 0.0f)
312 return 0;
315 else {
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));
324 radist= sqrt(dist);
326 /* watch it: not used nicely: flarec is set at zero in pixstruct */
327 if(flarec) har->pixels+= (int)(har->rad-radist);
329 if(har->ringc) {
330 float *rc, fac;
331 int ofs;
333 /* per ring an antialised circle */
334 ofs= har->seed;
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) );
342 if(fac< 1.0) {
343 ringf+= (1.0-fac);
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;
351 if(har->tex) {
352 zn= har->sin*xn - har->cos*yn;
353 yn= har->cos*xn + har->sin*yn;
354 xn= zn;
357 else dist= dist/har->radsq;
359 if(har->type & HA_FLARECIRC) {
361 dist= 0.5+fabs(dist-0.5);
365 if(har->hard>=30) {
366 dist= sqrt(dist);
367 if(har->hard>=40) {
368 dist= sin(dist*M_PI_2);
369 if(har->hard>=50) {
370 dist= sqrt(dist);
374 else if(har->hard<20) dist*=dist;
376 if(dist < 1.0f)
377 dist= (1.0f-dist);
378 else
379 dist= 0.0f;
381 if(har->linec) {
382 float *rc, fac;
383 int ofs;
385 /* per starpoint an antialiased line */
386 ofs= har->seed;
388 for(a= har->linec; a>0; a--, ofs+=3) {
390 rc= hashvectf + (ofs % 768);
392 fac= fabs( (xn)*rc[0]+(yn)*rc[1]);
394 if(fac< 1.0f )
395 linef+= (1.0f-fac);
398 linef*= dist;
401 if(har->starpoints) {
402 float ster, angle;
403 /* rotation */
404 angle= atan2(yn, xn);
405 angle*= (1.0+0.25*har->starpoints);
407 co= cos(angle);
408 si= sin(angle);
410 angle= (co*xn+si*yn)*(co*yn-si*xn);
412 ster= fabs(angle);
413 if(ster>1.0) {
414 ster= (har->rad)/(ster);
416 if(ster<1.0) dist*= sqrt(ster);
420 /* disputable optimize... (ton) */
421 if(dist<=0.00001)
422 return 0;
424 dist*= alpha;
425 ringf*= dist;
426 linef*= alpha;
428 /* The color is either the rgb spec-ed by the user, or extracted from */
429 /* the texture */
430 if(har->tex) {
431 col[0]= har->r;
432 col[1]= har->g;
433 col[2]= har->b;
434 col[3]= dist;
436 do_halo_tex(har, xn, yn, col);
438 col[0]*= col[3];
439 col[1]*= col[3];
440 col[2]*= col[3];
443 else {
444 col[0]= dist*har->r;
445 col[1]= dist*har->g;
446 col[2]= dist*har->b;
447 if(har->type & HA_XALPHA) col[3]= dist*dist;
448 else col[3]= dist;
451 if(har->mat) {
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. */
458 if(linef!=0.0) {
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;
466 else col[3]+= linef;
468 if(ringf!=0.0) {
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;
476 else col[3]+= ringf;
480 /* alpha requires clip, gives black dots */
481 if(col[3] > 1.0f)
482 col[3]= 1.0f;
484 return 1;
487 /* ------------------------------------------------------------------------- */
489 static void fillBackgroundImage(float *collector, float fx, float fy)
491 collector[0] = 0.0;
492 collector[1] = 0.0;
493 collector[2] = 0.0;
494 collector[3] = 0.0;
496 if(R.backbuf) {
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;
508 int skyflag;
510 /* flag indicating if we render the top hemisphere */
511 skyflag = WO_ZENUP;
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];
518 if(blend<0.0)
519 skyflag= 0;
521 blend= fabs(blend);
523 else if(R.wrld.skytype & WO_SKYPAPER) {
524 blend= 0.5+ 0.5*view[1];
526 else {
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) {
537 VECCOPY(lo, view);
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;
549 blendm= 1.0-blend;
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]);
556 } else {
557 /* Done when a texture was grabbed. */
558 colf[0]= hor[0];
559 colf[1]= hor[1];
560 colf[2]= hor[2];
565 Stuff the sky color into the collector.
567 void shadeSkyPixel(float *collector, float fx, float fy)
569 float view[3], dxyview[2];
572 The rules for sky:
573 1. Draw an image, if a background image was provided. Stop
574 2. get texture and color blend, and combine these.
577 float fac;
579 /* 1. Do a backbuffer image: */
580 if(R.r.bufflag & 1) {
581 fillBackgroundImage(collector, fx, fy);
582 return;
584 else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
585 /* 2. solid color */
586 collector[0] = R.wrld.horr;
587 collector[1] = R.wrld.horg;
588 collector[2] = R.wrld.horb;
589 collector[3] = 0.0f;
591 else {
592 /* 3. */
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);
598 view[2]= 0.0;
600 dxyview[0]= 1.0f/(float)R.winx;
601 dxyview[1]= 1.0f/(float)R.winy;
603 else {
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);
615 collector[3] = 0.0f;
620 /* eof */