diff options
Diffstat (limited to 'intern/cycles/kernel/integrator/intersect_volume_stack.h')
-rw-r--r-- | intern/cycles/kernel/integrator/intersect_volume_stack.h | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/intern/cycles/kernel/integrator/intersect_volume_stack.h b/intern/cycles/kernel/integrator/intersect_volume_stack.h new file mode 100644 index 00000000000..1c91318ff9c --- /dev/null +++ b/intern/cycles/kernel/integrator/intersect_volume_stack.h @@ -0,0 +1,206 @@ +/* + * Copyright 2011-2021 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "kernel/bvh/bvh.h" +#include "kernel/geom/geom.h" +#include "kernel/integrator/shader_eval.h" +#include "kernel/integrator/volume_stack.h" + +CCL_NAMESPACE_BEGIN + +ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg, + IntegratorState state, + const float3 from_P, + const float3 to_P) +{ + PROFILING_INIT(kg, PROFILING_INTERSECT_VOLUME_STACK); + + ShaderDataTinyStorage stack_sd_storage; + ccl_private ShaderData *stack_sd = AS_SHADER_DATA(&stack_sd_storage); + + kernel_assert(kernel_data.integrator.use_volumes); + + Ray volume_ray ccl_optional_struct_init; + volume_ray.P = from_P; + volume_ray.D = normalize_len(to_P - from_P, &volume_ray.t); + + /* Store to avoid global fetches on every intersection step. */ + const uint volume_stack_size = kernel_data.volume_stack_size; + +#ifdef __VOLUME_RECORD_ALL__ + Intersection hits[2 * MAX_VOLUME_STACK_SIZE + 1]; + uint num_hits = scene_intersect_volume_all( + kg, &volume_ray, hits, 2 * volume_stack_size, PATH_RAY_ALL_VISIBILITY); + if (num_hits > 0) { + Intersection *isect = hits; + + qsort(hits, num_hits, sizeof(Intersection), intersections_compare); + + for (uint hit = 0; hit < num_hits; ++hit, ++isect) { + shader_setup_from_ray(kg, stack_sd, &volume_ray, isect); + volume_stack_enter_exit(kg, state, stack_sd); + } + } +#else + Intersection isect; + int step = 0; + while (step < 2 * volume_stack_size && + scene_intersect_volume(kg, &volume_ray, &isect, PATH_RAY_ALL_VISIBILITY)) { + shader_setup_from_ray(kg, stack_sd, &volume_ray, &isect); + volume_stack_enter_exit(kg, state, stack_sd); + + /* Move ray forward. */ + volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng); + if (volume_ray.t != FLT_MAX) { + volume_ray.D = normalize_len(to_P - volume_ray.P, &volume_ray.t); + } + ++step; + } +#endif +} + +ccl_device void integrator_intersect_volume_stack(KernelGlobals kg, IntegratorState state) +{ + PROFILING_INIT(kg, PROFILING_INTERSECT_VOLUME_STACK); + + ShaderDataTinyStorage stack_sd_storage; + ccl_private ShaderData *stack_sd = AS_SHADER_DATA(&stack_sd_storage); + + Ray volume_ray ccl_optional_struct_init; + integrator_state_read_ray(kg, state, &volume_ray); + volume_ray.t = FLT_MAX; + + const uint visibility = (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_ALL_VISIBILITY); + int stack_index = 0, enclosed_index = 0; + + /* Write background shader. */ + if (kernel_data.background.volume_shader != SHADER_NONE) { + const VolumeStack new_entry = {OBJECT_NONE, kernel_data.background.volume_shader}; + integrator_state_write_volume_stack(state, stack_index, new_entry); + stack_index++; + } + + /* Store to avoid global fetches on every intersection step. */ + const uint volume_stack_size = kernel_data.volume_stack_size; + +#ifdef __VOLUME_RECORD_ALL__ + Intersection hits[2 * MAX_VOLUME_STACK_SIZE + 1]; + uint num_hits = scene_intersect_volume_all( + kg, &volume_ray, hits, 2 * volume_stack_size, visibility); + if (num_hits > 0) { + int enclosed_volumes[MAX_VOLUME_STACK_SIZE]; + Intersection *isect = hits; + + qsort(hits, num_hits, sizeof(Intersection), intersections_compare); + + for (uint hit = 0; hit < num_hits; ++hit, ++isect) { + shader_setup_from_ray(kg, stack_sd, &volume_ray, isect); + 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] == stack_sd->object) { + need_add = false; + } + } + for (int i = 0; i < stack_index && need_add; ++i) { + /* Don't add intersections twice. */ + VolumeStack entry = integrator_state_read_volume_stack(state, i); + if (entry.object == stack_sd->object) { + need_add = false; + break; + } + } + if (need_add && stack_index < volume_stack_size - 1) { + const VolumeStack new_entry = {stack_sd->object, stack_sd->shader}; + integrator_state_write_volume_stack(state, stack_index, new_entry); + ++stack_index; + } + } + else { + /* If ray from camera enters the volume, this volume shouldn't + * be added to the stack on exit. + */ + enclosed_volumes[enclosed_index++] = stack_sd->object; + } + } + } +#else + /* CUDA does not support definition of a variable size arrays, so use the maximum possible. */ + int enclosed_volumes[MAX_VOLUME_STACK_SIZE]; + int step = 0; + + while (stack_index < volume_stack_size - 1 && enclosed_index < volume_stack_size - 1 && + step < 2 * volume_stack_size) { + Intersection isect; + if (!scene_intersect_volume(kg, &volume_ray, &isect, visibility)) { + break; + } + + shader_setup_from_ray(kg, stack_sd, &volume_ray, &isect); + 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. + */ + 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] == stack_sd->object) { + need_add = false; + } + } + for (int i = 0; i < stack_index && need_add; ++i) { + /* Don't add intersections twice. */ + VolumeStack entry = integrator_state_read_volume_stack(state, i); + if (entry.object == stack_sd->object) { + need_add = false; + break; + } + } + if (need_add) { + const VolumeStack new_entry = {stack_sd->object, stack_sd->shader}; + integrator_state_write_volume_stack(state, stack_index, new_entry); + ++stack_index; + } + } + else { + /* If ray from camera enters the volume, this volume shouldn't + * be added to the stack on exit. + */ + enclosed_volumes[enclosed_index++] = stack_sd->object; + } + + /* Move ray forward. */ + volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng); + ++step; + } +#endif + + /* Write terminator. */ + const VolumeStack new_entry = {OBJECT_NONE, SHADER_NONE}; + integrator_state_write_volume_stack(state, stack_index, new_entry); + + INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK, + DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST); +} + +CCL_NAMESPACE_END |