Patch from Raul Fernandez Hernandez - volume render multiple scattering fixes
authorMatt Ebb <matt@mke3.net>
Sun, 3 Jan 2010 23:45:13 +0000 (23:45 +0000)
committerMatt Ebb <matt@mke3.net>
Sun, 3 Jan 2010 23:45:13 +0000 (23:45 +0000)
Also: Changed 'Spread' value to be proportional to the light cache voxel grid
(i.e. 0.5 spreads half the width of the grid), so that it's independent of light
cache resolution. This means that results should be similar as you increase/
decrease resolution.

source/blender/blenkernel/intern/material.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_material_types.h
source/blender/makesrna/intern/rna_material.c
source/blender/render/intern/source/volume_precache.c
source/blender/render/intern/source/volumetric.c

index a3e0ab049918fe817962a5960ca782306c2bd3e4..3567c061f045437583411e97b7bace20709a5971 100644 (file)
@@ -184,6 +184,9 @@ void init_material(Material *ma)
        ma->vol.shade_type = MA_VOL_SHADE_SHADED;
        ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
        ma->vol.precache_resolution = 50;
+       ma->vol.ms_spread = 0.2f;
+       ma->vol.ms_diff = 1.f;
+       ma->vol.ms_intensity = 1.f;
        
        ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RAYBIAS|MA_TANGENT_STR|MA_ZTRANSP;
 
index 18fc7b8e3be645103c6f2d7699df0ce55ed0534b..69186432d64a58ed92076304d5edfef52f3df28f 100644 (file)
@@ -10324,6 +10324,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                Scene *sce;
                Object *ob;
                Brush *brush;
+               Material *ma;
                
                /* game engine changes */
                for(sce = main->scene.first; sce; sce = sce->id.next) {
@@ -10386,6 +10387,15 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                for (brush= main->brush.first; brush; brush= brush->id.next) {
                        default_mtex(&brush->mtex);
                }
+
+               for (ma= main->mat.first; ma; ma= ma->id.next) {
+                       if (ma->vol.ms_spread < 0.0001f) {
+                               ma->vol.ms_spread = 0.2f;
+                               ma->vol.ms_diff = 1.f;
+                               ma->vol.ms_intensity = 1.f;     
+                       }
+               }
+               
        }
 
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
index 36de890e6dc41541421017c4716bc6c542dfe495..7a19262b0cd0f5bf96c3527bf628f0af37568e72 100644 (file)
@@ -69,7 +69,7 @@ typedef struct VolumeSettings {
        float stepsize;
        float ms_diff;
        float ms_intensity;
-       int ms_steps;
+       float ms_spread;
 } VolumeSettings;
 
 typedef struct Material {
index a5c1d8d5f575ed3f564c8c797443f252fc1c1a0f..b69e5130c0f0c18d712bffa7d83968bfcd5e5293 100644 (file)
@@ -1023,10 +1023,11 @@ static void rna_def_material_volume(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Diffusion", "Diffusion factor, the strength of the blurring effect");
        RNA_def_property_update(prop, 0, "rna_Material_update");
        
-       prop= RNA_def_property(srna, "ms_spread", PROP_INT, PROP_NONE);
-       RNA_def_property_int_sdna(prop, NULL, "ms_steps");
-       RNA_def_property_range(prop, 0, 1024);
-       RNA_def_property_ui_text(prop, "Spread", "Simulation steps, the effective distance over which the light is diffused");
+       prop= RNA_def_property(srna, "ms_spread", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "ms_spread");
+       RNA_def_property_range(prop, 0, FLT_MAX);
+       RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 3);
+       RNA_def_property_ui_text(prop, "Spread", "Proportional distance over which the light is diffused");
        RNA_def_property_update(prop, 0, "rna_Material_update");
        
        prop= RNA_def_property(srna, "ms_intensity", PROP_FLOAT, PROP_NONE);
index e9162b7367f83341838f5ab21a7a23b5fe1a130a..80a6dd9d6a0f1f94b9451081d86b99b1fafc02d6 100644 (file)
@@ -21,7 +21,7 @@
  *
  * The Original Code is: all of this file.
  *
- * Contributor(s): Matt Ebb.
+ * Contributor(s): Matt Ebb, Ra˙l Fern·ndez Hern·ndez (Farsthary).
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -134,9 +134,10 @@ static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz)
                                        for (x=-1; x <= 1; x++) {
                                                x_ = xx+x;
                                                if (x_ >= 0 && x_ <= res[0]-1) {
-                                               
-                                                       if (cache[ V_I(x_, y_, z_, res) ] > 0.0f) {
-                                                               tot += cache[ V_I(x_, y_, z_, res) ];
+                                                       const int i= V_I(x_, y_, z_, res);
+                                                       
+                                                       if (cache[i] > 0.0f) {
+                                                               tot += cache[i];
                                                                added++;
                                                        }
                                                        
@@ -164,12 +165,14 @@ static void lightcache_filter(VolumePrecache *vp)
                for (y=0; y < vp->res[1]; y++) {
                        for (x=0; x < vp->res[0]; x++) {
                                /* trigger for outside mesh */
-                               if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.f)
-                                       vp->data_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
-                               if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.f)
-                                       vp->data_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
-                               if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.f)
-                                       vp->data_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
+                               const int i= V_I(x, y, z, vp->res);
+                               
+                               if (vp->data_r[i] < -0.f)
+                                       vp->data_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
+                               if (vp->data_g[i] < -0.f)
+                                       vp->data_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
+                               if (vp->data_b[i] < -0.f)
+                                       vp->data_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
                        }
                }
        }
