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