Blender  V2.93
svm_ies.h
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 /* IES Light */
20 
22  KernelGlobals *kg, int ofs, int v, int v_num, float v_frac, int h)
23 {
24  /* Since lookups are performed in spherical coordinates, clamping the coordinates at the low end
25  * of v (corresponding to the north pole) would result in artifacts. The proper way of dealing
26  * with this would be to lookup the corresponding value on the other side of the pole, but since
27  * the horizontal coordinates might be nonuniform, this would require yet another interpolation.
28  * Therefore, the assumption is made that the light is going to be symmetrical, which means that
29  * we can just take the corresponding value at the current horizontal coordinate. */
30 
31 #define IES_LOOKUP(v) kernel_tex_fetch(__ies, ofs + h * v_num + (v))
32  /* If v is zero, assume symmetry and read at v=1 instead of v=-1. */
33  float a = IES_LOOKUP((v == 0) ? 1 : v - 1);
34  float b = IES_LOOKUP(v);
35  float c = IES_LOOKUP(v + 1);
36  float d = IES_LOOKUP(min(v + 2, v_num - 1));
37 #undef IES_LOOKUP
38 
39  return cubic_interp(a, b, c, d, v_frac);
40 }
41 
42 ccl_device_inline float kernel_ies_interp(KernelGlobals *kg,
43  int slot,
44  float h_angle,
45  float v_angle)
46 {
47  /* Find offset of the IES data in the table. */
48  int ofs = __float_as_int(kernel_tex_fetch(__ies, slot));
49  if (ofs == -1) {
50  return 100.0f;
51  }
52 
53  int h_num = __float_as_int(kernel_tex_fetch(__ies, ofs++));
54  int v_num = __float_as_int(kernel_tex_fetch(__ies, ofs++));
55 
56 #define IES_LOOKUP_ANGLE_H(h) kernel_tex_fetch(__ies, ofs + (h))
57 #define IES_LOOKUP_ANGLE_V(v) kernel_tex_fetch(__ies, ofs + h_num + (v))
58 
59  /* Check whether the angle is within the bounds of the IES texture. */
60  if (v_angle >= IES_LOOKUP_ANGLE_V(v_num - 1)) {
61  return 0.0f;
62  }
63  kernel_assert(v_angle >= IES_LOOKUP_ANGLE_V(0));
64  kernel_assert(h_angle >= IES_LOOKUP_ANGLE_H(0));
65  kernel_assert(h_angle <= IES_LOOKUP_ANGLE_H(h_num - 1));
66 
67  /* Lookup the angles to find the table position. */
68  int h_i, v_i;
69  /* TODO(lukas): Consider using bisection.
70  * Probably not worth it for the vast majority of IES files. */
71  for (h_i = 0; IES_LOOKUP_ANGLE_H(h_i + 1) < h_angle; h_i++)
72  ;
73  for (v_i = 0; IES_LOOKUP_ANGLE_V(v_i + 1) < v_angle; v_i++)
74  ;
75 
76  float h_frac = inverse_lerp(IES_LOOKUP_ANGLE_H(h_i), IES_LOOKUP_ANGLE_H(h_i + 1), h_angle);
77  float v_frac = inverse_lerp(IES_LOOKUP_ANGLE_V(v_i), IES_LOOKUP_ANGLE_V(v_i + 1), v_angle);
78 
79 #undef IES_LOOKUP_ANGLE_H
80 #undef IES_LOOKUP_ANGLE_V
81 
82  /* Skip forward to the actual intensity data. */
83  ofs += h_num + v_num;
84 
85  /* Perform cubic interpolation along the horizontal coordinate to get the intensity value.
86  * If h_i is zero, just wrap around since the horizontal angles always go over the full circle.
87  * However, the last entry (360°) equals the first one, so we need to wrap around to the one
88  * before that. */
90  kg, ofs, v_i, v_num, v_frac, (h_i == 0) ? h_num - 2 : h_i - 1);
91  float b = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i);
92  float c = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i + 1);
93  /* Same logic here, wrap around to the second element if necessary. */
94  float d = interpolate_ies_vertical(
95  kg, ofs, v_i, v_num, v_frac, (h_i + 2 == h_num) ? 1 : h_i + 2);
96 
97  /* Cubic interpolation can result in negative values, so get rid of them. */
98  return max(cubic_interp(a, b, c, d, h_frac), 0.0f);
99 }
100 
102  KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
103 {
104  uint vector_offset, strength_offset, fac_offset, slot = node.z;
105  svm_unpack_node_uchar3(node.y, &strength_offset, &vector_offset, &fac_offset);
106 
107  float3 vector = stack_load_float3(stack, vector_offset);
108  float strength = stack_load_float_default(stack, strength_offset, node.w);
109 
111  float v_angle = safe_acosf(-vector.z);
112  float h_angle = atan2f(vector.x, vector.y) + M_PI_F;
113 
114  float fac = strength * kernel_ies_interp(kg, slot, h_angle, v_angle);
115 
116  if (stack_valid(fac_offset)) {
117  stack_store_float(stack, fac_offset, fac);
118  }
119 }
120 
MINLINE float safe_acosf(float a)
unsigned int uint
Definition: BLI_sys_types.h:83
ATTR_WARN_UNUSED_RESULT const BMVert * v
OperationNode * node
CCL_NAMESPACE_BEGIN ccl_device_inline float3 stack_load_float3(float *stack, uint a)
ccl_device_inline float stack_load_float_default(float *stack, uint a, uint value)
ccl_device_forceinline void svm_unpack_node_uchar3(uint i, uint *x, uint *y, uint *z)
ccl_device_inline void stack_store_float(float *stack, uint a, float f)
ccl_device_inline bool stack_valid(uint a)
#define kernel_assert(cond)
#define kernel_tex_fetch(tex, index)
#define ccl_device
#define ccl_device_inline
#define CCL_NAMESPACE_END
#define atan2f(x, y)
ShaderData
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
#define min(a, b)
Definition: sort.c:51
#define IES_LOOKUP_ANGLE_V(v)
#define IES_LOOKUP(v)
CCL_NAMESPACE_BEGIN ccl_device_inline float interpolate_ies_vertical(KernelGlobals *kg, int ofs, int v, int v_num, float v_frac, int h)
Definition: svm_ies.h:21
ccl_device_inline float kernel_ies_interp(KernelGlobals *kg, int slot, float h_angle, float v_angle)
Definition: svm_ies.h:42
#define IES_LOOKUP_ANGLE_H(h)
ccl_device void svm_node_ies(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
Definition: svm_ies.h:101
float max
ccl_device_inline float inverse_lerp(float a, float b, float x)
Definition: util_math.h:425
ccl_device_inline int __float_as_int(float f)
Definition: util_math.h:202
#define M_PI_F
Definition: util_math.h:43
ccl_device_inline float cubic_interp(float a, float b, float c, float d, float x)
Definition: util_math.h:431
ccl_device_inline float2 normalize(const float2 &a)