Blender V4.5
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(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(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)) {
111 INTEGRATOR_STATE_ARRAY_WRITE(state, volume_stack, stack_index, object) = OBJECT_NONE;
113 state, volume_stack, stack_index, shader) = kernel_data.background.volume_shader;
114 stack_index++;
115 }
116 }
117
118 /* Store to avoid global fetches on every intersection step. */
119 const uint volume_stack_size = kernel_data.volume_stack_size;
120
121# ifdef __VOLUME_RECORD_ALL__
123 const uint num_hits = scene_intersect_volume(
124 kg, &volume_ray, hits, 2 * volume_stack_size, visibility);
125 if (num_hits > 0) {
126 int enclosed_volumes[MAX_VOLUME_STACK_SIZE];
127 Intersection *isect = hits;
128
129 qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
130
131 for (uint hit = 0; hit < num_hits; ++hit, ++isect) {
132 shader_setup_from_ray(kg, stack_sd, &volume_ray, isect);
133 if (stack_sd->flag & SD_BACKFACING) {
134 bool need_add = true;
135 for (int i = 0; i < enclosed_index && need_add; ++i) {
136 /* If ray exited the volume and never entered to that volume
137 * it means that camera is inside such a volume.
138 */
139 if (enclosed_volumes[i] == stack_sd->object) {
140 need_add = false;
141 }
142 }
143 for (int i = 0; i < stack_index && need_add; ++i) {
144 /* Don't add intersections twice. */
145 const VolumeStack entry = integrator_state_read_volume_stack(state, i);
146 if (entry.object == stack_sd->object) {
147 need_add = false;
148 break;
149 }
150 }
151 if (need_add && stack_index < volume_stack_size - 1) {
152 const VolumeStack new_entry = {stack_sd->object, stack_sd->shader};
153 integrator_state_write_volume_stack(state, stack_index, new_entry);
154 ++stack_index;
155 }
156 }
157 else {
158 /* If ray from camera enters the volume, this volume shouldn't
159 * be added to the stack on exit.
160 */
161 enclosed_volumes[enclosed_index++] = stack_sd->object;
162 }
163 }
164 }
165# else
166 /* CUDA does not support definition of a variable size arrays, so use the maximum possible. */
167 int enclosed_volumes[MAX_VOLUME_STACK_SIZE];
168 int step = 0;
169
170 while (stack_index < volume_stack_size - 1 && enclosed_index < MAX_VOLUME_STACK_SIZE - 1 &&
171 step < 2 * volume_stack_size)
172 {
173 Intersection isect;
174 if (!scene_intersect_volume(kg, &volume_ray, &isect, visibility)) {
175 break;
176 }
177
178 shader_setup_from_ray(kg, stack_sd, &volume_ray, &isect);
179 if (stack_sd->flag & SD_BACKFACING) {
180 /* If ray exited the volume and never entered to that volume
181 * it means that camera is inside such a volume.
182 */
183 bool need_add = true;
184 for (int i = 0; i < enclosed_index && need_add; ++i) {
185 /* If ray exited the volume and never entered to that volume
186 * it means that camera is inside such a volume.
187 */
188 if (enclosed_volumes[i] == stack_sd->object) {
189 need_add = false;
190 }
191 }
192 for (int i = 0; i < stack_index && need_add; ++i) {
193 /* Don't add intersections twice. */
194 VolumeStack entry = integrator_state_read_volume_stack(state, i);
195 if (entry.object == stack_sd->object) {
196 need_add = false;
197 break;
198 }
199 }
200 if (need_add) {
201 const VolumeStack new_entry = {stack_sd->object, stack_sd->shader};
202 integrator_state_write_volume_stack(state, stack_index, new_entry);
203 ++stack_index;
204 }
205 }
206 else {
207 /* If ray from camera enters the volume, this volume shouldn't
208 * be added to the stack on exit.
209 */
210 enclosed_volumes[enclosed_index++] = stack_sd->object;
211 }
212
213 /* Move ray forward. */
214 volume_ray.tmin = intersection_t_offset(isect.t);
215 volume_ray.self.object = isect.object;
216 volume_ray.self.prim = isect.prim;
217 ++step;
218 }
219# endif
220
221 /* Write terminator. */
222 const VolumeStack new_entry = {OBJECT_NONE, SHADER_NONE};
223 integrator_state_write_volume_stack(state, stack_index, new_entry);
224#endif
225}
226
228{
229#ifdef __VOLUME__
230 integrator_volume_stack_init(kg, state);
231
232# ifdef __SHADOW_CATCHER__
234 /* Volume stack re-init for shadow catcher, continue with shading of hit. */
235 integrator_intersect_next_kernel_after_shadow_catcher_volume<
237 }
238 else
239# endif
240 {
241 /* Volume stack init for camera rays, continue with intersection of camera ray. */
243 state,
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 ccl_device
#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)
Definition profiler.h:14
@ PROFILING_INTERSECT_VOLUME_STACK
Definition profiling.h:22
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(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel)
Definition state_flow.h:173
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:139