Blender V4.3
kernel/bvh/volume.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2010 NVIDIA Corporation
2 * SPDX-FileCopyrightText: 2009-2012 Intel Corporation
3 * SPDX-FileCopyrightText: 2011-2022 Blender Foundation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Adapted code from NVIDIA Corporation. */
8
9#if BVH_FEATURE(BVH_HAIR)
10# define NODE_INTERSECT bvh_node_intersect
11#else
12# define NODE_INTERSECT bvh_aligned_node_intersect
13#endif
14
15/* This is a template BVH traversal function for volumes, where
16 * various features can be enabled/disabled. This way we can compile optimized
17 * versions for each case without new features slowing things down.
18 *
19 * BVH_MOTION: motion blur rendering
20 */
21
22#ifndef __KERNEL_GPU__
24#else
26#endif
27 bool
29 ccl_private const Ray *ray,
31 const uint visibility)
32{
33 /* todo:
34 * - test if pushing distance on the stack helps (for non shadow rays)
35 * - separate version for shadow rays
36 * - likely and unlikely for if() statements
37 * - test restrict attribute for pointers
38 */
39
40 /* traversal stack in CUDA thread-local memory */
43
44 /* traversal variables in registers */
45 int stack_ptr = 0;
46 int node_addr = kernel_data.bvh.root;
47
48 /* ray parameters in registers */
49 float3 P = ray->P;
50 float3 dir = bvh_clamp_direction(ray->D);
51 float3 idir = bvh_inverse_direction(dir);
52 const float tmin = ray->tmin;
53 int object = OBJECT_NONE;
54
55 isect->t = ray->tmax;
56 isect->u = 0.0f;
57 isect->v = 0.0f;
58 isect->prim = PRIM_NONE;
59 isect->object = OBJECT_NONE;
60
61 /* traversal loop */
62 do {
63 do {
64 /* traverse internal nodes */
65 while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
66 int node_addr_child1, traverse_mask;
67 float dist[2];
68 float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
69
70 traverse_mask = NODE_INTERSECT(kg,
71 P,
73 dir,
74#endif
75 idir,
76 tmin,
77 isect->t,
78 node_addr,
79 visibility,
80 dist);
81
82 node_addr = __float_as_int(cnodes.z);
83 node_addr_child1 = __float_as_int(cnodes.w);
84
85 if (traverse_mask == 3) {
86 /* Both children were intersected, push the farther one. */
87 bool is_closest_child1 = (dist[1] < dist[0]);
88 if (is_closest_child1) {
89 int tmp = node_addr;
90 node_addr = node_addr_child1;
91 node_addr_child1 = tmp;
92 }
93
94 ++stack_ptr;
95 kernel_assert(stack_ptr < BVH_STACK_SIZE);
96 traversal_stack[stack_ptr] = node_addr_child1;
97 }
98 else {
99 /* One child was intersected. */
100 if (traverse_mask == 2) {
101 node_addr = node_addr_child1;
102 }
103 else if (traverse_mask == 0) {
104 /* Neither child was intersected. */
105 node_addr = traversal_stack[stack_ptr];
106 --stack_ptr;
107 }
108 }
109 }
110
111 /* if node is leaf, fetch triangle list */
112 if (node_addr < 0) {
113 float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
114 int prim_addr = __float_as_int(leaf.x);
115
116 if (prim_addr >= 0) {
117 const int prim_addr2 = __float_as_int(leaf.y);
118 const uint type = __float_as_int(leaf.w);
119
120 /* pop */
121 node_addr = traversal_stack[stack_ptr];
122 --stack_ptr;
123
124 /* primitive intersection */
125 switch (type & PRIMITIVE_ALL) {
126 case PRIMITIVE_TRIANGLE: {
127 /* intersect ray against primitive */
128 for (; prim_addr < prim_addr2; prim_addr++) {
129 kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
130 /* only primitives from volume object */
131 const int prim_object = (object == OBJECT_NONE) ?
132 kernel_data_fetch(prim_object, prim_addr) :
133 object;
134 const int prim = kernel_data_fetch(prim_index, prim_addr);
135 if (intersection_skip_self(ray->self, prim_object, prim)) {
136 continue;
137 }
138
139 int object_flag = kernel_data_fetch(object_flag, prim_object);
140 if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
141 continue;
142 }
144 kg, isect, P, dir, tmin, isect->t, visibility, prim_object, prim, prim_addr);
145 }
146 break;
147 }
148#if BVH_FEATURE(BVH_MOTION)
150 /* intersect ray against primitive */
151 for (; prim_addr < prim_addr2; prim_addr++) {
152 kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
153 /* only primitives from volume object */
154 const int prim_object = (object == OBJECT_NONE) ?
155 kernel_data_fetch(prim_object, prim_addr) :
156 object;
157 const int prim = kernel_data_fetch(prim_index, prim_addr);
158 if (intersection_skip_self(ray->self, prim_object, prim)) {
159 continue;
160 }
161 int object_flag = kernel_data_fetch(object_flag, prim_object);
162 if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
163 continue;
164 }
166 isect,
167 P,
168 dir,
169 tmin,
170 isect->t,
171 ray->time,
172 visibility,
173 prim_object,
174 prim,
175 prim_addr);
176 }
177 break;
178 }
179#endif
180 default: {
181 break;
182 }
183 }
184 }
185 else {
186 /* instance push */
187 object = kernel_data_fetch(prim_object, -prim_addr - 1);
188 int object_flag = kernel_data_fetch(object_flag, object);
189 if (object_flag & SD_OBJECT_HAS_VOLUME) {
190#if BVH_FEATURE(BVH_MOTION)
191 bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir);
192#else
193 bvh_instance_push(kg, object, ray, &P, &dir, &idir);
194#endif
195
196 ++stack_ptr;
197 kernel_assert(stack_ptr < BVH_STACK_SIZE);
199
200 node_addr = kernel_data_fetch(object_node, object);
201 }
202 else {
203 /* pop */
204 object = OBJECT_NONE;
205 node_addr = traversal_stack[stack_ptr];
206 --stack_ptr;
207 }
208 }
209 }
210 } while (node_addr != ENTRYPOINT_SENTINEL);
211
212 if (stack_ptr >= 0) {
213 kernel_assert(object != OBJECT_NONE);
214
215 /* instance pop */
216 bvh_instance_pop(ray, &P, &dir, &idir);
217
218 object = OBJECT_NONE;
219 node_addr = traversal_stack[stack_ptr];
220 --stack_ptr;
221 }
222 } while (node_addr != ENTRYPOINT_SENTINEL);
223
224 return (isect->prim != PRIM_NONE);
225}
226
228 ccl_private const Ray *ray,
230 const uint visibility)
231{
232 return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect, visibility);
233}
234
235#undef BVH_FUNCTION_NAME
236#undef BVH_FUNCTION_FEATURES
237#undef NODE_INTERSECT
unsigned int uint
Definition bvh/bvh.h:66
ccl_device_inline bool intersection_skip_self(ccl_ray_data const RaySelfPrimitives &self, const int object, const int prim)
BLI_Stack * traversal_stack
#define kernel_assert(cond)
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define __float_as_int(x)
#define BVH_FUNCTION_NAME
#define BVH_STACK_SIZE
#define BVH_FEATURE(f)
#define ENTRYPOINT_SENTINEL
#define BVH_HAIR
#define BVH_FUNCTION_FULL_NAME(prefix)
#define NODE_INTERSECT
ccl_device_inline void bvh_instance_push(KernelGlobals kg, int object, ccl_private const Ray *ray, ccl_private float3 *P, ccl_private float3 *dir, ccl_private float3 *idir)
ccl_device_inline float3 bvh_clamp_direction(float3 dir)
ccl_device_inline void bvh_instance_pop(ccl_private const Ray *ray, ccl_private float3 *P, ccl_private float3 *dir, ccl_private float3 *idir)
ccl_device_inline float3 bvh_inverse_direction(float3 dir)
@ PRIMITIVE_ALL
@ PRIMITIVE_MOTION_TRIANGLE
@ PRIMITIVE_TRIANGLE
#define PRIM_NONE
#define OBJECT_NONE
@ SD_OBJECT_HAS_VOLUME
ccl_device_inline bool motion_triangle_intersect(KernelGlobals kg, ccl_private Intersection *isect, float3 P, float3 dir, float tmin, float tmax, float time, uint visibility, int object, int prim, int prim_addr)
CCL_NAMESPACE_BEGIN ccl_device_inline bool triangle_intersect(KernelGlobals kg, ccl_private Intersection *isect, float3 P, float3 dir, float tmin, float tmax, uint visibility, int object, int prim, int prim_addr)