@@ -194,12 +197,13 @@ static void lightcache_filter2(VolumePrecache *vp)
                for (y=0; y < vp->res[1]; y++) {
                        for (x=0; x < vp->res[0]; x++) {
                                /* trigger for outside mesh */
-                               if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.f)
-                                       new_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
-                               if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.f)
-                                       new_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
-                               if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.f)
-                                       new_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
+                               const int i= V_I(x, y, z, vp->res);
+                               if (vp->data_r[i] < -0.f)
+                                       new_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
+                               if (vp->data_g[i] < -0.f)
+                                       new_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
+                               if (vp->data_b[i] < -0.f)
+                                       new_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
                        }
                }
        }
@@ -216,9 +220,21 @@ static void lightcache_filter2(VolumePrecache *vp)
 
 static inline int ms_I(int x, int y, int z, int *n) //has a pad of 1 voxel surrounding the core for boundary simulation
 { 
-       return z*(n[1]+2)*(n[0]+2) + y*(n[0]+2) + x;
+       /* different ordering to light cache */
+       return x*(n[1]+2)*(n[2]+2) + y*(n[2]+2) + z;    
+}
+
+static inline int v_I_pad(int x, int y, int z, int *n) //has a pad of 1 voxel surrounding the core for boundary simulation
+{ 
+       /* same ordering to light cache, with padding */
+       return z*(n[1]+2)*(n[0]+2) + y*(n[0]+2) + x;    
 }
 
+static inline int lc_to_ms_I(int x, int y, int z, int *n)
+{ 
+       /* converting light cache index to multiple scattering index */
+       return (x-1)*(n[1]*n[2]) + (y-1)*(n[2]) + z-1;
+}
 
 /* *** multiple scattering approximation *** */
 
