This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/intern/cycles/kernel/integrator/intersect_volume_stack.h

211 lines
7.3 KiB
C++

/*
* 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);
/* Trace ray in random direction. Any direction works, Z up is a guess to get the
* fewest hits. */
volume_ray.D = make_float3(0.0f, 0.0f, 1.0f);
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 < MAX_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