[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17127] branches/sim_physics/source/ blender: New volume rendering feature: Light Cache

Matt Ebb matt at mke3.net
Mon Oct 20 09:08:06 CEST 2008


Revision: 17127
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17127
Author:   broken
Date:     2008-10-20 09:08:06 +0200 (Mon, 20 Oct 2008)

Log Message:
-----------
New volume rendering feature: Light Cache

This was a bit complicated to do, but is working pretty well now, and can make shading significantly faster to render.

This option pre-calculates self-shading information into a 
3d voxel grid before rendering, then uses and interpolates
that data during the main rendering phase, rather than 
calculating shading for each sample. It's an approximation
and isn't as accurate as getting the lighting directly, 
but in many cases it looks very similar and renders much faster.
The voxel grid covers the object's 3D screen-aligned bounding box
so this may not be that useful for large volume regions like a
big range of cloud cover, since you'll need a lot of resolution.

The render time speaks for itself here:
http://mke3.net/blender/devel/rendering/volumetrics/vol_light_cache_interpolation.jpg

The resolution is set in the volume panel - it's the resolution
of one edge of the voxel grid. Keep in mind that the higher the
resolution, the more memory needed, like in fluid sim. The
memory requirements increase with the cube of the edge 
resolution so be careful. I might try and add a little memory 
calculator thing like fluid sim has there later.

The voxels are interpolated using trilinear interpolation - 
here's a comparison image I made during testing:
http://mke3.net/blender/devel/rendering/volumetrics/vol_light_cache_compare.jpg

There might still be a couple of little tweaks I can do to 
improve the visual quality, I'll see.

Modified Paths:
--------------
    branches/sim_physics/source/blender/blenkernel/intern/material.c
    branches/sim_physics/source/blender/blenloader/intern/readfile.c
    branches/sim_physics/source/blender/render/extern/include/RE_shader_ext.h
    branches/sim_physics/source/blender/render/intern/source/shadeinput.c
    branches/sim_physics/source/blender/render/intern/source/volumetric.c
    branches/sim_physics/source/blender/src/buttons_shading.c

Modified: branches/sim_physics/source/blender/blenkernel/intern/material.c
===================================================================
--- branches/sim_physics/source/blender/blenkernel/intern/material.c	2008-10-20 06:39:08 UTC (rev 17126)
+++ branches/sim_physics/source/blender/blenkernel/intern/material.c	2008-10-20 07:08:06 UTC (rev 17127)
@@ -173,6 +173,7 @@
 	ma->vol_absorption = 1.0f;
 	ma->vol_scattering = 1.0f;
 	ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f;
+	ma->vol_precache_resolution = 50;
 	
 	ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RADIO|MA_RAYBIAS|MA_TANGENT_STR;
 

Modified: branches/sim_physics/source/blender/blenloader/intern/readfile.c
===================================================================
--- branches/sim_physics/source/blender/blenloader/intern/readfile.c	2008-10-20 06:39:08 UTC (rev 17126)
+++ branches/sim_physics/source/blender/blenloader/intern/readfile.c	2008-10-20 07:08:06 UTC (rev 17127)
@@ -7895,6 +7895,8 @@
 			}
 			if (ma->vol_density_scale < 0.0001f)
 				ma->vol_density_scale = 1.0f;
