[Bf-blender-cvs] [75eea19] openvdb: Cycles: first pass at using VDB ray intersectors for ray marching.

Kévin Dietrich noreply at git.blender.org
Fri Jun 5 22:25:01 CEST 2015


Commit: 75eea19d026028fccc62455bb2001eac2c8b1e17
Author: Kévin Dietrich
Date:   Fri Jun 5 17:42:55 2015 +0200
Branches: openvdb
https://developer.blender.org/rB75eea19d026028fccc62455bb2001eac2c8b1e17

Cycles: first pass at using VDB ray intersectors for ray marching.

The idea behind them is to avoid unnecessary ray marching by frog
leaping empty space. The only requirement for it to work is to have a
grid whose voxels are uniform, otherwise Cycles' default ray marching is
used.

For now the code has a some issues and dark sides to it:
- it only works if there is a single object containing vdb volumes in
the scene
- for a given file, only the grid named "density" (case insensitive) is
used for intersection, it's not clear how to handle multiple grids in
this case (maybe we coiuld let the user set which one to use?)
- the ray march loop is a total duplicate of the default one, this will
be addressed later on
- some leaf nodes are missing when using large volumes, the issue might
be the early exit due to the check to see if light was totally absorbed
or not

Here's some render tests:
Dense volume: http://www.pasteall.org/pic/89090
VDB with intersection: http://www.pasteall.org/pic/89092

===================================================================

M	intern/cycles/kernel/kernel_types.h
M	intern/cycles/kernel/kernel_volume.h
M	intern/cycles/render/openvdb.cpp
M	intern/cycles/render/openvdb.h
M	intern/cycles/util/util_openvdb.h

===================================================================

diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 31fdce2..66413d0 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -964,7 +964,7 @@ typedef struct KernelCurves {
 typedef struct KernelTables {
 	int beckmann_offset;
 	int num_volumes;
-	int pad1, pad2;
+	int density_index, pad2;
 } KernelTables;
 
 typedef struct KernelData {
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index e065684..8b84f8d 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -436,7 +436,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
 	float random_jitter_offset = lcg_step_float(&state->rng_congruential) * step_size;
 
 	/* compute coefficients at the start */
-	float t = 0.0f;
+	float t = 0.0f, t1 = 0.0f;
 	float3 accum_transmittance = make_float3(1.0f, 1.0f, 1.0f);
 
 	/* pick random color channel, we use the Veach one-sample
@@ -446,113 +446,234 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
 	int channel = (int)(rphase*3.0f);
 	sd->randb_closure = rphase*3.0f - channel;
 	bool has_scatter = false;
+	int vdb_index = kernel_data.tables.density_index;
+	bool has_vdb_volume = kernel_data.tables.num_volumes > 0;
+	bool path_missed = true;
+
+	if(has_vdb_volume && kg->float_volumes[vdb_index]->has_uniform_voxels()) {
+		/* TODO(kevin): this call should be moved out of here, all it does is
+		 * checking if we have an intersection with the boundbox of the volumue
+		 * which in most cases corresponds to the boundbox of the object that has
+		 * this volume. Also it initializes the rays for the ray marching. */
+		if(!kg->float_volumes[vdb_index]->intersect(ray, NULL)) {
+			return VOLUME_PATH_MISSED;
+		}
 
-	for(int i = 0; i < max_steps; i++) {
-		/* advance to new position */
-		float new_t = min(ray->t, (i+1) * step_size);
-		float dt = new_t - t;
+		/* t and t1 represent the entry and exit points for each leaf node or tile
+		 * containing active voxels. If we don't have any active node in the current
+		 * ray path (i.e. empty space) the ray march loop is not executed,
+		 * otherwise we loop through all leaves until the end of the volume. */
+		while(kg->float_volumes[vdb_index]->march(&t, &t1)) {
+			path_missed = false;
 
-		/* use random position inside this segment to sample shader */
-		if(new_t == ray->t)
-			random_jitter_offset = lcg_step_float(&state->rng_congruential) * dt;
+			/* Perform small steps through the current leaf or tile. */
+			for(float new_t = step_size * ceilf(t / step_size); new_t <= t1; new_t += step_size) {
+				float dt = new_t - t;
 
-		float3 new_P = ray->P + ray->D * (t + random_jitter_offset);
-		VolumeShaderCoefficients coeff;
+				/* use random position inside this segment to sample shader */
+				if(new_t == ray->t)
+					random_jitter_offset = lcg_step_float(&state->rng_congruential) * dt;
 
-		/* compute segment */
-		if(volume_shader_sample(kg, sd, state, new_P, &coeff)) {
-			int closure_flag = sd->flag;
-			float3 new_tp;
-			float3 transmittance;
-			bool scatter = false;
+				float3 new_P = ray->P + ray->D * (t + random_jitter_offset);
+				VolumeShaderCoefficients coeff;
 
-			/* distance sampling */
+				/* compute segment */
+				if(volume_shader_sample(kg, sd, state, new_P, &coeff)) {
+					int closure_flag = sd->flag;
+					float3 new_tp;
+					float3 transmittance;
+					bool scatter = false;
+
+					/* distance sampling */
 #ifdef __VOLUME_SCATTER__
-			if((closure_flag & SD_SCATTER) || (has_scatter && (closure_flag & SD_ABSORPTION))) {
-				has_scatter = true;
+					if((closure_flag & SD_SCATTER) || (has_scatter && (closure_flag & SD_ABSORPTION))) {
+						has_scatter = true;
+
+						float3 sigma_t = coeff.sigma_a + coeff.sigma_s;
+						float3 sigma_s = coeff.sigma_s;
+
+						/* compute transmittance over full step */
+						transmittance = volume_color_transmittance(sigma_t, dt);
+
+						/* decide if we will scatter or continue */
+						float sample_transmittance = kernel_volume_channel_get(transmittance, channel);
+
+						if(1.0f - xi >= sample_transmittance) {
+							/* compute sampling distance */
+							float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel);
+							float new_dt = -logf(1.0f - xi)/sample_sigma_t;
+							new_t = t + new_dt;
+
+							/* transmittance and pdf */
+							float3 new_transmittance = volume_color_transmittance(sigma_t, new_dt);
+							float3 pdf = sigma_t * new_transmittance;
+
+							/* throughput */
+							new_tp = tp * sigma_s * new_transmittance / average(pdf);
+							scatter = true;
+						}
+						else {
+							/* throughput */
+							float pdf = average(transmittance);
+							new_tp = tp * transmittance / pdf;
+
+							/* remap xi so we can reuse it and keep thing stratified */
+							xi = 1.0f - (1.0f - xi)/sample_transmittance;
+						}
+					}
+					else
+#endif
+						if(closure_flag & SD_ABSORPTION) {
+							/* absorption only, no sampling needed */
+							float3 sigma_a = coeff.sigma_a;
+
+							transmittance = volume_color_transmittance(sigma_a, dt);
+							new_tp = tp * transmittance;
+						}
+
+					/* integrate emission attenuated by absorption */
+					if(L && (closure_flag & SD_EMISSION)) {
+						float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, dt);
+						path_radiance_accum_emission(L, tp, emission, state->bounce);
+					}
 
-				float3 sigma_t = coeff.sigma_a + coeff.sigma_s;
-				float3 sigma_s = coeff.sigma_s;
+					/* modify throughput */
+					if(closure_flag & (SD_ABSORPTION|SD_SCATTER)) {
+						tp = new_tp;
 
-				/* compute transmittance over full step */
-				transmittance = volume_color_transmittance(sigma_t, dt);
+						/* stop if nearly all light blocked */
+						if(tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps) {
+							tp = make_float3(0.0f, 0.0f, 0.0f);
+							break;
+						}
+					}
 
-				/* decide if we will scatter or continue */
-				float sample_transmittance = kernel_volume_channel_get(transmittance, channel);
+					/* prepare to scatter to new direction */
+					if(scatter) {
+						/* adjust throughput and move to new location */
+						sd->P = ray->P + new_t*ray->D;
+						*throughput = tp;
 
-				if(1.0f - xi >= sample_transmittance) {
-					/* compute sampling distance */
-					float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel);
-					float new_dt = -logf(1.0f - xi)/sample_sigma_t;
-					new_t = t + new_dt;
+						return VOLUME_PATH_SCATTERED;
+					}
+					else {
+						/* accumulate transmittance */
+						accum_transmittance *= transmittance;
+					}
+				}
 
-					/* transmittance and pdf */
-					float3 new_transmittance = volume_color_transmittance(sigma_t, new_dt);
-					float3 pdf = sigma_t * new_transmittance;
+				t = new_t;
+			}
+		}
+	}
+	else {
+		for (int i = 0; i < max_steps; i++) {
+			/* advance to new position */
+			float new_t = min(ray->t, (i+1) * step_size);
+			float dt = new_t - t;
+
+			/* use random position inside this segment to sample shader */
+			if(new_t == ray->t)
+				random_jitter_offset = lcg_step_float(&state->rng_congruential) * dt;
+
+			float3 new_P = ray->P + ray->D * (t + random_jitter_offset);
+			VolumeShaderCoefficients coeff;
+
+			/* compute segment */
+			if(volume_shader_sample(kg, sd, state, new_P, &coeff)) {
+				int closure_flag = sd->flag;
+				float3 new_tp;
+				float3 transmittance;
+				bool scatter = false;
+
+				/* distance sampling */
+		#ifdef __VOLUME_SCATTER__
+				if((closure_flag & SD_SCATTER) || (has_scatter && (closure_flag & SD_ABSORPTION))) {
+					has_scatter = true;
+
+					float3 sigma_t = coeff.sigma_a + coeff.sigma_s;
+					float3 sigma_s = coeff.sigma_s;
+
+					/* compute transmittance over full step */
+					transmittance = volume_color_transmittance(sigma_t, dt);
+
+					/* decide if we will scatter or continue */
+					float sample_transmittance = kernel_volume_channel_get(transmittance, channel);
+
+					if(1.0f - xi >= sample_transmittance) {
+						/* compute sampling distance */
+						float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel);
+						float new_dt = -logf(1.0f - xi)/sample_sigma_t;
+						new_t = t + new_dt;
+
+						/* transmittance and pdf */
+						float3 new_transmittance = volume_color_transmittance(sigma_t, new_dt);
+						float3 pdf = sigma_t * new_transmittance;
+
+						/* throughput */
+						new_tp = tp * sigma_s * new_transmittance / average(pdf);
+						scatter = true;
+					}
+					else {
+						/* throughput */
+						float pdf = average(transmittance);
+						new_tp = tp * transmittance / pdf;
 
-					/* throughput */
-					new_tp = tp * sigma_s * new_transmittance / average(pdf);
-					scatter = true;
+						/* remap xi so we can reuse it and keep thing stratified */
+						xi = 1.0f - (1.0f - xi)/sample_transmittance;
+					}
 				}
-				else {
-					/* throughput */
-					float pdf = average(transmittance);
-					new_tp = tp * transmittance / pdf;
+				else
+		#endif
+					if(closure_flag & SD_ABSORPTION) {
+						/* absorption only, no sampling needed */
+						float3 sigma_a = coeff.sigma_a;
+
+						transmittance = volume_color_transmittance(sigma_a, dt);
+						new_tp = tp * transmittance;
+					}
 
-					/* remap xi so we can reuse it and keep thing stratified */
-					xi = 1.0f - (1.0f - xi)/sample_transmittance;
+				/* integrate emission attenuated by absorption */
+				if(L && (closure_flag & SD_EMISSION)) {
+					float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, dt);
+					path_radiance_accum_emission(L, tp, emission, state->bounce);
 				}
-			}
-			else 
-#endif
-			if(closure_flag & SD_ABSORPTION) {
-				/* absorption only, no sampling needed */
-				float3 sigma_a = coeff.sigma_a;
 
-				transmittance = volume_color_transmittance(sigma_a, dt);
-				new_tp = tp * transmittance;
-			}
+				/* modify throughput */
+				if(closure_flag & (SD_ABSORPTION|SD_SCATTER)) {
+					tp = new_tp;
 
-			/* integrate emission attenuated by absorption */
-			if(L && (closure_flag & SD_EMISSION)) {
-				float3 emission = kernel_volume_emissi

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list