Blender V4.3
cycles/kernel/camera/projection.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al.
2 * SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Adapted code from Open Shading Language. */
7
8#pragma once
9
10#include "util/math.h"
11#include "util/types.h"
12
14
15/* Spherical coordinates <-> Cartesian direction. */
16
18{
19 float theta = safe_acosf(dir.z);
20 float phi = atan2f(dir.x, dir.y);
21
22 return make_float2(theta, phi);
23}
24
26{
27 float sin_theta = sinf(theta);
28 return make_float3(sin_theta * sinf(phi), sin_theta * cosf(phi), cosf(theta));
29}
30
31/* Equirectangular coordinates <-> Cartesian direction */
32
34{
35 if (is_zero(dir))
36 return zero_float2();
37
38 float u = (atan2f(dir.y, dir.x) - range.y) / range.x;
39 float v = (acosf(dir.z / len(dir)) - range.w) / range.z;
40
41 return make_float2(u, v);
42}
43
45{
46 float phi = range.x * u + range.y;
47 float theta = range.z * v + range.w;
48 float sin_theta = sinf(theta);
49 return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta));
50}
51
56
61
63{
64 const float z = dir.z / len(make_float2(dir.x, dir.y));
65 const float theta = atan2f(dir.y, dir.x);
66 const float u = inverse_lerp(range.x, range.y, theta);
67 const float v = inverse_lerp(range.z, range.w, z);
68 return make_float2(u, v);
69}
70
72{
73 const float theta = mix(range.x, range.y, u);
74 const float z = mix(range.z, range.w, v);
75 return make_float3(cosf(theta), sinf(theta), z);
76}
77
78/* Fisheye <-> Cartesian direction */
79
81{
82 const float r = atan2f(len(make_float2(dir.y, dir.z)), dir.x) / fov;
83 const float2 uv = r * safe_normalize(make_float2(dir.y, dir.z));
84 return make_float2(0.5f - uv.x, uv.y + 0.5f);
85}
86
87ccl_device float3 fisheye_to_direction(float u, float v, float fov)
88{
89 u = (u - 0.5f) * 2.0f;
90 v = (v - 0.5f) * 2.0f;
91
92 float r = sqrtf(u * u + v * v);
93
94 if (r > 1.0f)
95 return zero_float3();
96
97 float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
98 float theta = r * fov * 0.5f;
99
100 if (v < 0.0f)
101 phi = -phi;
102
103 return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
104}
105
106ccl_device float2 direction_to_fisheye_equisolid(float3 dir, float lens, float width, float height)
107{
108 const float theta = safe_acosf(dir.x);
109 const float r = 2.0f * lens * sinf(theta * 0.5f);
110
111 const float2 uv = r * safe_normalize(make_float2(dir.y, dir.z));
112 return make_float2(0.5f - uv.x / width, uv.y / height + 0.5f);
113}
114
116fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float width, float height)
117{
118 u = (u - 0.5f) * width;
119 v = (v - 0.5f) * height;
120
121 float rmax = 2.0f * lens * sinf(fov * 0.25f);
122 float r = sqrtf(u * u + v * v);
123
124 if (r > rmax)
125 return zero_float3();
126
127 float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
128 float theta = 2.0f * asinf(r / (2.0f * lens));
129
130 if (v < 0.0f)
131 phi = -phi;
132
133 return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
134}
135
137 float u, float v, float coeff0, float4 coeffs, float fov, float width, float height)
138{
139 u = (u - 0.5f) * width;
140 v = (v - 0.5f) * height;
141
142 float r = sqrtf(u * u + v * v);
143 float r2 = r * r;
144 float4 rr = make_float4(r, r2, r2 * r, r2 * r2);
145 float theta = -(coeff0 + dot(coeffs, rr));
146
147 if (fabsf(theta) > 0.5f * fov)
148 return zero_float3();
149
150 float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
151
152 if (v < 0.0f)
153 phi = -phi;
154
155 return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
156}
157
159 float3 dir, float coeff0, float4 coeffs, float width, float height)
160{
161 const float theta = -safe_acosf(dir.x);
162
163 /* Initialize r with the closed-form solution for the special case
164 * coeffs.y = coeffs.z = coeffs.w = 0 */
165 float r = (theta - coeff0) / coeffs.x;
166
167 const float4 diff_coeffs = make_float4(1.0f, 2.0f, 3.0f, 4.0f) * coeffs;
168
169 for (int i = 0; i < 20; i++) {
170 /* Newton's method for finding roots
171 *
172 * Given is the result theta = distortion_model(r),
173 * we need to find r.
174 * Let F(r) := theta - distortion_model(r).
175 * Then F(r) = 0 <=> distortion_model(r) = theta
176 * Therefore we apply Newton's method for finding a root of F(r).
177 * Newton step for the function F:
178 * r_n+1 = r_n - F(r_n) / F'(r_n)
179 * The addition in the implementation is due to canceling of signs.
180 * \{ */
181 const float old_r = r, r2 = r * r;
182 const float F_r = theta - (coeff0 + dot(coeffs, make_float4(r, r2, r2 * r, r2 * r2)));
183 const float dF_r = dot(diff_coeffs, make_float4(1.0f, r, r2, r2 * r));
184 r += F_r / dF_r;
185
186 /* Early termination if the change is below the threshold */
187 if (fabsf(r - old_r) < 1e-6f) {
188 break;
189 }
191 }
192
193 const float2 uv = r * safe_normalize(make_float2(dir.y, dir.z));
194 return make_float2(0.5f - uv.x / width, uv.y / height + 0.5f);
195}
196
197/* Mirror Ball <-> Cartesion direction */
198
200{
201 /* point on sphere */
202 float3 dir;
203
204 dir.x = 2.0f * u - 1.0f;
205 dir.z = 2.0f * v - 1.0f;
206
207 if (dir.x * dir.x + dir.z * dir.z > 1.0f)
208 return zero_float3();
209
210 dir.y = -sqrtf(max(1.0f - dir.x * dir.x - dir.z * dir.z, 0.0f));
211
212 /* reflection */
213 float3 I = make_float3(0.0f, -1.0f, 0.0f);
214
215 return 2.0f * dot(dir, I) * dir - I;
216}
217
219{
220 /* inverse of mirrorball_to_direction */
221 dir.y -= 1.0f;
222
223 float div = 2.0f * sqrtf(max(-0.5f * dir.y, 0.0f));
224 if (div > 0.0f)
225 dir /= div;
226
227 float u = 0.5f * (dir.x + 1.0f);
228 float v = 0.5f * (dir.z + 1.0f);
229
230 return make_float2(u, v);
231}
232
233/* Single face of a equiangular cube map projection as described in
234 * https://blog.google/products/google-ar-vr/bringing-pixels-front-and-center-vr-video/ */
236{
237 u = tanf((0.5f - u) * M_PI_2_F);
238 v = tanf((v - 0.5f) * M_PI_2_F);
239
240 return normalize(make_float3(1.0f, u, v));
241}
242
244{
245 float u = 0.5f - atan2f(dir.y, dir.x) * 2.0f / M_PI_F;
246 float v = atan2f(dir.z, dir.x) * 2.0f / M_PI_F + 0.5f;
247
248 return make_float2(u, v);
249}
250
252{
253 switch (cam->panorama_type) {
255 return equirectangular_range_to_direction(u, v, cam->equirectangular_range);
259 return mirrorball_to_direction(u, v);
261 return fisheye_to_direction(u, v, cam->fisheye_fov);
264 v,
265 cam->fisheye_lens_polynomial_bias,
266 cam->fisheye_lens_polynomial_coefficients,
267 cam->fisheye_fov,
268 cam->sensorwidth,
269 cam->sensorheight);
271 return central_cylindrical_to_direction(u, v, cam->central_cylindrical_range);
273 default:
275 u, v, cam->fisheye_lens, cam->fisheye_fov, cam->sensorwidth, cam->sensorheight);
276 }
277}
278
280{
281 switch (cam->panorama_type) {
283 return direction_to_equirectangular_range(dir, cam->equirectangular_range);
287 return direction_to_mirrorball(dir);
289 return direction_to_fisheye(dir, cam->fisheye_fov);
292 cam->fisheye_lens_polynomial_bias,
293 cam->fisheye_lens_polynomial_coefficients,
294 cam->sensorwidth,
295 cam->sensorheight);
297 return direction_to_central_cylindrical(dir, cam->central_cylindrical_range);
299 default:
301 dir, cam->fisheye_lens, cam->sensorwidth, cam->sensorheight);
302 }
303}
304
308{
309 float interocular_offset = cam->interocular_offset;
310
311 /* Interocular offset of zero means either non stereo, or stereo without
312 * spherical stereo. */
313 kernel_assert(interocular_offset != 0.0f);
314
315 if (cam->pole_merge_angle_to > 0.0f) {
316 const float pole_merge_angle_from = cam->pole_merge_angle_from,
317 pole_merge_angle_to = cam->pole_merge_angle_to;
318 float altitude = fabsf(safe_asinf((*D).z));
319 if (altitude > pole_merge_angle_to) {
320 interocular_offset = 0.0f;
321 }
322 else if (altitude > pole_merge_angle_from) {
323 float fac = (altitude - pole_merge_angle_from) /
324 (pole_merge_angle_to - pole_merge_angle_from);
325 float fade = cosf(fac * M_PI_2_F);
326 interocular_offset *= fade;
327 }
328 }
329
330 float3 up = make_float3(0.0f, 0.0f, 1.0f);
331 float3 side = normalize(cross(*D, up));
332 float3 stereo_offset = side * interocular_offset;
333
334 *P += stereo_offset;
335
336 /* Convergence distance is FLT_MAX in the case of parallel convergence mode,
337 * no need to modify direction in this case either. */
338 const float convergence_distance = cam->convergence_distance;
339
340 if (convergence_distance != FLT_MAX) {
341 float3 screen_offset = convergence_distance * (*D);
342 *D = normalize(screen_offset - stereo_offset);
343 }
344}
345
MINLINE float safe_acosf(float a)
MINLINE float safe_asinf(float a)
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_inline float sin_theta(const float3 w)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
ccl_device float3 equiangular_cubemap_face_to_direction(float u, float v)
ccl_device float2 direction_to_fisheye(float3 dir, float fov)
ccl_device float3 fisheye_to_direction(float u, float v, float fov)
ccl_device float2 direction_to_mirrorball(float3 dir)
ccl_device float2 direction_to_equiangular_cubemap_face(float3 dir)
ccl_device float2 direction_to_fisheye_lens_polynomial(float3 dir, float coeff0, float4 coeffs, float width, float height)
CCL_NAMESPACE_BEGIN ccl_device float2 direction_to_spherical(float3 dir)
ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, float u, float v)
ccl_device float2 direction_to_central_cylindrical(float3 dir, float4 range)
ccl_device float2 direction_to_equirectangular_range(float3 dir, float4 range)
ccl_device_inline void spherical_stereo_transform(ccl_constant KernelCamera *cam, ccl_private float3 *P, ccl_private float3 *D)
ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, float3 dir)
ccl_device float3 equirectangular_to_direction(float u, float v)
ccl_device float2 direction_to_equirectangular(float3 dir)
ccl_device float2 direction_to_fisheye_equisolid(float3 dir, float lens, float width, float height)
ccl_device_inline float3 fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float width, float height)
ccl_device float3 spherical_to_direction(float theta, float phi)
ccl_device float3 equirectangular_range_to_direction(float u, float v, float4 range)
ccl_device float3 mirrorball_to_direction(float u, float v)
ccl_device float3 central_cylindrical_to_direction(float u, float v, float4 range)
ccl_device_inline float3 fisheye_lens_polynomial_to_direction(float u, float v, float coeff0, float4 coeffs, float fov, float width, float height)
#define kernel_assert(cond)
#define sinf(x)
#define cosf(x)
#define ccl_device
#define ccl_constant
#define ccl_private
#define ccl_device_inline
#define tanf(x)
#define CCL_NAMESPACE_END
ccl_device_forceinline float4 make_float4(const float x, const float y, const float z, const float w)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define atan2f(x, y)
#define asinf(x)
#define acosf(x)
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define fabsf(x)
#define sqrtf(x)
int len
#define mix(a, b, c)
Definition hash.h:36
@ PANORAMA_MIRRORBALL
@ PANORAMA_FISHEYE_EQUISOLID
@ PANORAMA_CENTRAL_CYLINDRICAL
@ PANORAMA_EQUIANGULAR_CUBEMAP_FACE
@ PANORAMA_FISHEYE_EQUIDISTANT
@ PANORAMA_FISHEYE_LENS_POLYNOMIAL
@ PANORAMA_EQUIRECTANGULAR
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
Definition math_float2.h:14
ccl_device_inline bool is_zero(const float2 a)
ccl_device_inline float2 safe_normalize(const float2 a)
ccl_device_inline float cross(const float2 a, const float2 b)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:15
#define M_PI_F
Definition mikk_util.hh:15
#define I
CCL_NAMESPACE_BEGIN ccl_device float fade(float t)
Definition noise.h:14
#define M_PI_2_F
Definition sky_float3.h:20
#define M_2PI_F
Definition sky_float3.h:23
#define FLT_MAX
Definition stdcycles.h:14
float x
float y
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
float max
ccl_device_inline float inverse_lerp(float a, float b, float x)
Definition util/math.h:550