Patch #8034: "soft" option for halos, which avoids ugly intersections
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 14 Apr 2008 19:48:14 +0000 (19:48 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 14 Apr 2008 19:48:14 +0000 (19:48 +0000)
with geometry, and makes halos look more volumetric.

Patch contributed by Markus Ilmola, thanks!

source/blender/makesdna/DNA_material_types.h
source/blender/render/intern/include/pixelshading.h
source/blender/render/intern/source/pixelshading.c
source/blender/render/intern/source/rendercore.c
source/blender/src/buttons_shading.c

index a4c6120..361b240 100644 (file)
@@ -161,6 +161,7 @@ typedef struct Material {
 #define MA_SHLESS              4
 #define MA_WIRE                        8
 #define MA_VERTEXCOL   16
+#define MA_HALO_SOFT   16
 #define MA_HALO                        32
 #define MA_ZTRA                        64
 #define MA_VERTEXCOLP  128
index d223578..ee7199a 100644 (file)
@@ -45,7 +45,7 @@
  * mask is pixel coverage in bits
  * @return pointer to the object
  */
-void shadeHaloFloat(HaloRen *har, 
+int shadeHaloFloat(HaloRen *har, 
                                        float *col, int zz, 
                                        float dist, float xn, 
                                        float yn, short flarec);
index 6871a06..6128a48 100644 (file)
@@ -24,6 +24,7 @@
  * ***** END GPL LICENSE BLOCK *****
  */
 
+#include <float.h>
 #include <math.h>
 #include <string.h>
 #include "BLI_arithb.h"
@@ -243,8 +244,36 @@ static void render_lighting_halo(HaloRen *har, float *colf)
 }
 
 
+/**
+ * Converts a halo z-buffer value to distance from the camera's near plane
+ * @param z The z-buffer value to convert
+ * @return a distance from the camera's near plane in blender units
+ */
+static float haloZtoDist(int z)
+{
+       float zco = 0;
 
-void shadeHaloFloat(HaloRen *har,  float *col, int zz, 
+       if(z >= 0x7FFFFF)
+               return 10e10;
+       else {
+               zco = (float)z/(float)0x7FFFFF;
+               if(R.r.mode & R_ORTHO)
+                       return (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
+               else
+                       return (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
+       }
+}
+
+/**
+ * @param col (float[4]) Store the rgb color here (with alpha)
+ * The alpha is used to blend the color to the background 
+ * color_new = (1-alpha)*color_background + color
+ * @param zz The current zbuffer value at the place of this pixel
+ * @param dist Distance of the pixel from the center of the halo squared. Given in pixels
+ * @param xn The x coordinate of the pixel relaticve to the center of the halo. given in pixels
+ * @param yn The y coordinate of the pixel relaticve to the center of the halo. given in pixels
+ */
+int shadeHaloFloat(HaloRen *har,  float *col, int zz, 
                                        float dist, float xn,  float yn, short flarec)
 {
        /* fill in col */
@@ -263,12 +292,40 @@ void shadeHaloFloat(HaloRen *har,  float *col, int zz,
        }
        else alpha= har->alfa;
        
-       if(alpha==0.0) {
-               col[0] = 0.0;
-               col[1] = 0.0;
-               col[2] = 0.0;
-               col[3] = 0.0;
-               return;
+       if(alpha==0.0)
+               return 0;
+
+       /* soften the halo if it intersects geometry */
+       if(har->mat->mode & MA_HALO_SOFT) {
+               float segment_length, halo_depth, distance_from_z, visible_depth, soften;
+               
+               /* calculate halo depth */
+               segment_length= har->hasize*sasqrt(1.0f - dist/(har->rad*har->rad));
+               halo_depth= 2.0f*segment_length;
+
+               if(halo_depth < FLT_EPSILON)
+                       return 0;
+
+               /* calculate how much of this depth is visible */
+               distance_from_z = haloZtoDist(zz) - haloZtoDist(har->zs);
+               visible_depth = halo_depth;
+               if(distance_from_z < segment_length) {
+                       soften= (segment_length + distance_from_z)/halo_depth;
+
+                       /* apply softening to alpha */
+                       if(soften < 1.0f)
+                               alpha *= soften;
+                       if(alpha <= 0.0f)
+                               return 0;
+               }
+       }
+       else {
+               /* not a soft halo. use the old softening code */
+               /* halo being intersected? */
+               if(har->zs> zz-har->zd) {
+                       t= ((float)(zz-har->zs))/(float)har->zd;
+                       alpha*= sqrt(sqrt(t));
+               }
        }
 
        radist= sqrt(dist);
@@ -366,21 +423,10 @@ void shadeHaloFloat(HaloRen *har,  float *col, int zz,
                        if(ster<1.0) dist*= sqrt(ster);
                }
        }
-       
-       /* halo being intersected? */
-       if(har->zs> zz-har->zd) {
-               t= ((float)(zz-har->zs))/(float)har->zd;
-               alpha*= sqrt(sqrt(t));
-       }
 
        /* disputable optimize... (ton) */
-       if(dist<=0.00001) {
-               col[0] = 0.0;
-               col[1] = 0.0;
-               col[2] = 0.0;
-               col[3] = 0.0;
-               return;
-       }
+       if(dist<=0.00001)
+               return 0;
        
        dist*= alpha;
        ringf*= dist;
@@ -441,6 +487,8 @@ void shadeHaloFloat(HaloRen *har,  float *col, int zz,
        /* alpha requires clip, gives black dots */
        if(col[3] > 1.0f)
                col[3]= 1.0f;
+
+       return 1;
 }
 
 /* ------------------------------------------------------------------------- */
index e36d864..15d41d4 100644 (file)
@@ -165,9 +165,11 @@ static int calchalo_z(HaloRen *har, int zz)
        return zz;
 }
 
+
+
 static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, int od, float dist, float xn, float yn, PixStr *ps)
 {
-       float col[4], accol[4];
+       float col[4], accol[4], fac;
        int amount, amountm, zz, flarec, sample, fullsample, mask=0;
        
        fullsample= (totsample > 1);
@@ -180,23 +182,22 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
                amount+= amountm;
                
                zz= calchalo_z(har, ps->z);
-               if(zz> har->zs) {
-                       float fac;
-                       
-                       shadeHaloFloat(har, col, zz, dist, xn, yn, flarec);
-                       flarec= 0;
-
-                       if(fullsample) {
-                               for(sample=0; sample<totsample; sample++)
-                                       if(ps->mask & (1 << sample))
-                                               addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
-                       }
-                       else {
-                               fac= ((float)amountm)/(float)R.osa;
-                               accol[0]+= fac*col[0];
-                               accol[1]+= fac*col[1];
-                               accol[2]+= fac*col[2];
-                               accol[3]+= fac*col[3];
+               if((zz> har->zs) || (har->mat->mode & MA_HALO_SOFT)) {
+                       if(shadeHaloFloat(har, col, zz, dist, xn, yn, flarec)) {
+                               flarec= 0;
+
+                               if(fullsample) {
+                                       for(sample=0; sample<totsample; sample++)
+                                               if(ps->mask & (1 << sample))
+                                                       addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+                               }
+                               else {
+                                       fac= ((float)amountm)/(float)R.osa;
+                                       accol[0]+= fac*col[0];
+                                       accol[1]+= fac*col[1];
+                                       accol[2]+= fac*col[2];
+                                       accol[3]+= fac*col[3];
+                               }
                        }
                }
                
@@ -207,16 +208,14 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in
        /* now do the sky sub-pixels */
        amount= R.osa-amount;
        if(amount) {
-               float fac;
-
-               shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec);
-
-               if(!fullsample) {
-                       fac= ((float)amount)/(float)R.osa;
-                       accol[0]+= fac*col[0];
-                       accol[1]+= fac*col[1];
-                       accol[2]+= fac*col[2];
-                       accol[3]+= fac*col[3];
+               if(shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec)) {
+                       if(!fullsample) {
+                               fac= ((float)amount)/(float)R.osa;
+                               accol[0]+= fac*col[0];
+                               accol[1]+= fac*col[1];
+                               accol[2]+= fac*col[2];
+                               accol[3]+= fac*col[3];
+                       }
                }
        }
 
@@ -301,11 +300,11 @@ static void halo_tile(RenderPart *pa, RenderLayer *rl)
                                                        }
                                                        else {
                                                                zz= calchalo_z(har, *rz);
-                                                               if(zz> har->zs) {
-                                                                       shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec);
-
-                                                                       for(sample=0; sample<totsample; sample++)
-                                                                               addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+                                                               if((zz> har->zs) || (har->mat->mode & MA_HALO_SOFT)) {
+                                                                       if(shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec)) {
+                                                                               for(sample=0; sample<totsample; sample++)
+                                                                                       addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add);
+                                                                       }
                                                                }
                                                        }
                                                }
@@ -1634,8 +1633,8 @@ static void renderhalo_post(RenderResult *rr, float *rectf, HaloRen *har) /* pos
                                        dist= xsq+ysq;
                                        if(dist<har->radsq) {
                                                
-                                               shadeHaloFloat(har, colf, 0x7FFFFF, dist, xn, yn, har->flarec);
-                                               addalphaAddfacFloat(rtf, colf, har->add);
+                                               if(shadeHaloFloat(har, colf, 0x7FFFFF, dist, xn, yn, har->flarec))
+                                                       addalphaAddfacFloat(rtf, colf, har->add);
                                        }
                                        rtf+=4;
                                }
index 880076d..db531c7 100644 (file)
@@ -3843,14 +3843,15 @@ static void material_panel_shading(Material *ma)
                uiBlockSetCol(block, TH_BUT_SETTING1);
                
                uiBlockBeginAlign(block);
-               uiDefButBitI(block, TOG, MA_HALO_FLARE, B_MATPRV, "Flare",245,142,65,28, &(ma->mode), 0, 0, 0, 0, "Renders halo as a lensflare");
-               uiDefButBitI(block, TOG, MA_HALO_RINGS, B_MATPRV, "Rings",              245,123,65, 18, &(ma->mode), 0, 0, 0, 0, "Renders rings over halo");
-               uiDefButBitI(block, TOG, MA_HALO_LINES, B_MATPRV, "Lines",              245,104,65, 18, &(ma->mode), 0, 0, 0, 0, "Renders star shaped lines over halo");
-               uiDefButBitI(block, TOG, MA_STAR, B_MATPRV, "Star",             245,85,65, 18, &(ma->mode), 0, 0, 0, 0, "Renders halo as a star");
-               uiDefButBitI(block, TOG, MA_HALOTEX, B_MATPRV, "HaloTex",       245,66,65, 18, &(ma->mode), 0, 0, 0, 0, "Gives halo a texture");
-               uiDefButBitI(block, TOG, MA_HALOPUNO, B_MATPRV, "HaloPuno",     245,47,65, 18, &(ma->mode), 0, 0, 0, 0, "Uses the vertex normal to specify the dimension of the halo");
-               uiDefButBitI(block, TOG, MA_HALO_XALPHA, B_MATPRV, "X Alpha",   245,28,65, 18, &(ma->mode), 0, 0, 0, 0, "Uses extreme alpha");
-               uiDefButBitI(block, TOG, MA_HALO_SHADE, B_MATPRV, "Shaded",     245,9,65, 18, &(ma->mode), 0, 0, 0, 0, "Lets halo receive light and shadows");
+               uiDefButBitI(block, TOG, MA_HALO_FLARE,  B_MATPRV, "Flare",    245,161,65,28, &(ma->mode), 0, 0, 0, 0, "Renders halo as a lensflare");
+               uiDefButBitI(block, TOG, MA_HALO_RINGS,  B_MATPRV, "Rings",        245,142,65,18, &(ma->mode), 0, 0, 0, 0, "Renders rings over halo");
+               uiDefButBitI(block, TOG, MA_HALO_LINES,  B_MATPRV, "Lines",        245,123,65,18, &(ma->mode), 0, 0, 0, 0, "Renders star shaped lines over halo");
+               uiDefButBitI(block, TOG, MA_STAR,        B_MATPRV, "Star",         245,104,65, 18, &(ma->mode), 0, 0, 0, 0, "Renders halo as a star");
+               uiDefButBitI(block, TOG, MA_HALOTEX,     B_MATPRV, "HaloTex",  245,85,65, 18, &(ma->mode), 0, 0, 0, 0, "Gives halo a texture");
+               uiDefButBitI(block, TOG, MA_HALOPUNO,    B_MATPRV, "HaloPuno", 245,66,65, 18, &(ma->mode), 0, 0, 0, 0, "Uses the vertex normal to specify the dimension of the halo");
+               uiDefButBitI(block, TOG, MA_HALO_XALPHA, B_MATPRV, "X Alpha",  245,47,65, 18, &(ma->mode), 0, 0, 0, 0, "Uses extreme alpha");
+               uiDefButBitI(block, TOG, MA_HALO_SHADE,  B_MATPRV, "Shaded",   245,28,65,  18, &(ma->mode), 0, 0, 0, 0, "Lets halo receive light and shadows");
+               uiDefButBitI(block, TOG, MA_HALO_SOFT,   B_MATPRV, "Soft",         245,9,65,  18, &(ma->mode), 0, 0, 0, 0, "Softens the halo");
                uiBlockEndAlign(block);
        }
        else {