@@ -232,9 +248,11 @@ static float total_ss_energy(VolumePrecache *vp)
        for (z=0; z < res[2]; z++) {
                for (y=0; y < res[1]; y++) {
                        for (x=0; x < res[0]; x++) {
-                               if (vp->data_r[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_r[ V_I(x, y, z, res) ];
-                               if (vp->data_g[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_g[ V_I(x, y, z, res) ];
-                               if (vp->data_b[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_b[ V_I(x, y, z, res) ];
+                               const int i=V_I(x, y, z, res);
+                       
+                               if (vp->data_r[i] > 0.f) energy += vp->data_r[i];
+                               if (vp->data_g[i] > 0.f) energy += vp->data_g[i];
+                               if (vp->data_b[i] > 0.f) energy += vp->data_b[i];
                        }
                }
        }
@@ -244,14 +262,14 @@ static float total_ss_energy(VolumePrecache *vp)
 
 static float total_ms_energy(float *sr, float *sg, float *sb, int *res)
 {
-       int x, y, z, i;
+       int x, y, z;
        float energy=0.f;
        
        for (z=1;z<=res[2];z++) {
                for (y=1;y<=res[1];y++) {
                        for (x=1;x<=res[0];x++) {
-                       
-                               i = ms_I(x,y,z,res);
+                               const int i = ms_I(x,y,z,res);
+                               
                                if (sr[i] > 0.f) energy += sr[i];
                                if (sg[i] > 0.f) energy += sg[i];
                                if (sb[i] > 0.f) energy += sb[i];
@@ -262,7 +280,7 @@ static float total_ms_energy(float *sr, float *sg, float *sb, int *res)
        return energy;
 }
 
-static void ms_diffuse(int b, float* x0, float* x, float diff, int *n)
+static void ms_diffuse(float *x0, float *x, float diff, int *n) //n is the unpadded resolution
 {
        int i, j, k, l;
        const float dt = VOL_MS_TIMESTEP;
@@ -276,10 +294,9 @@ static void ms_diffuse(int b, float* x0, float* x, float diff, int *n)
                        {
                                for (i=1; i<=n[0]; i++)
                                {
-                                       x[ms_I(i,j,k,n)] = (x0[ms_I(i,j,k,n)] + a*(
-                                                x[ms_I(i-1,j,k,n)]+x[ms_I(i+1,j,k,n)]+
-                                                x[ms_I(i,j-1,k,n)]+x[ms_I(i,j+1,k,n)]+
-                                                x[ms_I(i,j,k-1,n)]+x[ms_I(i,j,k+1,n)]))/(1+6*a);
+                                  x[v_I_pad(i,j,k,n)] = (x0[v_I_pad(i,j,k,n)]) + a*(   x0[v_I_pad(i-1,j,k,n)]+ x0[v_I_pad(i+1,j,k,n)]+ x0[v_I_pad(i,j-1,k,n)]+
+                                                                                                                                               x0[v_I_pad(i,j+1,k,n)]+ x0[v_I_pad(i,j,k-1,n)]+x0[v_I_pad(i,j,k+1,n)]
+                                                                                                                                               ) / (1+6*a);
                                }
                        }
                }
@@ -289,7 +306,7 @@ static void ms_diffuse(int b, float* x0, float* x, float diff, int *n)
 void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
 {
        const float diff = ma->vol.ms_diff * 0.001f;    /* compensate for scaling for a nicer UI range */
-       const float simframes = ma->vol.ms_steps;
+       const int simframes = (int)(ma->vol.ms_spread * (float)MAX3(vp->res[0], vp->res[1], vp->res[2]));
        const int shade_type = ma->vol.shade_type;
        float fac = ma->vol.ms_intensity;
        
@@ -299,7 +316,6 @@ void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
        double time, lasttime= PIL_check_seconds_timer();
        float total;
        float c=1.0f;
-       int i;
        float origf;    /* factor for blending in original light cache */
        float energy_ss, energy_ms;
 
@@ -324,22 +340,22 @@ void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
                        {
                                for (x=1; x<=n[0]; x++)
                                {
-                                       i = V_I((x-1), (y-1), (z-1), n);
+                                       const int i = lc_to_ms_I(x, y ,z, n);   //lc index                                      
+                                       const int j = ms_I(x, y, z, n);                 //ms index
+                                       
                                        time= PIL_check_seconds_timer();
-                                       c++;
-                                                                               
-                                       if (vp->data_r[i] > 0.f)
-                                               sr[ms_I(x,y,z,n)] += vp->data_r[i];
-                                       if (vp->data_g[i] > 0.f)
-                                               sg[ms_I(x,y,z,n)] += vp->data_g[i];
-                                       if (vp->data_b[i] > 0.f)
-                                               sb[ms_I(x,y,z,n)] += vp->data_b[i];
+                                       c++;                                                                            
+                                       if (vp->data_r[i] > 0.0f)
+                                               sr[j] += vp->data_r[i];
+                                       if (vp->data_g[i] > 0.0f)
+                                               sg[j] += vp->data_g[i];
+                                       if (vp->data_b[i] > 0.0f)
+                                               sb[j] += vp->data_b[i];
                                        
                                        /* Displays progress every second */
                                        if(time-lasttime>1.0f) {
                                                char str[64];
-                                               sprintf(str, "Simulating multiple scattering: %d%%", (int)
-                                                               (100.0f * (c / total)));
+                                               sprintf(str, "Simulating multiple scattering: %d%%", (int)(100.0f * (c / total)));
                                                re->i.infostr= str;
                                                re->stats_draw(re->sdh, &re->i);
                                                re->i.infostr= NULL;
@@ -348,14 +364,14 @@ void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
                                }
                        }
                }
-               SWAP(float *, sr, sr0);
-               SWAP(float *, sg, sg0);
-               SWAP(float *, sb, sb0);
-
+               SWAP(float *,sr,sr0);
+               SWAP(float *,sg,sg0);
+               SWAP(float *,sb,sb0);
+               
                /* main diffusion simulation */
-               ms_diffuse(0, sr0, sr, diff, n);
-               ms_diffuse(0, sg0, sg, diff, n);
-               ms_diffuse(0, sb0, sb, diff, n);
+               ms_diffuse(sr0, sr, diff, n);
+               ms_diffuse(sg0, sg, diff, n);
+               ms_diffuse(sb0, sb, diff, n);
                
                if (re->test_break(re->tbh)) break;
        }
@@ -379,10 +395,12 @@ void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
                {
                        for (x=1;x<=n[0];x++)
                        {
-                               int index=(x-1)*n[1]*n[2] + (y-1)*n[2] + z-1;
-                               vp->data_r[index] = origf * vp->data_r[index] + fac * sr[ms_I(x,y,z,n)];
-                               vp->data_g[index] = origf * vp->data_g[index] + fac * sg[ms_I(x,y,z,n)];
-                               vp->data_b[index] = origf * vp->data_b[index] + fac * sb[ms_I(x,y,z,n)];
+                               const int i = lc_to_ms_I(x, y ,z, n);   //lc index                                      
+                               const int j = ms_I(x, y, z, n);                 //ms index
+                               
+                               vp->data_r[i] = origf * vp->data_r[i] + fac * sr[j];
+                               vp->data_g[i] = origf * vp->data_g[i] + fac * sg[j];
+                               vp->data_b[i] = origf * vp->data_b[i] + fac * sb[j];
                        }
                }
        }
@@ -426,7 +444,7 @@ static void *vol_precache_part(void *data)
        ShadeInput *shi = pa->shi;
        float scatter_col[3] = {0.f, 0.f, 0.f};
        float co[3];
-       int x, y, z;
+       int x, y, z, i;
        const int res[3]= {pa->res[0], pa->res[1], pa->res[2]};
 
        for (z= pa->minz; z < pa->maxz; z++) {
@@ -437,12 +455,14 @@ static void *vol_precache_part(void *data)
                        
                        for (x=pa->minx; x < pa->maxx; x++) {
                                co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f));
+                                                       
+                               i= V_I(x, y, z, res);
                                
                                // don't bother if the point is not inside the volume mesh
                                if (!point_inside_obi(tree, obi, co)) {
-                                       obi->volume_precache->data_r[ V_I(x, y, z, res) ] = -1.0f;
-                                       obi->volume_precache->data_g[ V_I(x, y, z, res) ] = -1.0f;
-                                       obi->volume_precache->data_b[ V_I(x, y, z, res) ] = -1.0f;
+                                       obi->volume_precache->data_r[i] = -1.0f;
+                                       obi->volume_precache->data_g[i] = -1.0f;
+                                       obi->volume_precache->data_b[i] = -1.0f;
                                        continue;
                                }
                                
@@ -450,9 +470,9 @@ static void *vol_precache_part(void *data)
                                normalize_v3(shi->view);
                                vol_get_scattering(shi, scatter_col, co);
                        
-                               obi->volume_precache->data_r[ V_I(x, y, z, res) ] = scatter_col[0];
-                               obi->volume_precache->data_g[ V_I(x, y, z, res) ] = scatter_col[1];
-                               obi->volume_precache->data_b[ V_I(x, y, z, res) ] = scatter_col[2];
+                               obi->volume_precache->data_r[i] = scatter_col[0];
+                               obi->volume_precache->data_g[i] = scatter_col[1];
+                               obi->volume_precache->data_b[i] = scatter_col[2];
                        }
                }
        }
@@ -684,12 +704,13 @@ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Mat
                //tree= NULL;
        }
        
-       lightcache_filter(obi->volume_precache);
-       
        if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE))
        {
-               multiple_scattering_diffusion(re, vp, ma);
+               /* this should be before the filtering */
+               multiple_scattering_diffusion(re, obi->volume_precache, ma);
        }
+               
+       lightcache_filter(obi->volume_precache);
 }
 
 static int using_lightcache(Material *ma)
@@ -741,7 +762,7 @@ int point_inside_volume_objectinstance(Render *re, ObjectInstanceRen *obi, float
        RayObject *tree;
        int inside=0;
        
-       tree = makeraytree_object(re, obi); //create_raytree_obi(obi, obi->obr->boundbox[0], obi->obr->boundbox[1]);
+       tree = makeraytree_object(re, obi);
        if (!tree) return 0;
        
        inside = point_inside_obi(tree, obi, co);
index 32ab2980316e2930909a58baba1a43f122914690..e44064de6065856a91d06f08d4189142ceb1f6d2 100644 (file)
@@ -493,7 +493,7 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *
        if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) {
                mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
        }
-       else if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADED)
+       else if (ELEM3(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE))
        {
                Isect is;