Blender V5.0
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 "kernel/types.h"
11
12#include "util/math.h"
13#include "util/types.h"
14
16
17/* Equirectangular coordinates <-> Cartesian direction */
18
20{
21 if (is_zero(dir)) {
22 return zero_float2();
23 }
24
25 const float u = (atan2f(dir.y, dir.x) - range.y) / range.x;
26 const float v = (acosf(dir.z / len(dir)) - range.w) / range.z;
27
28 return make_float2(u, v);
29}
30
32 const float v,
33 const float4 range)
34{
35 const float phi = range.x * u + range.y;
36 const float theta = range.z * v + range.w;
37 return spherical_to_direction(theta, phi);
38}
39
44
49
51{
52 const float z = dir.z / len(make_float2(dir.x, dir.y));
53 const float theta = atan2f(dir.y, dir.x);
54 const float u = inverse_lerp(range.x, range.y, theta);
55 const float v = inverse_lerp(range.z, range.w, z);
56 return make_float2(u, v);
57}
58
60 const float v,
61 const float4 range)
62{
63 const float theta = mix(range.x, range.y, u);
64 const float z = mix(range.z, range.w, v);
65 return make_float3(cosf(theta), sinf(theta), z);
66}
67
68/* Fisheye <-> Cartesian direction */
69
71 const float u,
72 float v,
73 const float r)
74{
75 float phi = safe_acosf(safe_divide(u, r));
76 if (v < 0.0f) {
77 phi = -phi;
78 }
79
80 return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
81}
82
84{
85 const float r = atan2f(len(make_float2(dir.y, dir.z)), dir.x) / fov;
86 const float2 uv = r * safe_normalize(make_float2(dir.y, dir.z));
87 return make_float2(0.5f - uv.x, uv.y + 0.5f);
88}
89
91{
92 u = (u - 0.5f) * 2.0f;
93 v = (v - 0.5f) * 2.0f;
94
95 const float r = sqrtf(u * u + v * v);
96
97 if (r > 1.0f) {
98 return zero_float3();
99 }
100
101 const float theta = r * fov * 0.5f;
102
103 return fisheye_to_direction(theta, u, v, r);
104}
105
107 const float lens,
108 const float width,
109 const float height)
110{
111 const float theta = safe_acosf(dir.x);
112 const float r = 2.0f * lens * sinf(theta * 0.5f);
113
114 const float2 uv = r * safe_normalize(make_float2(dir.y, dir.z));
115 return make_float2(0.5f - uv.x / width, uv.y / height + 0.5f);
116}
117
119 float u, float v, float lens, const float fov, const float width, const float height)
120{
121 u = (u - 0.5f) * width;
122 v = (v - 0.5f) * height;
123
124 const float rmax = 2.0f * lens * sinf(fov * 0.25f);
125 const float r = sqrtf(u * u + v * v);
126
127 if (r > rmax) {
128 return zero_float3();
129 }
130
131 const float theta = 2.0f * asinf(r / (2.0f * lens));
132
133 return fisheye_to_direction(theta, u, v, r);
134}
135
137 float v,
138 float coeff0,
139 const float4 coeffs,
140 const float fov,
141 const float width,
142 const float height)
143{
144 u = (u - 0.5f) * width;
145 v = (v - 0.5f) * height;
146
147 const float r = sqrtf(u * u + v * v);
148 const float r2 = r * r;
149 const float4 rr = make_float4(r, r2, r2 * r, r2 * r2);
150 const float theta = -(coeff0 + dot(coeffs, rr));
151
152 if (fabsf(theta) > 0.5f * fov) {
153 return zero_float3();
154 }
155
156 return fisheye_to_direction(theta, u, v, r);
157}
158
160 float3 dir, const float coeff0, const float4 coeffs, const float width, const float height)
161{
162 const float theta = -safe_acosf(dir.x);
163
164 /* Initialize r with the closed-form solution for the special case
165 * coeffs.y = coeffs.z = coeffs.w = 0 */
166 float r = (theta - coeff0) / coeffs.x;
167
168 const float4 diff_coeffs = make_float4(1.0f, 2.0f, 3.0f, 4.0f) * coeffs;
169
170 for (int i = 0; i < 20; i++) {
171 /* Newton's method for finding roots
172 *
173 * Given is the result theta = distortion_model(r),
174 * we need to find r.
175 * Let F(r) := theta - distortion_model(r).
176 * Then F(r) = 0 <=> distortion_model(r) = theta
177 * Therefore we apply Newton's method for finding a root of F(r).
178 * Newton step for the function F:
179 * r_n+1 = r_n - F(r_n) / F'(r_n)
180 * The addition in the implementation is due to canceling of signs.
181 * \{ */
182 const float old_r = r;
183 const float r2 = r * r;
184 const float F_r = theta - (coeff0 + dot(coeffs, make_float4(r, r2, r2 * r, r2 * r2)));
185 const float dF_r = dot(diff_coeffs, make_float4(1.0f, r, r2, r2 * r));
186 r += F_r / dF_r;
187
188 /* Early termination if the change is below the threshold */
189 if (fabsf(r - old_r) < 1e-6f) {
190 break;
191 }
193 }
194
195 const float2 uv = r * safe_normalize(make_float2(dir.y, dir.z));
196 return make_float2(0.5f - uv.x / width, uv.y / height + 0.5f);
197}
198
199/* Mirror Ball <-> Cartesion direction */
200
201ccl_device float3 mirrorball_to_direction(const float u, const float v)
202{
203 /* point on sphere */
204 float3 dir;
205
206 dir.x = 2.0f * u - 1.0f;
207 dir.z = 2.0f * v - 1.0f;
208
209 if (dir.x * dir.x + dir.z * dir.z > 1.0f) {
210 return zero_float3();
211 }
212
213 dir.y = -sqrtf(max(1.0f - dir.x * dir.x - dir.z * dir.z, 0.0f));
214
215 /* reflection */
216 const float3 I = make_float3(0.0f, -1.0f, 0.0f);
217
218 return 2.0f * dot(dir, I) * dir - I;
219}
220
222{
223 /* inverse of mirrorball_to_direction */
224 dir.y -= 1.0f;
225
226 const float div = 2.0f * sqrtf(max(-0.5f * dir.y, 0.0f));
227 if (div > 0.0f) {
228 dir /= div;
229 }
230
231 const float u = 0.5f * (dir.x + 1.0f);
232 const float v = 0.5f * (dir.z + 1.0f);
233
234 return make_float2(u, v);
235}
236
237/* Single face of a equiangular cube map projection as described in
238 * https://blog.google/products/google-ar-vr/bringing-pixels-front-and-center-vr-video/ */
240{
241 u = tanf((0.5f - u) * M_PI_2_F);
242 v = tanf((v - 0.5f) * M_PI_2_F);
243
244 return normalize(make_float3(1.0f, u, v));
245}
246
248{
249 const float u = 0.5f - atan2f(dir.y, dir.x) * 2.0f / M_PI_F;
250 const float v = atan2f(dir.z, dir.x) * 2.0f / M_PI_F + 0.5f;
251
252 return make_float2(u, v);
253}
254
256 const float u,
257 float v)
258{
259 switch (cam->panorama_type) {
261 return equirectangular_range_to_direction(u, v, cam->equirectangular_range);
265 return mirrorball_to_direction(u, v);
267 return fisheye_equidistant_to_direction(u, v, cam->fisheye_fov);
270 v,
271 cam->fisheye_lens_polynomial_bias,
272 cam->fisheye_lens_polynomial_coefficients,
273 cam->fisheye_fov,
274 cam->sensorwidth,
275 cam->sensorheight);
277 return central_cylindrical_to_direction(u, v, cam->central_cylindrical_range);
279 default:
281 u, v, cam->fisheye_lens, cam->fisheye_fov, cam->sensorwidth, cam->sensorheight);
282 }
283}
284
286{
287 switch (cam->panorama_type) {
289 return direction_to_equirectangular_range(dir, cam->equirectangular_range);
293 return direction_to_mirrorball(dir);
295 return direction_to_fisheye_equidistant(dir, cam->fisheye_fov);
298 cam->fisheye_lens_polynomial_bias,
299 cam->fisheye_lens_polynomial_coefficients,
300 cam->sensorwidth,
301 cam->sensorheight);
303 return direction_to_central_cylindrical(dir, cam->central_cylindrical_range);
305 default:
307 dir, cam->fisheye_lens, cam->sensorwidth, cam->sensorheight);
308 }
309}
310
314{
315 float interocular_offset = cam->interocular_offset;
316
317 /* Interocular offset of zero means either non stereo, or stereo without
318 * spherical stereo. */
319 kernel_assert(interocular_offset != 0.0f);
320
321 if (cam->pole_merge_angle_to > 0.0f) {
322 const float pole_merge_angle_from = cam->pole_merge_angle_from;
323 const float pole_merge_angle_to = cam->pole_merge_angle_to;
324 const float altitude = fabsf(safe_asinf((*D).z));
325 if (altitude > pole_merge_angle_to) {
326 interocular_offset = 0.0f;
327 }
328 else if (altitude > pole_merge_angle_from) {
329 const float fac = (altitude - pole_merge_angle_from) /
330 (pole_merge_angle_to - pole_merge_angle_from);
331 const float fade = cosf(fac * M_PI_2_F);
332 interocular_offset *= fade;
333 }
334 }
335
336 const float3 up = make_float3(0.0f, 0.0f, 1.0f);
337 const float3 side = normalize(cross(*D, up));
338 const float3 stereo_offset = side * interocular_offset;
339
340 *P += stereo_offset;
341
342 /* Convergence distance is FLT_MAX in the case of parallel convergence mode,
343 * no need to modify direction in this case either. */
344 const float convergence_distance = cam->convergence_distance;
345
346 if (convergence_distance != FLT_MAX) {
347 const float3 screen_offset = convergence_distance * (*D);
348 *D = normalize(screen_offset - stereo_offset);
349 }
350}
351
#define D
MINLINE float safe_acosf(float a)
MINLINE float safe_divide(float a, float b)
MINLINE float safe_asinf(float a)
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
ccl_device float3 equiangular_cubemap_face_to_direction(float u, float v)
CCL_NAMESPACE_BEGIN ccl_device float2 direction_to_equirectangular_range(const float3 dir, const float4 range)
ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, const float3 dir)
ccl_device float2 direction_to_mirrorball(float3 dir)
ccl_device float2 direction_to_fisheye_equidistant(const float3 dir, const float fov)
ccl_device_inline float3 fisheye_to_direction(const float theta, const float u, float v, const float r)
ccl_device_inline float3 fisheye_lens_polynomial_to_direction(float u, float v, float coeff0, const float4 coeffs, const float fov, const float width, const float height)
ccl_device float3 fisheye_equidistant_to_direction(float u, float v, float fov)
ccl_device float2 direction_to_fisheye_equisolid(const float3 dir, const float lens, const float width, const float height)
ccl_device_inline void spherical_stereo_transform(ccl_constant KernelCamera *cam, ccl_private float3 *P, ccl_private float3 *D)
ccl_device_inline float3 fisheye_equisolid_to_direction(float u, float v, float lens, const float fov, const float width, const float height)
ccl_device float2 direction_to_fisheye_lens_polynomial(float3 dir, const float coeff0, const float4 coeffs, const float width, const float height)
ccl_device float2 direction_to_central_cylindrical(const float3 dir, const float4 range)
ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, const float u, float v)
ccl_device float3 equirectangular_range_to_direction(const float u, const float v, const float4 range)
ccl_device float3 mirrorball_to_direction(const float u, const float v)
ccl_device float2 direction_to_equiangular_cubemap_face(const float3 dir)
ccl_device float3 central_cylindrical_to_direction(const float u, const float v, const float4 range)
ccl_device float2 direction_to_equirectangular(const float3 dir)
ccl_device float3 equirectangular_to_direction(const float u, const float v)
ccl_device float3 spherical_to_direction(const float theta, const float phi)
#define kernel_assert(cond)
#define M_PI_2_F
#define ccl_constant
#define ccl_private
#define ccl_device_inline
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define asinf(x)
#define acosf(x)
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
@ PANORAMA_MIRRORBALL
@ PANORAMA_FISHEYE_EQUISOLID
@ PANORAMA_CENTRAL_CYLINDRICAL
@ PANORAMA_EQUIANGULAR_CUBEMAP_FACE
@ PANORAMA_FISHEYE_EQUIDISTANT
@ PANORAMA_FISHEYE_LENS_POLYNOMIAL
@ PANORAMA_EQUIRECTANGULAR
ccl_device_inline float inverse_lerp(const float a, const float b, const float x)
Definition math_base.h:507
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
Definition math_float2.h:13
ccl_device_inline bool is_zero(const float2 a)
ccl_device_inline float2 safe_normalize(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:17
#define I
CCL_NAMESPACE_BEGIN ccl_device float fade(const float t)
Definition noise.h:18
#define mix
#define fabsf
#define sqrtf
#define ccl_device
#define M_2PI_F
#define sinf
#define make_float2
#define tanf
#define make_float4
#define M_PI_F
#define cosf
#define atan2f
#define FLT_MAX
Definition stdcycles.h:14
float x
float y
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
float y
Definition sky_math.h:225
float z
Definition sky_math.h:225
float x
Definition sky_math.h:225
float w
Definition sky_math.h:225
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len