Blender  V3.3
kernel/svm/ies.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #pragma once
5 
7 
8 /* IES Light */
9 
11  KernelGlobals kg, int ofs, int v, int v_num, float v_frac, int h)
12 {
13  /* Since lookups are performed in spherical coordinates, clamping the coordinates at the low end
14  * of v (corresponding to the north pole) would result in artifacts. The proper way of dealing
15  * with this would be to lookup the corresponding value on the other side of the pole, but since
16  * the horizontal coordinates might be nonuniform, this would require yet another interpolation.
17  * Therefore, the assumption is made that the light is going to be symmetrical, which means that
18  * we can just take the corresponding value at the current horizontal coordinate. */
19 
20 #define IES_LOOKUP(v) kernel_data_fetch(ies, ofs + h * v_num + (v))
21  /* If v is zero, assume symmetry and read at v=1 instead of v=-1. */
22  float a = IES_LOOKUP((v == 0) ? 1 : v - 1);
23  float b = IES_LOOKUP(v);
24  float c = IES_LOOKUP(v + 1);
25  float d = IES_LOOKUP(min(v + 2, v_num - 1));
26 #undef IES_LOOKUP
27 
28  return cubic_interp(a, b, c, d, v_frac);
29 }
30 
31 ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_angle, float v_angle)
32 {
33  /* Find offset of the IES data in the table. */
34  int ofs = __float_as_int(kernel_data_fetch(ies, slot));
35  if (ofs == -1) {
36  return 100.0f;
37  }
38 
39  int h_num = __float_as_int(kernel_data_fetch(ies, ofs++));
40  int v_num = __float_as_int(kernel_data_fetch(ies, ofs++));
41 
42 #define IES_LOOKUP_ANGLE_H(h) kernel_data_fetch(ies, ofs + (h))
43 #define IES_LOOKUP_ANGLE_V(v) kernel_data_fetch(ies, ofs + h_num + (v))
44 
45  /* Check whether the angle is within the bounds of the IES texture. */
46  if (v_angle >= IES_LOOKUP_ANGLE_V(v_num - 1)) {
47  return 0.0f;
48  }
49  kernel_assert(v_angle >= IES_LOOKUP_ANGLE_V(0));
50  kernel_assert(h_angle >= IES_LOOKUP_ANGLE_H(0));
51  kernel_assert(h_angle <= IES_LOOKUP_ANGLE_H(h_num - 1));
52 
53  /* Lookup the angles to find the table position. */
54  int h_i, v_i;
55  /* TODO(lukas): Consider using bisection.
56  * Probably not worth it for the vast majority of IES files. */
57  for (h_i = 0; IES_LOOKUP_ANGLE_H(h_i + 1) < h_angle; h_i++)
58  ;
59  for (v_i = 0; IES_LOOKUP_ANGLE_V(v_i + 1) < v_angle; v_i++)
60  ;
61 
62  float h_frac = inverse_lerp(IES_LOOKUP_ANGLE_H(h_i), IES_LOOKUP_ANGLE_H(h_i + 1), h_angle);
63  float v_frac = inverse_lerp(IES_LOOKUP_ANGLE_V(v_i), IES_LOOKUP_ANGLE_V(v_i + 1), v_angle);
64 
65 #undef IES_LOOKUP_ANGLE_H
66 #undef IES_LOOKUP_ANGLE_V
67 
68  /* Skip forward to the actual intensity data. */
69  ofs += h_num + v_num;
70 
71  /* Perform cubic interpolation along the horizontal coordinate to get the intensity value.
72  * If h_i is zero, just wrap around since the horizontal angles always go over the full circle.
73  * However, the last entry (360°) equals the first one, so we need to wrap around to the one
74  * before that. */
76  kg, ofs, v_i, v_num, v_frac, (h_i == 0) ? h_num - 2 : h_i - 1);
77  float b = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i);
78  float c = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i + 1);
79  /* Same logic here, wrap around to the second element if necessary. */
80  float d = interpolate_ies_vertical(
81  kg, ofs, v_i, v_num, v_frac, (h_i + 2 == h_num) ? 1 : h_i + 2);
82 
83  /* Cubic interpolation can result in negative values, so get rid of them. */
84  return max(cubic_interp(a, b, c, d, h_frac), 0.0f);
85 }
86 
89  ccl_private float *stack,
90  uint4 node)
91 {
92  uint vector_offset, strength_offset, fac_offset, slot = node.z;
93  svm_unpack_node_uchar3(node.y, &strength_offset, &vector_offset, &fac_offset);
94 
95  float3 vector = stack_load_float3(stack, vector_offset);
96  float strength = stack_load_float_default(stack, strength_offset, node.w);
97 
99  float v_angle = safe_acosf(-vector.z);
100  float h_angle = atan2f(vector.x, vector.y) + M_PI_F;
101 
102  float fac = strength * kernel_ies_interp(kg, slot, h_angle, v_angle);
103 
104  if (stack_valid(fac_offset)) {
105  stack_store_float(stack, fac_offset, fac);
106  }
107 }
108 
MINLINE float safe_acosf(float a)
unsigned int uint
Definition: BLI_sys_types.h:67
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define kernel_assert(cond)
Definition: cpu/compat.h:34
#define ccl_private
Definition: cuda/compat.h:48
#define ccl_device_inline
Definition: cuda/compat.h:34
#define ccl_device_noinline
Definition: cuda/compat.h:40
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
OperationNode * node
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
ccl_device_noinline void svm_node_ies(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node)
#define IES_LOOKUP_ANGLE_V(v)
#define IES_LOOKUP(v)
#define IES_LOOKUP_ANGLE_H(h)
ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_angle, float v_angle)
CCL_NAMESPACE_BEGIN ccl_device_inline float interpolate_ies_vertical(KernelGlobals kg, int ofs, int v, int v_num, float v_frac, int h)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 stack_load_float3(ccl_private float *stack, uint a)
ccl_device_forceinline void svm_unpack_node_uchar3(uint i, ccl_private uint *x, ccl_private uint *y, ccl_private uint *z)
ccl_device_inline float stack_load_float_default(ccl_private float *stack, uint a, uint value)
ccl_device_inline void stack_store_float(ccl_private float *stack, uint a, float f)
ccl_device_inline bool stack_valid(uint a)
ShaderData
Definition: kernel/types.h:925
#define atan2f(x, y)
Definition: metal/compat.h:227
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
#define min(a, b)
Definition: sort.c:35
float max
ccl_device_inline float inverse_lerp(float a, float b, float x)
Definition: util/math.h:515
ccl_device_inline int __float_as_int(float f)
Definition: util/math.h:243
#define M_PI_F
Definition: util/math.h:34
ccl_device_inline float cubic_interp(float a, float b, float c, float d, float x)
Definition: util/math.h:521