Blender V5.0
texture_3d.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2025 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "kernel/globals.h"
8#include "kernel/sample/lcg.h"
9
10#include "util/texture.h"
11
12#if !defined(__KERNEL_METAL__) && !defined(__KERNEL_ONEAPI__)
13# ifdef WITH_NANOVDB
14# include "kernel/util/nanovdb.h"
15# endif
16#endif
17
19
20#ifndef __KERNEL_GPU__
21/* Make template functions private so symbols don't conflict between kernels with different
22 * instruction sets. */
23namespace {
24#endif
25
26#ifdef WITH_NANOVDB
27/* -------------------------------------------------------------------- */
31ccl_device_inline float3 interp_tricubic_stochastic(const float3 P, ccl_private float3 &rand)
32{
33 const float3 p = floor(P);
34 const float3 t = P - p;
35
36 /* Cubic interpolation weights. */
37 const float3 w[4] = {(((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f),
38 ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f),
39 ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f),
40 (1.0f / 6.0f) * t * t * t};
41
42 /* For reservoir sampling, always accept the first in the stream. */
43 float3 total_weight = w[0];
44 float3 offset = make_float3(-1.0f);
45
46 for (int j = 1; j < 4; j++) {
47 total_weight += w[j];
48 const float3 thresh = w[j] / total_weight;
49 const auto mask = rand < thresh;
50 offset = select(mask, make_float3(float(j) - 1.0f), offset);
51 rand = select(mask, safe_divide(rand, thresh), safe_divide(rand - thresh, 1.0f - thresh));
52 }
53
54 return p + offset;
55}
56
57ccl_device_inline float3 interp_trilinear_stochastic(const float3 P, const float3 rand)
58{
59 const float3 p = floor(P);
60 const float3 t = P - p;
61 return select(rand < t, p + 1.0f, p);
62}
63
64ccl_device_inline float3 interp_stochastic(const float3 P,
65 ccl_private InterpolationType &interpolation,
66 ccl_private float3 &rand)
67{
68 float3 P_new = P;
69 if (interpolation == INTERPOLATION_CUBIC) {
70 P_new = interp_tricubic_stochastic(P, rand);
71 }
72 else if (interpolation == INTERPOLATION_LINEAR) {
73 P_new = interp_trilinear_stochastic(P, rand);
74 }
75 else {
76 kernel_assert(interpolation == INTERPOLATION_CLOSEST);
77 }
78 interpolation = INTERPOLATION_CLOSEST;
79 return P_new;
80}
82
83template<typename OutT, typename Acc>
84ccl_device OutT kernel_tex_image_interp_trilinear_nanovdb(ccl_private Acc &acc, const float3 P)
85{
86 const float3 floor_P = floor(P);
87 const float3 t = P - floor_P;
88 const int3 index = make_int3(floor_P);
89
90 const int ix = index.x;
91 const int iy = index.y;
92 const int iz = index.z;
93
94 return mix(mix(mix(OutT(acc.getValue(make_int3(ix, iy, iz))),
95 OutT(acc.getValue(make_int3(ix, iy, iz + 1))),
96 t.z),
97 mix(OutT(acc.getValue(make_int3(ix, iy + 1, iz + 1))),
98 OutT(acc.getValue(make_int3(ix, iy + 1, iz))),
99 1.0f - t.z),
100 t.y),
101 mix(mix(OutT(acc.getValue(make_int3(ix + 1, iy + 1, iz))),
102 OutT(acc.getValue(make_int3(ix + 1, iy + 1, iz + 1))),
103 t.z),
104 mix(OutT(acc.getValue(make_int3(ix + 1, iy, iz + 1))),
105 OutT(acc.getValue(make_int3(ix + 1, iy, iz))),
106 1.0f - t.z),
107 1.0f - t.y),
108 t.x);
109}
110
111template<typename OutT, typename Acc>
112ccl_device OutT kernel_tex_image_interp_tricubic_nanovdb(ccl_private Acc &acc, const float3 P)
113{
114 const float3 floor_P = floor(P);
115 const float3 t = P - floor_P;
116 const int3 index = make_int3(floor_P);
117
118 const int xc[4] = {index.x - 1, index.x, index.x + 1, index.x + 2};
119 const int yc[4] = {index.y - 1, index.y, index.y + 1, index.y + 2};
120 const int zc[4] = {index.z - 1, index.z, index.z + 1, index.z + 2};
121 float u[4], v[4], w[4];
122
123 /* Some helper macros to keep code size reasonable.
124 * Lets the compiler inline all the matrix multiplications.
125 */
126# define SET_CUBIC_SPLINE_WEIGHTS(u, t) \
127 { \
128 u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \
129 u[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f); \
130 u[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f); \
131 u[3] = (1.0f / 6.0f) * t * t * t; \
132 } \
133 (void)0
134
135# define DATA(x, y, z) (OutT(acc.getValue(make_int3(xc[x], yc[y], zc[z]))))
136# define COL_TERM(col, row) \
137 (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \
138 u[3] * DATA(3, col, row)))
139# define ROW_TERM(row) \
140 (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row)))
141
145
146 /* Actual interpolation. */
147 return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3);
148
149# undef COL_TERM
150# undef ROW_TERM
151# undef DATA
152# undef SET_CUBIC_SPLINE_WEIGHTS
153}
154
155template<typename OutT, typename T>
156# if defined(__KERNEL_METAL__)
158# else
160# endif
161OutT kernel_tex_image_interp_nanovdb(const ccl_global TextureInfo &info,
162 float3 P,
164{
166
168 nanovdb::ReadAccessor<T> acc(grid->tree().root());
169 return OutT(acc.getValue(make_int3(floor(P))));
170 }
171
172 nanovdb::CachedReadAccessor<T> acc(grid->tree().root());
174 return kernel_tex_image_interp_trilinear_nanovdb<OutT>(acc, P);
175 }
176
177 return kernel_tex_image_interp_tricubic_nanovdb<OutT>(acc, P);
178}
179#endif /* WITH_NANOVDB */
180
182 ccl_private ShaderData *sd,
183 const int id,
184 float3 P,
186 const bool stochastic)
187{
188#ifdef WITH_NANOVDB
189 const ccl_global TextureInfo &info = kernel_data_fetch(texture_info, id);
190
191 if (info.use_transform_3d) {
192 P = transform_point(&info.transform_3d, P);
193 }
194
195 InterpolationType interpolation = (interp == INTERPOLATION_NONE) ?
196 (InterpolationType)info.interpolation :
197 interp;
198
199 if (stochastic) {
200 float3 rand = lcg_step_float3(&sd->lcg_state);
201 P = interp_stochastic(P, interpolation, rand);
202 }
203
204 const ImageDataType data_type = (ImageDataType)info.data_type;
205 if (data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT) {
206 const float f = kernel_tex_image_interp_nanovdb<float, float>(info, P, interpolation);
207 return make_float4(f, f, f, 1.0f);
208 }
209 if (data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
210 const float3 f = kernel_tex_image_interp_nanovdb<float3, packed_float3>(
211 info, P, interpolation);
212 return make_float4(f, 1.0f);
213 }
214 if (data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT4) {
215 return kernel_tex_image_interp_nanovdb<float4, float4>(info, P, interpolation);
216 }
217 if (data_type == IMAGE_DATA_TYPE_NANOVDB_FPN) {
218 const float f = kernel_tex_image_interp_nanovdb<float, nanovdb::FpN>(info, P, interpolation);
219 return make_float4(f, f, f, 1.0f);
220 }
221 if (data_type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
222 const float f = kernel_tex_image_interp_nanovdb<float, nanovdb::Fp16>(info, P, interpolation);
223 return make_float4(f, f, f, 1.0f);
224 }
225 if (data_type == IMAGE_DATA_TYPE_NANOVDB_EMPTY) {
226 return zero_float4();
227 }
228#else
229 (void)kg;
230 (void)sd;
231 (void)id;
232 (void)P;
233 (void)interp;
234 (void)stochastic;
235#endif
236
237 return make_float4(
239}
240
241#ifndef __KERNEL_GPU__
242} /* Namespace. */
243#endif
244
MINLINE float safe_divide(float a, float b)
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static __attribute__((constructor)) void cpu_check()
Definition cpu_check.cc:94
#define SET_CUBIC_SPLINE_WEIGHTS(u, t)
#define kernel_assert(cond)
#define kernel_data_fetch(name, index)
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define ccl_global
#define ccl_device_noinline
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device_forceinline int3 make_int3(const int x, const int y, const int z)
#define noinline
#define select(A, B, C)
#define floor
ccl_device float3 lcg_step_float3(T rng)
Definition lcg.h:29
ccl_device_inline float interp(const float a, const float b, const float t)
Definition math_base.h:502
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float4 zero_float4()
Definition math_float4.h:13
ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg, ccl_private ShaderData *sd, const int id, float3 P, InterpolationType interp, const bool stochastic)
Definition texture_3d.h:181
Grid< NanoTree< BuildT > > NanoGrid
#define mix
#define ccl_device
#define make_float4
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
ImageDataType
Definition texture.h:32
@ IMAGE_DATA_TYPE_NANOVDB_FP16
Definition texture.h:45
@ IMAGE_DATA_TYPE_NANOVDB_EMPTY
Definition texture.h:46
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT
Definition texture.h:41
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT3
Definition texture.h:42
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT4
Definition texture.h:43
@ IMAGE_DATA_TYPE_NANOVDB_FPN
Definition texture.h:44
InterpolationType
Definition texture.h:22
@ INTERPOLATION_LINEAR
Definition texture.h:24
@ INTERPOLATION_NONE
Definition texture.h:23
@ INTERPOLATION_CLOSEST
Definition texture.h:25
@ INTERPOLATION_CUBIC
Definition texture.h:26
@ TEX_IMAGE_MISSING_G
Definition texture.h:15
@ TEX_IMAGE_MISSING_A
Definition texture.h:17
@ TEX_IMAGE_MISSING_R
Definition texture.h:14
@ TEX_IMAGE_MISSING_B
Definition texture.h:16
ccl_device_inline float3 transform_point(const ccl_private Transform *t, const float3 a)
Definition transform.h:56