[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [19326] branches/sim_physics/source/ blender/render/intern/source/volume_precache.c: * Volume rendering / multiple scattering - normalisation

Matt Ebb matt at mke3.net
Wed Mar 18 04:52:18 CET 2009


Revision: 19326
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=19326
Author:   broken
Date:     2009-03-18 04:52:17 +0100 (Wed, 18 Mar 2009)

Log Message:
-----------
* Volume rendering / multiple scattering - normalisation

This changes the effect of the multiple scattering approximation to be more 
physically plausible (and easier to use) by making it conserve energy. 
Previously, the multiple scattering could show wildly different results 
based on the spread settings, often outputting much more light than was put 
in (via lamps), which is physically incorrect and made it difficult to use 
by requiring a lot of tweaking of the intensity value.

This fixes it to some extent with a simple normalization, where it scales 
the light energy after multiple scattering to be the same as what was
previously there in the light cache via single scattering. This means that 
using the default intensity of 1.0 should give good results by default, 
although you can still use it to tweak the effect.

Note: This will render differently if you've already set up a .blend using
multiple scattering with the old code, so you'll need to tweak older files. 
Setting the intensity back to the default 1.0 should be good though.


* Smaller thing - fixed the camera view vector stuff up a bit in light 
cache, it now gives much more similar results to non-light cache when using 
anisotropic scattering.

Modified Paths:
--------------
    branches/sim_physics/source/blender/render/intern/source/volume_precache.c

Modified: branches/sim_physics/source/blender/render/intern/source/volume_precache.c
===================================================================
--- branches/sim_physics/source/blender/render/intern/source/volume_precache.c	2009-03-17 22:27:15 UTC (rev 19325)
+++ branches/sim_physics/source/blender/render/intern/source/volume_precache.c	2009-03-18 03:52:17 UTC (rev 19326)
@@ -220,6 +220,53 @@
 	return (x*(n+2)+y)*(n+2)+z;
 }
 
+
+/* get the total amount of light energy in the light cache. used to normalise after multiple scattering */
+static float total_ss_energy(float *cache, const int res)
+{
+	int x, y, z, rgb;
+	int res_2, res_3;
+	int i;
+	float energy=0.f;
+	
+	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;
+					
+					if (cache[i] > 0.f) energy += cache[i];
+				}
+			}
+		}
+	}
+	
+	return energy;
+}
+
+static float total_ms_energy(float *sr, float *sg, float *sb, const int res)
+{
+	int x, y, z, i;
+	float energy=0.f;
+	
+	for (z=1;z<=res;z++) {
+		for (y=1;y<=res;y++) {
+			for (x=1;x<=res;x++) {
+			
+				i = 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];
+			}
+		}
+	}
+	
+	return energy;
+}
+
 static void ms_diffuse(int b, float* x0, float* x, float diff, int n)
 {
 	int i, j, k, l;
@@ -247,9 +294,9 @@
 void multiple_scattering_diffusion(Render *re, float *cache, int res, Material *ma)
 {
 	const float diff = ma->vol_ms_diff * 0.001f; 	/* compensate for scaling for a nicer UI range */
-	const float fac = ma->vol_ms_intensity;
 	const float simframes = ma->vol_ms_steps;
 	const int shade_type = ma->vol_shade_type;
+	float fac = ma->vol_ms_intensity;
 	
 	int i, j, k, m;
 	int n = res;
@@ -259,8 +306,8 @@
 	float c=1.0f;
 	int index;
 	float origf;	/* factor for blending in original light cache */
-	
-	
+	float energy_ss, energy_ms;
+
 	float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
 	float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
 	float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
@@ -270,6 +317,8 @@
 
 	total = (float)(n*n*n*simframes);
 	
+	energy_ss = total_ss_energy(cache, res);
+	
 	/* Scattering as diffusion pass */
 	for (m=0; m<simframes; m++)
 	{
@@ -318,12 +367,18 @@
 		if (re->test_break()) break;
 	}
 	
-	/* copy to light cache */
-
-	if (shade_type == MA_VOL_SHADE_SINGLEPLUSMULTIPLE)
-		origf = 1.0f;
-	else
+	/* normalisation factor to conserve energy */
+	energy_ms = total_ms_energy(sr, sg, sb, res);
+	fac *= (energy_ss / energy_ms);
+	
+	/* blend multiple scattering back in the light cache */
+	if (shade_type == MA_VOL_SHADE_SINGLEPLUSMULTIPLE) {
+		/* conserve energy - half single, half multiple */
+		origf = 0.5f;
+		fac *= 0.5f;
+	} else {
 		origf = 0.0f;
+	}
 
 	for (k=1;k<=n;k++)
 	{
@@ -390,7 +445,7 @@
 			
 			for (z=pa->minz; z < pa->maxz; z++) {
 				co[2] = pa->bbmin[2] + (pa->voxel[2] * z);
-			
+				
 				// don't bother if the point is not inside the volume mesh
 				if (!point_inside_obi(tree, obi, co)) {
 					obi->volume_precache[0*res_3 + x*res_2 + y*res + z] = -1.0f;
@@ -398,6 +453,9 @@
 					obi->volume_precache[2*res_3 + x*res_2 + y*res + z] = -1.0f;
 					continue;
 				}
+				
+				VecCopyf(shi->view, co);
+				Normalize(shi->view);
 				density = vol_get_density(shi, co);
 				vol_get_scattering(shi, scatter_col, co, stepsize, density);
 			
@@ -416,8 +474,6 @@
 
 static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi)
 {
-	float view[3] = {0.0,0.0,-1.0};
-	
 	memset(shi, 0, sizeof(ShadeInput)); 
 	shi->depth= 1;
 	shi->mask= 1;
@@ -428,7 +484,6 @@
 	shi->obi= obi;
 	shi->obr= obi->obr;
 	shi->lay = re->scene->lay;
-	VECCOPY(shi->view, view);
 }
 
 static void precache_init_parts(Render *re, RayTree *tree, ShadeInput *shi, ObjectInstanceRen *obi, float *bbmin, float *bbmax, int res, int totthread, int *parts)
@@ -654,3 +709,4 @@
 	
 	return inside;
 }
+





More information about the Bf-blender-cvs mailing list