Patch from Raul Fernandez Hernandez - volume render multiple scattering fixes

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.
This commit is contained in:
Matt Ebb
2010-01-03 23:45:13 +00:00
parent 1f33d574c2
commit f02dde5de7
6 changed files with 104 additions and 69 deletions

View 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;

View 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! */

View 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 {

View 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);

View 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);

View 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;