+			if (ma->vol_precache_resolution == 0)
+				ma->vol_precache_resolution = 50;
 		}
 		
 		for(tex=main->tex.first; tex; tex= tex->id.next) {

Modified: branches/sim_physics/source/blender/render/extern/include/RE_shader_ext.h
===================================================================
--- branches/sim_physics/source/blender/render/extern/include/RE_shader_ext.h	2008-10-20 06:39:08 UTC (rev 17126)
+++ branches/sim_physics/source/blender/render/extern/include/RE_shader_ext.h	2008-10-20 07:08:06 UTC (rev 17127)
@@ -100,6 +100,7 @@
 	struct StrandRen *strand;
 	struct ObjectInstanceRen *obi;
 	struct ObjectRen *obr;
+	struct Render *re;				/* link back to the Render */
 	int facenr;
 	float facenor[3];				/* copy from face */
 	short flippednor;				/* is facenor flipped? */

Modified: branches/sim_physics/source/blender/render/intern/source/shadeinput.c
===================================================================
--- branches/sim_physics/source/blender/render/intern/source/shadeinput.c	2008-10-20 06:39:08 UTC (rev 17126)
+++ branches/sim_physics/source/blender/render/intern/source/shadeinput.c	2008-10-20 07:08:06 UTC (rev 17127)
@@ -1270,6 +1270,7 @@
 	shi->combinedflag= ~rl->pass_xor;
 	shi->mat_override= rl->mat_override;
 	shi->light_override= rl->light_override;
+	shi->re = &R;
 //	shi->rl= rl;
 	/* note shi.depth==0  means first hit, not raytracing */
 	

Modified: branches/sim_physics/source/blender/render/intern/source/volumetric.c
===================================================================
--- branches/sim_physics/source/blender/render/intern/source/volumetric.c	2008-10-20 06:39:08 UTC (rev 17126)
+++ branches/sim_physics/source/blender/render/intern/source/volumetric.c	2008-10-20 07:08:06 UTC (rev 17127)
@@ -51,6 +51,7 @@
 #include "BKE_main.h"
 
 #include "render_types.h"
+#include "renderdatabase.h"
 #include "pixelshading.h"
 #include "shading.h"
 #include "texture.h"
@@ -61,8 +62,6 @@
 extern struct Render R;
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
-#define PRECACHE_RES	5
-
 static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face)
 {
 	VlakRen *vlr = (VlakRen *)face;
@@ -96,7 +95,7 @@
 /* TODO: Box or sphere intersection types could speed things up */
 static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type, int checkfunc)
 {
-	float maxsize = RE_ray_tree_max_size(R.raytree);
+	float maxsize = RE_ray_tree_max_size(shi->re->raytree);
 	int intersected=0;
 
 	/* TODO: use object's bounding box to calculate max size */
@@ -115,9 +114,9 @@
 	else if (intersect_type == VOL_BOUNDS_SS) isect->faceorig= NULL;
 	
 	if (checkfunc==VOL_IS_BACKFACE)
-		intersected = RE_ray_tree_intersect_check(R.raytree, isect, vol_backface_intersect_check);
+		intersected = RE_ray_tree_intersect_check(shi->re->raytree, isect, vol_backface_intersect_check);
 	else
-		intersected = RE_ray_tree_intersect(R.raytree, isect);
+		intersected = RE_ray_tree_intersect(shi->re->raytree, isect);
 	
 	if(intersected)
 	{
@@ -240,6 +239,82 @@
 	absorb_col[2] = (1.0f - absorb_col[2]) * absorption;
 }
 
+
+static float D(ShadeInput *shi, int rgb, int x, int y, int z)
+{
+	const int res = shi->mat->vol_precache_resolution;
+	CLAMP(x, 0, res-1);
+	CLAMP(y, 0, res-1);
+	CLAMP(y, 0, res-1);
+	return shi->obi->volume_precache[rgb*res*res*res + x*res*res + y*res + z];
+}
+
+inline float lerp(float t, float v1, float v2) {
+	return (1.f - t) * v1 + t * v2;
+}
+
+/* trilinear interpolation */
+static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co)
+{
+	const int res = shi->mat->vol_precache_resolution;
+	float voxx, voxy, voxz;
+	int vx, vy, vz;
+	float dx, dy, dz;
+	float d00, d10, d01, d11, d0, d1, d_final;
+	float bbmin[3], bbmax[3], dim[3];
+	int rgb;
+	
+	if (!shi->obi->volume_precache) return;
+	
+	VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
+	VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
+	VecSubf(dim, bbmax, bbmin);
+	
+	voxx = ((co[0] - bbmin[0]) / dim[0]) * res - 0.5f;
+	voxy = ((co[1] - bbmin[1]) / dim[1]) * res - 0.5f;
+	voxz = ((co[2] - bbmin[2]) / dim[2]) * res - 0.5f;
+	
+	vx = (int)voxx; vy = (int)voxy; vz = (int)voxz;
+	
+	dx = voxx - vx; dy = voxy - vy; dz = voxz - vz;
+	
+	for (rgb=0; rgb < 3; rgb++) {
+		d00 = lerp(dx, D(shi, rgb, vx, vy, vz), 		D(shi, rgb, vx+1, vy, vz));
+		d10 = lerp(dx, D(shi, rgb, vx, vy+1, vz), 		D(shi, rgb, vx+1, vy+1, vz));
+		d01 = lerp(dx, D(shi, rgb, vx, vy, vz+1), 		D(shi, rgb, vx+1, vy, vz+1));
+		d11 = lerp(dx, D(shi, rgb, vx, vy+1, vz+1), 	D(shi, rgb, vx+1, vy+1, vz+1));
+		d0 = lerp(dy, d00, d10);
+		d1 = lerp(dy, d01, d11);
+		d_final = lerp(dz, d0, d1);
+		
+		scatter_col[rgb] = d_final;
+	}
+}
+
+#if 0
+/* no interpolation, not used */
+static void vol_get_precached_scattering_nearest(ShadeInput *shi, float *scatter_col, float *co)
+{
+	const int res = shi->mat->vol_precache_resolution;
+	int x,y,z;
+	float bbmin[3], bbmax[3], dim[3];
+
+	if (!shi->obi->volume_precache) return;
+	
+	VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
+	VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
+	VecSubf(dim, bbmax, bbmin);
+	
+	x = (int)(((co[0] - bbmin[0]) / dim[0]) * res);
+	y = (int)(((co[1] - bbmin[1]) / dim[1]) * res);
+	z = (int)(((co[2] - bbmin[2]) / dim[2]) * res);
+	
+	scatter_col[0] = shi->obi->volume_precache[0*res*res*res + x*res*res + y*res + z];
+	scatter_col[1] = shi->obi->volume_precache[1*res*res*res + x*res*res + y*res + z];
+	scatter_col[2] = shi->obi->volume_precache[2*res*res*res + x*res*res + y*res + z];
+}
+#endif
+
 /* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau.
  * Used in the relationship Transmittance = e^(-attenuation)
  */
