Blender V4.3
kernel/util/ies.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
8
9/* IES Light */
10
12 int ofs,
13 const bool wrap_vlow,
14 const bool wrap_vhigh,
15 int v,
16 int v_num,
17 float v_frac,
18 int h)
19{
20 /* Since lookups are performed in spherical coordinates, clamping the coordinates at the low end
21 * of v (corresponding to the north pole) would result in artifacts. The proper way of dealing
22 * with this would be to lookup the corresponding value on the other side of the pole, but since
23 * the horizontal coordinates might be nonuniform, this would require yet another interpolation.
24 * Therefore, the assumption is made that the light is going to be symmetrical, which means that
25 * we can just take the corresponding value at the current horizontal coordinate. */
26
27#define IES_LOOKUP(v) kernel_data_fetch(ies, ofs + h * v_num + (v))
28 float a = 0.0f;
29 if (v > 0) {
30 a = IES_LOOKUP(v - 1);
31 }
32 else if (wrap_vlow) {
33 a = IES_LOOKUP(1);
34 }
35 float b = IES_LOOKUP(v);
36 float c = IES_LOOKUP(v + 1);
37 float d = 0.0f;
38 if (v + 2 < v_num) {
39 d = IES_LOOKUP(v + 2);
40 }
41 else if (wrap_vhigh) {
42 d = IES_LOOKUP(v_num - 2);
43 }
44#undef IES_LOOKUP
45
46 return cubic_interp(a, b, c, d, v_frac);
47}
48
49ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_angle, float v_angle)
50{
51 /* Find offset of the IES data in the table. */
52 int ofs = __float_as_int(kernel_data_fetch(ies, slot));
53 if (ofs == -1) {
54 return 100.0f;
55 }
56
57 int h_num = __float_as_int(kernel_data_fetch(ies, ofs++));
58 int v_num = __float_as_int(kernel_data_fetch(ies, ofs++));
59
60#define IES_LOOKUP_ANGLE_H(h) kernel_data_fetch(ies, ofs + (h))
61#define IES_LOOKUP_ANGLE_V(v) kernel_data_fetch(ies, ofs + h_num + (v))
62
63 /* Check whether the angle is within the bounds of the IES texture. */
64 const float v_low = IES_LOOKUP_ANGLE_V(0), v_high = IES_LOOKUP_ANGLE_V(v_num - 1);
65 const float h_low = IES_LOOKUP_ANGLE_H(0), h_high = IES_LOOKUP_ANGLE_H(h_num - 1);
66 if (v_angle < v_low || v_angle >= v_high) {
67 return 0.0f;
68 }
69 if (h_angle < h_low || h_angle >= h_high) {
70 return 0.0f;
71 }
72
73 /* If the texture covers the full 360° range horizontally, wrap around the lookup
74 * to get proper cubic interpolation. Otherwise, just set the out-of-range values to zero.
75 * Similar logic for V, but there we check the lower and upper wrap separately. */
76 const bool wrap_h = (h_low < 1e-7f && h_high > M_2PI_F - 1e-7f);
77 const bool wrap_vlow = (v_low < 1e-7f);
78 const bool wrap_vhigh = (v_high > M_PI_F - 1e-7f);
79
80 /* Lookup the angles to find the table position. */
81 int h_i, v_i;
82 /* TODO(lukas): Consider using bisection.
83 * Probably not worth it for the vast majority of IES files. */
84 for (h_i = 0; IES_LOOKUP_ANGLE_H(h_i + 1) < h_angle; h_i++) {
85 ;
86 }
87 for (v_i = 0; IES_LOOKUP_ANGLE_V(v_i + 1) < v_angle; v_i++) {
88 ;
89 }
90
91 float h_frac = inverse_lerp(IES_LOOKUP_ANGLE_H(h_i), IES_LOOKUP_ANGLE_H(h_i + 1), h_angle);
92 float v_frac = inverse_lerp(IES_LOOKUP_ANGLE_V(v_i), IES_LOOKUP_ANGLE_V(v_i + 1), v_angle);
93
94#undef IES_LOOKUP_ANGLE_H
95#undef IES_LOOKUP_ANGLE_V
96
97 /* Skip forward to the actual intensity data. */
98 ofs += h_num + v_num;
99
100 float a = 0.0f;
101 if (h_i > 0) {
102 a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i - 1);
103 }
104 else if (wrap_h) {
105 /* The last entry (360°) equals the first one, so we need to wrap around to the one before. */
106 a = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_num - 2);
107 }
108 float b = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i);
109 float c = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 1);
110 float d = 0.0f;
111 if (h_i + 2 < h_num) {
112 d = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, h_i + 2);
113 }
114 else if (wrap_h) {
115 /* Same logic here, wrap around to the second element if necessary. */
116 d = interpolate_ies_vertical(kg, ofs, wrap_vlow, wrap_vhigh, v_i, v_num, v_frac, 1);
117 }
118
119 /* Cubic interpolation can result in negative values, so get rid of them. */
120 return max(cubic_interp(a, b, c, d, h_frac), 0.0f);
121}
122
ATTR_WARN_UNUSED_RESULT const BMVert * v
local_group_size(16, 16) .push_constant(Type b
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_device_inline
#define CCL_NAMESPACE_END
#define __float_as_int(x)
#define IES_LOOKUP_ANGLE_V(v)
#define IES_LOOKUP(v)
CCL_NAMESPACE_BEGIN ccl_device_inline float interpolate_ies_vertical(KernelGlobals kg, int ofs, const bool wrap_vlow, const bool wrap_vhigh, int v, int v_num, float v_frac, int h)
#define IES_LOOKUP_ANGLE_H(h)
ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_angle, float v_angle)
#define M_PI_F
Definition mikk_util.hh:15
#define M_2PI_F
Definition sky_float3.h:23
float max
ccl_device_inline float inverse_lerp(float a, float b, float x)
Definition util/math.h:550
ccl_device_inline float cubic_interp(float a, float b, float c, float d, float x)
Definition util/math.h:556