From deea0fa2e70a094cd289ac0083dcbf624453df51 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Thu, 23 Oct 2008 03:50:56 +0000 Subject: [PATCH] * More improvements for light cache Previously when using light cache, there could be artifacts caused when voxel points that were sampled outside the volume object's geometry got interpolated into the rest of the volume. This commit adds a (similar to a dilate) filter pass after creating the light cache, that fills these empty areas with the average of their surrounding voxels. http://mke3.net/blender/devel/rendering/volumetrics/vol_lightcache_filter.jpg --- .../blender/render/intern/source/volumetric.c | 92 ++++++++++++++++--- 1 file changed, 77 insertions(+), 15 deletions(-) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index aad8f44441e..02ebbd83c31 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -75,6 +75,7 @@ static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face) return (INPR(is->vec, vlr->n) < 0.0f); } +#if 0 static int vol_frontface_intersect_check(Isect *is, int ob, RayFace *face) { VlakRen *vlr = (VlakRen *)face; @@ -88,6 +89,7 @@ static int vol_always_intersect_check(Isect *is, int ob, RayFace *face) { return 1; } +#endif #define VOL_IS_BACKFACE 1 #define VOL_IS_SAMEMATERIAL 2 @@ -257,12 +259,6 @@ inline float lerp(float t, float v1, float v2) { return (1.f - t) * v1 + t * v2; } -inline float do_lerp(float t, float a, float b) { - if (a > 0.f && b > 0.f) return lerp(t, a, b); - else if (a < 0.f) return b; - else if (b < 0.f) return a; -} - /* trilinear interpolation */ static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co) { @@ -384,7 +380,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * float p; float scatter_fac; float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE); - float shadfac[4]; if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; if ((lar->lay & shi->lay)==0) return; @@ -454,7 +449,6 @@ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float * void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsize, float density) { GroupObject *go; - ListBase *lights; LampRen *lar; float col[3] = {0.f, 0.f, 0.f}; int i=0; @@ -530,10 +524,10 @@ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float if ((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) && (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED)) { - if (G.rt==0) - vol_get_precached_scattering(shi, scatter_col, step_mid); - else + if (G.rt==100) vol_get_precached_scattering_nearest(shi, scatter_col, step_mid); + else + vol_get_precached_scattering(shi, scatter_col, step_mid); } else vol_get_scattering(shi, scatter_col, step_mid, stepsize, density); @@ -782,7 +776,6 @@ int intersect_outside_volume(RayTree *tree, Isect *isect, float *offset, int lim int point_inside_obi(RayTree *tree, ObjectInstanceRen *obi, float *co) { float maxsize = RE_ray_tree_max_size(tree); - int intersected; Isect isect; float vec[3] = {0.0f,0.0f,1.0f}; int final_depth=0, depth=0, limit=20; @@ -848,6 +841,70 @@ RayTree *create_raytree_obi(ObjectInstanceRen *obi, float *bbmin, float *bbmax) return tree; } +static float get_avg_surrounds(float *cache, int res, int res_2, int res_3, int rgb, int xx, int yy, int zz) +{ + int x, y, z, x_, y_, z_; + int added=0; + float tot=0.0f; + int i; + + for (x=-1; x <= 1; x++) { + x_ = xx+x; + if (x_ >= 0 && x_ <= res-1) { + + for (y=-1; y <= 1; y++) { + y_ = yy+y; + if (y_ >= 0 && y_ <= res-1) { + + for (z=-1; z <= 1; z++) { + z_ = zz+z; + if (z_ >= 0 && z_ <= res-1) { + + i = rgb*res_3 + x_*res_2 + y_*res + z_; + if (cache[i] > 0.0f) { + tot += cache[i]; + added++; + } + + } + } + } + } + } + } + + tot /= added; + + return ((added>0)?tot:0.0f); +} + +/* function to filter the edges of the light cache, where there was no volume originally. + * For each voxel which was originally external to the mesh, it finds the average values of + * the surrounding internal voxels and sets the original external voxel to that average amount. + * Works almost a bit like a 'dilate' filter */ +static void lightcache_filter(float *cache, int res) +{ + int x, y, z, rgb; + int res_2, res_3; + int i; + + res_2 = res*res; + res_3 = res*res*res; + + for (x=0; x < res; x++) { + for (y=0; y < res; y++) { + for (z=0; z < res; z++) { + for (rgb=0; rgb < 3; rgb++) { + i = rgb*res_3 + x*res_2 + y*res + z; + + /* trigger for outside mesh */ + if (cache[i] < 0.5f) cache[i] = get_avg_surrounds(cache, res, res_2, res_3, rgb, x, y, z); + } + } + } + } +} + /* Precache a volume into a 3D voxel grid. * The voxel grid is stored in the ObjectInstanceRen, * in camera space, aligned with the ObjectRen's bounding box. @@ -941,9 +998,12 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m } /* don't bother if the point is not inside the volume mesh */ - if (!point_inside_obi(tree, obi, co)) + if (!point_inside_obi(tree, obi, co)) { + obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[1*res_3 + x*res_2 + y*res + z] = -1.0f; + obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f; continue; - + } density = vol_get_density(&shi, co); vol_get_scattering(&shi, scatter_col, co, stepsize, density); @@ -959,6 +1019,7 @@ void vol_precache_objectinstance(Render *re, ObjectInstanceRen *obi, Material *m tree= NULL; } + lightcache_filter(obi->volume_precache, res); } @@ -990,4 +1051,5 @@ void free_volume_precache(Render *re) } BLI_freelistN(&re->vol_precache_obs); -} \ No newline at end of file +} +