Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/kernel/kernel_volume.h')
-rw-r--r--intern/cycles/kernel/kernel_volume.h131
1 files changed, 88 insertions, 43 deletions
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index c69ed9bc862..f0e9b68a9a4 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -37,7 +37,11 @@ typedef struct VolumeShaderCoefficients {
} VolumeShaderCoefficients;
/* evaluate shader to get extinction coefficient at P */
-ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *sd, PathState *state, float3 P, float3 *extinction)
+ccl_device_inline bool volume_shader_extinction_sample(KernelGlobals *kg,
+ ShaderData *sd,
+ PathState *state,
+ float3 P,
+ float3 *extinction)
{
sd->P = P;
shader_eval_volume(kg, sd, state, state->volume_stack, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
@@ -59,7 +63,11 @@ ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *s
}
/* evaluate shader to get absorption, scattering and emission at P */
-ccl_device bool volume_shader_sample(KernelGlobals *kg, ShaderData *sd, PathState *state, float3 P, VolumeShaderCoefficients *coeff)
+ccl_device_inline bool volume_shader_sample(KernelGlobals *kg,
+ ShaderData *sd,
+ PathState *state,
+ float3 P,
+ VolumeShaderCoefficients *coeff)
{
sd->P = P;
shader_eval_volume(kg, sd, state, state->volume_stack, state->flag, SHADER_CONTEXT_VOLUME);
@@ -108,7 +116,7 @@ ccl_device float kernel_volume_channel_get(float3 value, int channel)
ccl_device bool volume_stack_is_heterogeneous(KernelGlobals *kg, VolumeStack *stack)
{
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
- int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*2);
+ int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
if(shader_flag & SD_HETEROGENEOUS_VOLUME)
return true;
@@ -125,7 +133,7 @@ ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stac
int method = -1;
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
- int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*2);
+ int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
if(shader_flag & SD_VOLUME_MIS) {
return SD_VOLUME_MIS;
@@ -276,15 +284,14 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, PathState
/* get the volume attenuation over line segment defined by ray, with the
* assumption that there are no surfaces blocking light between the endpoints */
-ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, PathState *state, Ray *ray, float3 *throughput)
+ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, ShaderData *shadow_sd, PathState *state, Ray *ray, float3 *throughput)
{
- ShaderData sd;
- shader_setup_from_volume(kg, &sd, ray);
+ shader_setup_from_volume(kg, shadow_sd, ray);
if(volume_stack_is_heterogeneous(kg, state->volume_stack))
- kernel_volume_shadow_heterogeneous(kg, state, ray, &sd, throughput);
+ kernel_volume_shadow_heterogeneous(kg, state, ray, shadow_sd, throughput);
else
- kernel_volume_shadow_homogeneous(kg, state, ray, &sd, throughput);
+ kernel_volume_shadow_homogeneous(kg, state, ray, shadow_sd, throughput);
}
/* Equi-angular sampling as in:
@@ -334,7 +341,7 @@ ccl_device float kernel_volume_distance_sample(float max_t, float3 sigma_t, int
float sample_t = min(max_t, -logf(1.0f - xi*(1.0f - sample_transmittance))/sample_sigma_t);
*transmittance = volume_color_transmittance(sigma_t, sample_t);
- *pdf = (sigma_t * *transmittance)/(make_float3(1.0f, 1.0f, 1.0f) - full_transmittance);
+ *pdf = safe_divide_color(sigma_t * *transmittance, make_float3(1.0f, 1.0f, 1.0f) - full_transmittance);
/* todo: optimization: when taken together with hit/miss decision,
* the full_transmittance cancels out drops out and xi does not
@@ -348,7 +355,7 @@ ccl_device float3 kernel_volume_distance_pdf(float max_t, float3 sigma_t, float
float3 full_transmittance = volume_color_transmittance(sigma_t, max_t);
float3 transmittance = volume_color_transmittance(sigma_t, sample_t);
- return (sigma_t * transmittance)/(make_float3(1.0f, 1.0f, 1.0f) - full_transmittance);
+ return safe_divide_color(sigma_t * transmittance, make_float3(1.0f, 1.0f, 1.0f) - full_transmittance);
}
/* Emission */
@@ -742,12 +749,36 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
const int global_max_steps = kernel_data.integrator.volume_max_steps;
step_size = kernel_data.integrator.volume_step_size;
/* compute exact steps in advance for malloc */
- max_steps = max((int)ceilf(ray->t/step_size), 1);
- if(max_steps > global_max_steps) {
+ if(ray->t > global_max_steps*step_size) {
max_steps = global_max_steps;
step_size = ray->t / (float)max_steps;
}
+ else {
+ max_steps = max((int)ceilf(ray->t/step_size), 1);
+ }
+#ifdef __KERNEL_CPU__
+ /* NOTE: For the branched path tracing it's possible to have direct
+ * and indirect light integration both having volume segments allocated.
+ * We detect this using index in the pre-allocated memory. Currently we
+ * only support two segments allocated at a time, if more needed some
+ * modifications to the KernelGlobals will be needed.
+ *
+ * This gives us restrictions that decoupled record should only happen
+ * in the stack manner, meaning if there's subsequent call of decoupled
+ * record it'll need to free memory before it's caller frees memory.
+ */
+ const int index = kg->decoupled_volume_steps_index;
+ assert(index < sizeof(kg->decoupled_volume_steps) /
+ sizeof(*kg->decoupled_volume_steps));
+ if(kg->decoupled_volume_steps[index] == NULL) {
+ kg->decoupled_volume_steps[index] =
+ (VolumeStep*)malloc(sizeof(VolumeStep)*global_max_steps);
+ }
+ segment->steps = kg->decoupled_volume_steps[index];
+ ++kg->decoupled_volume_steps_index;
+#else
segment->steps = (VolumeStep*)malloc(sizeof(VolumeStep)*max_steps);
+#endif
random_jitter_offset = lcg_step_float(&state->rng_congruential) * step_size;
}
else {
@@ -961,8 +992,18 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta
ccl_device void kernel_volume_decoupled_free(KernelGlobals *kg, VolumeSegment *segment)
{
- if(segment->steps != &segment->stack_step)
+ if(segment->steps != &segment->stack_step) {
+#ifdef __KERNEL_CPU__
+ /* NOTE: We only allow free last allocated segment.
+ * No random order of alloc/free is supported.
+ */
+ assert(kg->decoupled_volume_steps_index > 0);
+ assert(segment->steps == kg->decoupled_volume_steps[kg->decoupled_volume_steps_index - 1]);
+ --kg->decoupled_volume_steps_index;
+#else
free(segment->steps);
+#endif
+ }
}
/* scattering for homogeneous and heterogeneous volumes, using decoupled ray
@@ -1184,7 +1225,9 @@ ccl_device bool kernel_volume_use_decoupled(KernelGlobals *kg, bool heterogeneou
* is inside of. */
ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
- Ray *ray,
+ ShaderData *stack_sd,
+ const PathState *state,
+ const Ray *ray,
VolumeStack *stack)
{
/* NULL ray happens in the baker, does it need proper initialization of
@@ -1205,14 +1248,16 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
return;
}
+ kernel_assert(state->flag & PATH_RAY_CAMERA);
+
Ray volume_ray = *ray;
volume_ray.t = FLT_MAX;
+ const uint visibility = (state->flag & PATH_RAY_ALL_VISIBILITY);
int stack_index = 0, enclosed_index = 0;
- const uint visibility = PATH_RAY_ALL_VISIBILITY | kernel_data.integrator.layer_flag;
#ifdef __VOLUME_RECORD_ALL__
- Intersection hits[2*VOLUME_STACK_SIZE];
+ Intersection hits[2*VOLUME_STACK_SIZE + 1];
uint num_hits = scene_intersect_volume_all(kg,
&volume_ray,
hits,
@@ -1225,28 +1270,27 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, &volume_ray);
- if(sd.flag & SD_BACKFACING) {
+ shader_setup_from_ray(kg, stack_sd, isect, &volume_ray);
+ if(stack_sd->flag & SD_BACKFACING) {
bool need_add = true;
for(int i = 0; i < enclosed_index && need_add; ++i) {
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
- if(enclosed_volumes[i] == sd.object) {
+ if(enclosed_volumes[i] == stack_sd->object) {
need_add = false;
}
}
for(int i = 0; i < stack_index && need_add; ++i) {
/* Don't add intersections twice. */
- if(stack[i].object == sd.object) {
+ if(stack[i].object == stack_sd->object) {
need_add = false;
break;
}
}
if(need_add) {
- stack[stack_index].object = sd.object;
- stack[stack_index].shader = sd.shader;
+ stack[stack_index].object = stack_sd->object;
+ stack[stack_index].shader = stack_sd->shader;
++stack_index;
}
}
@@ -1254,7 +1298,7 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
/* If ray from camera enters the volume, this volume shouldn't
* be added to the stack on exit.
*/
- enclosed_volumes[enclosed_index++] = sd.object;
+ enclosed_volumes[enclosed_index++] = stack_sd->object;
}
}
}
@@ -1271,9 +1315,8 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
break;
}
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &volume_ray);
- if(sd.flag & SD_BACKFACING) {
+ shader_setup_from_ray(kg, stack_sd, &isect, &volume_ray);
+ if(stack_sd->flag & SD_BACKFACING) {
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
@@ -1282,20 +1325,20 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
- if(enclosed_volumes[i] == sd.object) {
+ if(enclosed_volumes[i] == stack_sd->object) {
need_add = false;
}
}
for(int i = 0; i < stack_index && need_add; ++i) {
/* Don't add intersections twice. */
- if(stack[i].object == sd.object) {
+ if(stack[i].object == stack_sd->object) {
need_add = false;
break;
}
}
if(need_add) {
- stack[stack_index].object = sd.object;
- stack[stack_index].shader = sd.shader;
+ stack[stack_index].object = stack_sd->object;
+ stack[stack_index].shader = stack_sd->shader;
++stack_index;
}
}
@@ -1303,11 +1346,11 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
/* If ray from camera enters the volume, this volume shouldn't
* be added to the stack on exit.
*/
- enclosed_volumes[enclosed_index++] = sd.object;
+ enclosed_volumes[enclosed_index++] = stack_sd->object;
}
/* Move ray forward. */
- volume_ray.P = ray_offset(sd.P, -sd.Ng);
+ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
++step;
}
#endif
@@ -1375,6 +1418,7 @@ ccl_device void kernel_volume_stack_enter_exit(KernelGlobals *kg, ShaderData *sd
#ifdef __SUBSURFACE__
ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
+ ShaderData *stack_sd,
Ray *ray,
VolumeStack *stack)
{
@@ -1383,7 +1427,7 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
Ray volume_ray = *ray;
# ifdef __VOLUME_RECORD_ALL__
- Intersection hits[2*VOLUME_STACK_SIZE];
+ Intersection hits[2*VOLUME_STACK_SIZE + 1];
uint num_hits = scene_intersect_volume_all(kg,
&volume_ray,
hits,
@@ -1395,27 +1439,28 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, &volume_ray);
- kernel_volume_stack_enter_exit(kg, &sd, stack);
+ shader_setup_from_ray(kg, stack_sd, isect, &volume_ray);
+ kernel_volume_stack_enter_exit(kg, stack_sd, stack);
}
}
# else
Intersection isect;
int step = 0;
+ float3 Pend = ray->P + ray->D*ray->t;
while(step < 2 * VOLUME_STACK_SIZE &&
scene_intersect_volume(kg,
&volume_ray,
&isect,
PATH_RAY_ALL_VISIBILITY))
{
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &volume_ray);
- kernel_volume_stack_enter_exit(kg, &sd, stack);
+ shader_setup_from_ray(kg, stack_sd, &isect, &volume_ray);
+ kernel_volume_stack_enter_exit(kg, stack_sd, stack);
/* Move ray forward. */
- volume_ray.P = ray_offset(sd.P, -sd.Ng);
- volume_ray.t -= sd.ray_length;
+ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
+ if(volume_ray.t != FLT_MAX) {
+ volume_ray.D = normalize_len(Pend - volume_ray.P, &volume_ray.t);
+ }
++step;
}
# endif