@@ -276,7 +351,6 @@
 	VecAddf(step_end, step_sta, step_vec);
 	
 	for (s = 0;  s < nsteps; s++) {
-		
 		if (s > 0)
 			density = vol_get_density(shi, step_sta);
 		
@@ -317,9 +391,9 @@
 		shi->osatex= 0;
 		do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
 	}
-	
+
 	VecMulf(lacol, visifac*lar->energy);
-		
+
 	if (ELEM(lar->type, LA_SUN, LA_HEMI))
 		VECCOPY(lv, lar->vec);
 	VecMulf(lv, -1.0f);
@@ -364,27 +438,27 @@
 	
 	vol_get_scattering_fac(shi, &scatter_fac, co, density);
 	VecMulf(lacol, scatter_fac);
-	
 }
 
 /* single scattering only for now */
-void vol_get_scattering(Render *re, ShadeInput *shi, float *scatter, float *co, float stepsize, float density)
+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};
-	
-	lights= get_lights(shi);
-	for(go=lights->first; go; go= go->next)
+	int i=0;
+
+	for(go=shi->re->lights.first; go; go= go->next)
 	{
 		float lacol[3] = {0.f, 0.f, 0.f};
 	
+		i++;
+	
 		lar= go->lampren;
 		if (lar) {
-		
 			vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density);
-		
+			
 			VecMulf(lacol, density);
 		
 			VecAddf(col, col, lacol);
@@ -415,7 +489,6 @@
 	VecMulVecf(radiance, tr, col);	
 	tr[0] = tr[1] = tr[2] = 1.0f;
 	
-
 	/* ray marching */
 	nsteps = (int)ceil(VecLenf(co, endco) / stepsize);
 	
@@ -447,24 +520,13 @@
 		
 			/* incoming light via emission or scattering (additive) */
 			vol_get_emission(shi, emit_col, step_mid, density);
-			if ((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) && shi->obi->volume_precache) {
-				const int res = shi->mat->vol_precache_resolution;
-				int x,y,z;
-				float bbmin[3], bbmax[3], dim[3];
-								
-				VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
-				VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
-				VecSubf(dim, bbmax, bbmin);
-				
-				x = (int)(((step_mid[0] - bbmin[0]) / dim[0]) * res);
-				y = (int)(((step_mid[1] - bbmin[1]) / dim[1]) * res);
-				z = (int)(((step_mid[2] - bbmin[2]) / dim[2]) * res);
-				
-				scatter_col[0] = scatter_col[1] = scatter_col[2] = shi->obi->volume_precache[x*res*res + y*res + z];
-			}
-			else
-				vol_get_scattering(&R, shi, scatter_col, step_mid, stepsize, density);
 			
+			if ((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) &&
+				(shi->mat->vol_shadeflag & MA_VOL_ATTENUATED)) {
+				vol_get_precached_scattering(shi, scatter_col, step_mid);
+			} else
+				vol_get_scattering(shi, scatter_col, step_mid, stepsize, density);
+			
 			VecAddf(d_radiance, emit_col, scatter_col);
 			
 			/*   Lv += Tr * (Lve() + Ld) */
@@ -544,7 +606,7 @@
 static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *col)
 {
 	Isect isect;
-	float maxsize = RE_ray_tree_max_size(R.raytree);
+	float maxsize = RE_ray_tree_max_size(shi->re->raytree);
 
 	VECCOPY(isect.start, co);
 	isect.end[0] = isect.start[0] + shi->view[0] * maxsize;
@@ -560,7 +622,7 @@
 	isect.lay= -1;
 	
 	/* check to see if there's anything behind the volume, otherwise shade the sky */
-	if(RE_ray_tree_intersect(R.raytree, &isect)) {
+	if(RE_ray_tree_intersect(shi->re->raytree, &isect)) {
 		shade_intersection(shi, col, &isect);
 	} else {
 		shadeSkyView(col, co, shi->view, NULL);
@@ -568,6 +630,7 @@
 	}
 }
 
+/* the main entry point for volume shading */
 void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr)
 {
 	float hitco[3], col[4] = {0.f,0.f,0.f,0.f};
@@ -629,6 +692,8 @@
 	}
 }
 
+/* Traces a shadow through the object, 
+ * pretty much gets the transmission over a ray path */

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list