Blender V5.0
intersect_volume_stack.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "kernel/bvh/bvh.h"
8
10
13
15
18 const float3 from_P,
19 const float3 to_P)
20{
21#ifdef __VOLUME__
23
24 ShaderDataTinyStorage stack_sd_storage;
25 ccl_private ShaderData *stack_sd = AS_SHADER_DATA(&stack_sd_storage);
26
27 kernel_assert(kernel_data.integrator.use_volumes);
28
30 volume_ray.P = from_P;
31 volume_ray.D = safe_normalize_len(to_P - from_P, &volume_ray.tmax);
32 volume_ray.tmin = 0.0f;
33 volume_ray.self.object = INTEGRATOR_STATE(state, isect, object);
34 volume_ray.self.prim = INTEGRATOR_STATE(state, isect, prim);
35 volume_ray.self.light_object = OBJECT_NONE;
36 volume_ray.self.light_prim = PRIM_NONE;
37 /* Store to avoid global fetches on every intersection step. */
38 const uint volume_stack_size = kernel_data.volume_stack_size;
39
40 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
41 const uint32_t visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, PATH_RAY_ALL_VISIBILITY);
42
43# ifdef __VOLUME_RECORD_ALL__
45 const uint num_hits = scene_intersect_volume(
46 kg, &volume_ray, hits, 2 * volume_stack_size, visibility);
47 if (num_hits > 0) {
48 Intersection *isect = hits;
49
50 qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
51
52 for (uint hit = 0; hit < num_hits; ++hit, ++isect) {
53 /* Ignore self, SSS itself already enters and exits the object. */
54 if (isect->object == volume_ray.self.object) {
55 continue;
56 }
57 shader_setup_from_ray(kg, stack_sd, &volume_ray, isect);
58 volume_stack_enter_exit<false>(kg, state, stack_sd);
59 }
60 }
61# else
62 Intersection isect;
63 int step = 0;
64 while (step < 2 * volume_stack_size &&
65 scene_intersect_volume(kg, &volume_ray, &isect, visibility))
66 {
67 /* Ignore self, SSS itself already enters and exits the object. */
68 if (isect.object != volume_ray.self.object) {
69 shader_setup_from_ray(kg, stack_sd, &volume_ray, &isect);
70 volume_stack_enter_exit<false>(kg, state, stack_sd);
71 }
72 /* Move ray forward. */
73 volume_ray.tmin = intersection_t_offset(isect.t);
74 volume_ray.self.object = isect.object;
75 volume_ray.self.prim = isect.prim;
76 ++step;
77 }
78# endif
79}
80
81ccl_device void integrator_volume_stack_init(KernelGlobals kg, IntegratorState state)
82{
84
85 ShaderDataTinyStorage stack_sd_storage;
86 ccl_private ShaderData *stack_sd = AS_SHADER_DATA(&stack_sd_storage);
87
89 integrator_state_read_ray(state, &volume_ray);
90
91 /* Trace ray in random direction. Any direction works, Z up is a guess to get the
92 * fewest hits. */
93 volume_ray.D = make_float3(0.0f, 0.0f, 1.0f);
94 volume_ray.tmin = 0.0f;
95 volume_ray.tmax = FLT_MAX;
96 volume_ray.self.object = OBJECT_NONE;
97 volume_ray.self.prim = PRIM_NONE;
98 volume_ray.self.light_object = OBJECT_NONE;
99 volume_ray.self.light_prim = PRIM_NONE;
100
101 int stack_index = 0;
102 int enclosed_index = 0;
103
104 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
105 const uint32_t visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, PATH_RAY_CAMERA);
106
107 /* Initialize volume stack with background volume For shadow catcher the
108 * background volume is always assumed to be CG. */
109 if (kernel_data.background.volume_shader != SHADER_NONE) {
110 if (!(path_flag & PATH_RAY_SHADOW_CATCHER_PASS)) {
112 state, volume_stack, stack_index, object) = kernel_data.background.object_index;
114 state, volume_stack, stack_index, shader) = kernel_data.background.volume_shader;
115 stack_index++;
116 }
117 }
118
119 /* Store to avoid global fetches on every intersection step. */
120 const uint volume_stack_size = kernel_data.volume_stack_size;
121
122# ifdef __VOLUME_RECORD_ALL__
124 const uint num_hits = scene_intersect_volume(
125 kg, &volume_ray, hits, 2 * volume_stack_size, visibility);
126 if (num_hits > 0) {
127 int enclosed_volumes[MAX_VOLUME_STACK_SIZE];
128 Intersection *isect = hits;
129
130 qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
131
132 for (uint hit = 0; hit < num_hits; ++hit, ++isect) {
133 shader_setup_from_ray(kg, stack_sd, &volume_ray, isect);
134 if (stack_sd->flag & SD_BACKFACING) {
135 bool need_add = true;
136 for (int i = 0; i < enclosed_index && need_add; ++i) {
137 /* If ray exited the volume and never entered to that volume
138 * it means that camera is inside such a volume.
139 */
140 if (enclosed_volumes[i] == stack_sd->object) {
141 need_add = false;
142 }
143 }
144 for (int i = 0; i < stack_index && need_add; ++i) {
145 /* Don't add intersections twice. */
146 const VolumeStack entry = integrator_state_read_volume_stack(state, i);
147 if (entry.object == stack_sd->object) {
148 need_add = false;
149 break;
150 }
151 }
152 if (need_add && stack_index < volume_stack_size - 1) {
153 const VolumeStack new_entry = {stack_sd->object, stack_sd->shader};
154 integrator_state_write_volume_stack(state, stack_index, new_entry);
155 ++stack_index;
156 }
157 }
158 else {
159 /* If ray from camera enters the volume, this volume shouldn't
160 * be added to the stack on exit.
161 */
162 enclosed_volumes[enclosed_index++] = stack_sd->object;
163 }
164 }
165 }
166# else
167 /* CUDA does not support definition of a variable size arrays, so use the maximum possible. */
168 int enclosed_volumes[MAX_VOLUME_STACK_SIZE];
169 int step = 0;
170
171 while (stack_index < volume_stack_size - 1 && enclosed_index < MAX_VOLUME_STACK_SIZE - 1 &&
172 step < 2 * volume_stack_size)
173 {
174 Intersection isect;
175 if (!scene_intersect_volume(kg, &volume_ray, &isect, visibility)) {
176 break;
177 }
178
179 shader_setup_from_ray(kg, stack_sd, &volume_ray, &isect);
180 if (stack_sd->flag & SD_BACKFACING) {
181 /* If ray exited the volume and never entered to that volume
182 * it means that camera is inside such a volume.
183 */
184 bool need_add = true;
185 for (int i = 0; i < enclosed_index && need_add; ++i) {
186 /* If ray exited the volume and never entered to that volume
187 * it means that camera is inside such a volume.
188 */
189 if (enclosed_volumes[i] == stack_sd->object) {
190 need_add = false;
191 }
192 }
193 for (int i = 0; i < stack_index && need_add; ++i) {
194 /* Don't add intersections twice. */
195 VolumeStack entry = integrator_state_read_volume_stack(state, i);
196 if (entry.object == stack_sd->object) {
197 need_add = false;
198 break;
199 }
200 }
201 if (need_add) {
202 const VolumeStack new_entry = {stack_sd->object, stack_sd->shader};
203 integrator_state_write_volume_stack(state, stack_index, new_entry);
204 ++stack_index;
205 }
206 }
207 else {
208 /* If ray from camera enters the volume, this volume shouldn't
209 * be added to the stack on exit.
210 */
211 enclosed_volumes[enclosed_index++] = stack_sd->object;
212 }
213
214 /* Move ray forward. */
215 volume_ray.tmin = intersection_t_offset(isect.t);
216 volume_ray.self.object = isect.object;
217 volume_ray.self.prim = isect.prim;
218 ++step;
219 }
220# endif
221
222 /* Write terminator. */
223 const VolumeStack new_entry = {OBJECT_NONE, SHADER_NONE};
224 integrator_state_write_volume_stack(state, stack_index, new_entry);
225#endif
226}
227
229{
230#ifdef __VOLUME__
231 integrator_volume_stack_init(kg, state);
232
233# ifdef __SHADOW_CATCHER__
235 /* Volume stack re-init for shadow catcher, continue with shading of hit. */
236 integrator_intersect_next_kernel_after_shadow_catcher_volume<
238 }
239 else
240# endif
241 {
242 /* Volume stack init for camera rays, continue with intersection of camera ray. */
246 }
247#endif
248}
249
unsigned int uint
ccl_device_forceinline float intersection_t_offset(const float t)
ccl_device int intersections_compare(const void *a, const void *b)
#define kernel_assert(cond)
#define kernel_data
#define MAX_VOLUME_STACK_SIZE
#define ccl_optional_struct_init
#define AS_SHADER_DATA(shader_data_tiny_storage)
#define SHADER_NONE
#define PRIM_NONE
#define OBJECT_NONE
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility)
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
ccl_device void integrator_intersect_volume_stack(KernelGlobals kg, IntegratorState state)
CCL_NAMESPACE_BEGIN ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg, IntegratorState state, const float3 from_P, const float3 to_P)
@ SD_BACKFACING
ShaderData ShaderDataTinyStorage
@ PATH_RAY_SHADOW_CATCHER_PASS
@ PATH_RAY_ALL_VISIBILITY
@ PATH_RAY_CAMERA
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST
ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t)
static ulong state[N]
#define PROFILING_INIT(kg, event)
@ PROFILING_INTERSECT_VOLUME_STACK
Definition profiling.h:22
#define ccl_device
ccl_device_inline void shader_setup_from_ray(KernelGlobals kg, ccl_private ShaderData *ccl_restrict sd, const ccl_private Ray *ccl_restrict ray, const ccl_private Intersection *ccl_restrict isect)
Definition shader_data.h:39
#define INTEGRATOR_STATE_ARRAY_WRITE(state, nested_struct, array_index, member)
Definition state.h:240
#define INTEGRATOR_STATE(state, nested_struct, member)
Definition state.h:235
IntegratorStateCPU * IntegratorState
Definition state.h:228
ccl_device_forceinline void integrator_path_next(IntegratorState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel)
Definition state_flow.h:195
ccl_device_forceinline void integrator_state_read_ray(ConstIntegratorState state, ccl_private Ray *ccl_restrict ray)
Definition state_util.h:55
#define FLT_MAX
Definition stdcycles.h:14
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:145