Blender V4.3
transform.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#ifndef __UTIL_TRANSFORM_H__
6#define __UTIL_TRANSFORM_H__
7
8#ifndef __KERNEL_GPU__
9# include <string.h>
10#endif
11
12#include "util/math.h"
13#include "util/types.h"
14
15#ifndef __KERNEL_GPU__
16# include "util/system.h"
17#endif
18
20
21/* Affine transformation, stored as 4x3 matrix. */
22
23typedef struct Transform {
24 float4 x, y, z;
25
26#ifndef __KERNEL_GPU__
27 float4 operator[](int i) const
28 {
29 return *(&x + i);
30 }
31 float4 &operator[](int i)
32 {
33 return *(&x + i);
34 }
35#endif
37
38/* Transform decomposed in rotation/translation/scale. we use the same data
39 * structure as Transform, and tightly pack decomposition into it. first the
40 * rotation (4), then translation (3), then 3x3 scale matrix (9). */
41
42typedef struct DecomposedTransform {
43 float4 x, y, z, w;
45
47
49
51
52/* Functions */
53
54#ifdef __KERNEL_METAL__
55/* transform_point specialized for ccl_global */
57{
58 ccl_global const float3x3 &b(*(ccl_global const float3x3 *)t);
59 return (a * b).xyz + make_float3(t->x.w, t->y.w, t->z.w);
60}
61#endif
62
64{
65 /* TODO(sergey): Disabled for now, causes crashes in certain cases. */
66#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
67 const float4 aa(a.m128);
68
69 float4 x(_mm_loadu_ps(&t->x.x));
70 float4 y(_mm_loadu_ps(&t->y.x));
71 float4 z(_mm_loadu_ps(&t->z.x));
72 float4 w(_mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f));
73
74 _MM_TRANSPOSE4_PS(x.m128, y.m128, z.m128, w.m128);
75
76 float4 tmp = w;
77 tmp = madd(shuffle<2>(aa), z, tmp);
78 tmp = madd(shuffle<1>(aa), y, tmp);
79 tmp = madd(shuffle<0>(aa), x, tmp);
80
81 return float3(tmp.m128);
82#elif defined(__KERNEL_METAL__)
83 ccl_private const float3x3 &b(*(ccl_private const float3x3 *)t);
84 return (a * b).xyz + make_float3(t->x.w, t->y.w, t->z.w);
85#else
86 float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z + t->x.w,
87 a.x * t->y.x + a.y * t->y.y + a.z * t->y.z + t->y.w,
88 a.x * t->z.x + a.y * t->z.y + a.z * t->z.z + t->z.w);
89
90 return c;
91#endif
92}
93
95{
96#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
97 const float4 aa(a.m128);
98
99 float4 x(_mm_loadu_ps(&t->x.x));
100 float4 y(_mm_loadu_ps(&t->y.x));
101 float4 z(_mm_loadu_ps(&t->z.x));
102 float4 w(_mm_setzero_ps());
103
104 _MM_TRANSPOSE4_PS(x.m128, y.m128, z.m128, w.m128);
105
106 float4 tmp = shuffle<2>(aa) * z;
107 tmp = madd(shuffle<1>(aa), y, tmp);
108 tmp = madd(shuffle<0>(aa), x, tmp);
109
110 return float3(tmp.m128);
111#elif defined(__KERNEL_METAL__)
112 ccl_private const float3x3 &b(*(ccl_private const float3x3 *)t);
113 return (a * b).xyz;
114#else
115 float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z,
116 a.x * t->y.x + a.y * t->y.y + a.z * t->y.z,
117 a.x * t->z.x + a.y * t->z.y + a.z * t->z.z);
118
119 return c;
120#endif
121}
122
124 const float3 a)
125{
126 float3 x = make_float3(t->x.x, t->y.x, t->z.x);
127 float3 y = make_float3(t->x.y, t->y.y, t->z.y);
128 float3 z = make_float3(t->x.z, t->y.z, t->z.z);
129
130 return make_float3(dot(x, a), dot(y, a), dot(z, a));
131}
132
134 float b,
135 float c,
136 float d,
137 float e,
138 float f,
139 float g,
140 float h,
141 float i,
142 float j,
143 float k,
144 float l)
145{
146 Transform t;
147
148 t.x.x = a;
149 t.x.y = b;
150 t.x.z = c;
151 t.x.w = d;
152 t.y.x = e;
153 t.y.y = f;
154 t.y.z = g;
155 t.y.w = h;
156 t.z.x = i;
157 t.z.y = j;
158 t.z.z = k;
159 t.z.w = l;
160
161 return t;
162}
163
165{
166 Transform t;
167
168 t.x = float3_to_float4(x, 0.0f);
169 t.y = float3_to_float4(y, 0.0f);
170 t.z = float3_to_float4(z, 0.0f);
171
172 return t;
173}
174
176{
177 float cx = cosf(euler.x);
178 float cy = cosf(euler.y);
179 float cz = cosf(euler.z);
180 float sx = sinf(euler.x);
181 float sy = sinf(euler.y);
182 float sz = sinf(euler.z);
183
184 Transform t;
185 t.x.x = cy * cz;
186 t.y.x = cy * sz;
187 t.z.x = -sy;
188
189 t.x.y = sy * sx * cz - cx * sz;
190 t.y.y = sy * sx * sz + cx * cz;
191 t.z.y = cy * sx;
192
193 t.x.z = sy * cx * cz + sx * sz;
194 t.y.z = sy * cx * sz - sx * cz;
195 t.z.z = cy * cx;
196
197 t.x.w = t.y.w = t.z.w = 0.0f;
198 return t;
199}
200
201/* Constructs a coordinate frame from a normalized normal. */
203{
204 const float3 dx0 = cross(make_float3(1.0f, 0.0f, 0.0f), N);
205 const float3 dx1 = cross(make_float3(0.0f, 1.0f, 0.0f), N);
206 const float3 dx = normalize((dot(dx0, dx0) > dot(dx1, dx1)) ? dx0 : dx1);
207 const float3 dy = normalize(cross(N, dx));
208 return make_transform(dx.x, dx.y, dx.z, 0.0f, dy.x, dy.y, dy.z, 0.0f, N.x, N.y, N.z, 0.0f);
209}
210
211#if !defined(__KERNEL_METAL__)
213{
214 float4 c_x = make_float4(b.x.x, b.y.x, b.z.x, 0.0f);
215 float4 c_y = make_float4(b.x.y, b.y.y, b.z.y, 0.0f);
216 float4 c_z = make_float4(b.x.z, b.y.z, b.z.z, 0.0f);
217 float4 c_w = make_float4(b.x.w, b.y.w, b.z.w, 1.0f);
218
219 Transform t;
220 t.x = make_float4(dot(a.x, c_x), dot(a.x, c_y), dot(a.x, c_z), dot(a.x, c_w));
221 t.y = make_float4(dot(a.y, c_x), dot(a.y, c_y), dot(a.y, c_z), dot(a.y, c_w));
222 t.z = make_float4(dot(a.z, c_x), dot(a.z, c_y), dot(a.z, c_z), dot(a.z, c_w));
223
224 return t;
225}
226#endif
227
228#ifndef __KERNEL_GPU__
229
231{
233 return zero;
234}
235
237{
238 print_float4(label, t.x);
239 print_float4(label, t.y);
240 print_float4(label, t.z);
241 printf("\n");
242}
243
245{
246 return make_transform(1, 0, 0, t.x, 0, 1, 0, t.y, 0, 0, 1, t.z);
247}
248
250{
251 return transform_translate(make_float3(x, y, z));
252}
253
255{
256 return make_transform(s.x, 0, 0, 0, 0, s.y, 0, 0, 0, 0, s.z, 0);
257}
258
260{
261 return transform_scale(make_float3(x, y, z));
262}
263
265{
266 float s = sinf(angle);
267 float c = cosf(angle);
268 float t = 1.0f - c;
269
270 axis = normalize(axis);
271
272 return make_transform(axis.x * axis.x * t + c,
273 axis.x * axis.y * t - s * axis.z,
274 axis.x * axis.z * t + s * axis.y,
275 0.0f,
276
277 axis.y * axis.x * t + s * axis.z,
278 axis.y * axis.y * t + c,
279 axis.y * axis.z * t - s * axis.x,
280 0.0f,
281
282 axis.z * axis.x * t - s * axis.y,
283 axis.z * axis.y * t + s * axis.x,
284 axis.z * axis.z * t + c,
285 0.0f);
286}
287
288/* Euler is assumed to be in XYZ order. */
290{
291 return transform_rotate(euler.z, make_float3(0.0f, 0.0f, 1.0f)) *
292 transform_rotate(euler.y, make_float3(0.0f, 1.0f, 0.0f)) *
293 transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f));
294}
295
297{
298 return transform_scale(1.0f, 1.0f, 1.0f);
299}
300
302{
303 return memcmp(&A, &B, sizeof(Transform)) == 0;
304}
305
307{
308 return !(A == B);
309}
310
312 const Transform &B,
313 const float threshold)
314{
315 for (int x = 0; x < 3; x++) {
316 for (int y = 0; y < 4; y++) {
317 if (fabsf(A[x][y] - B[x][y]) > threshold) {
318 return false;
319 }
320 }
321 }
322
323 return true;
324}
325
327{
328 return make_float3(t->x[column], t->y[column], t->z[column]);
329}
330
332{
333 t->x[column] = value.x;
334 t->y[column] = value.y;
335 t->z[column] = value.z;
336}
337
339
341{
342 /* the epsilon here is quite arbitrary, but this function is only used for
343 * surface area and bump, where we expect it to not be so sensitive */
344 float eps = 1e-6f;
345
346 float sx = len_squared(float4_to_float3(tfm.x));
347 float sy = len_squared(float4_to_float3(tfm.y));
348 float sz = len_squared(float4_to_float3(tfm.z));
349 float stx = len_squared(transform_get_column(&tfm, 0));
350 float sty = len_squared(transform_get_column(&tfm, 1));
351 float stz = len_squared(transform_get_column(&tfm, 2));
352
353 if (fabsf(sx - sy) < eps && fabsf(sx - sz) < eps && fabsf(sx - stx) < eps &&
354 fabsf(sx - sty) < eps && fabsf(sx - stz) < eps)
355 {
356 scale = sx;
357 return true;
358 }
359
360 return false;
361}
362
364{
365 float3 c0 = transform_get_column(&tfm, 0);
366 float3 c1 = transform_get_column(&tfm, 1);
367 float3 c2 = transform_get_column(&tfm, 2);
368
369 return (dot(cross(c0, c1), c2) < 0.0f);
370}
371
373{
374 Transform ntfm = tfm;
375
379
380 return ntfm;
381}
382
384{
385 return make_transform(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
386}
387
388#endif
389
390/* Motion Transform */
391
392ccl_device_inline float4 quat_interpolate(float4 q1, float4 q2, float t)
393{
394 /* Optix and MetalRT are using linear interpolation to interpolate motion transformations. */
395#if defined(__KERNEL_GPU_RAYTRACING__)
396 return normalize((1.0f - t) * q1 + t * q2);
397#else /* defined(__KERNEL_GPU_RAYTRACING__) */
398 /* NOTE: this does not ensure rotation around shortest angle, q1 and q2
399 * are assumed to be matched already in transform_motion_decompose */
400 float costheta = dot(q1, q2);
401
402 /* possible optimization: it might be possible to precompute theta/qperp */
403
404 if (costheta > 0.9995f) {
405 /* linear interpolation in degenerate case */
406 return normalize((1.0f - t) * q1 + t * q2);
407 }
408 else {
409 /* slerp */
410 float theta = acosf(clamp(costheta, -1.0f, 1.0f));
411 float4 qperp = normalize(q2 - q1 * costheta);
412 float thetap = theta * t;
413 return q1 * cosf(thetap) + qperp * sinf(thetap);
414 }
415#endif /* defined(__KERNEL_GPU_RAYTRACING__) */
416}
417
418#ifndef __KERNEL_GPU__
419void transform_inverse_cpu_sse42(const Transform &tfm, Transform &itfm);
420void transform_inverse_cpu_avx2(const Transform &tfm, Transform &itfm);
421#endif
422
424{
425 /* Optimized transform implementations. */
426#ifndef __KERNEL_GPU__
428 Transform itfm;
430 return itfm;
431 }
432 else if (system_cpu_support_sse42()) {
433 Transform itfm;
435 return itfm;
436 }
437#endif
438
439 return transform_inverse_impl(tfm);
440}
441
443 ccl_private const DecomposedTransform *decomp)
444{
445 /* rotation */
446 float q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc;
447
448 q0 = M_SQRT2_F * decomp->x.w;
449 q1 = M_SQRT2_F * decomp->x.x;
450 q2 = M_SQRT2_F * decomp->x.y;
451 q3 = M_SQRT2_F * decomp->x.z;
452
453 qda = q0 * q1;
454 qdb = q0 * q2;
455 qdc = q0 * q3;
456 qaa = q1 * q1;
457 qab = q1 * q2;
458 qac = q1 * q3;
459 qbb = q2 * q2;
460 qbc = q2 * q3;
461 qcc = q3 * q3;
462
463 float3 rotation_x = make_float3(1.0f - qbb - qcc, -qdc + qab, qdb + qac);
464 float3 rotation_y = make_float3(qdc + qab, 1.0f - qaa - qcc, -qda + qbc);
465 float3 rotation_z = make_float3(-qdb + qac, qda + qbc, 1.0f - qaa - qbb);
466
467 /* scale */
468 float3 scale_x = make_float3(decomp->y.w, decomp->z.z, decomp->w.y);
469 float3 scale_y = make_float3(decomp->z.x, decomp->z.w, decomp->w.z);
470 float3 scale_z = make_float3(decomp->z.y, decomp->w.x, decomp->w.w);
471
472 /* compose with translation */
473 tfm->x = make_float4(
474 dot(rotation_x, scale_x), dot(rotation_x, scale_y), dot(rotation_x, scale_z), decomp->y.x);
475 tfm->y = make_float4(
476 dot(rotation_y, scale_x), dot(rotation_y, scale_y), dot(rotation_y, scale_z), decomp->y.y);
477 tfm->z = make_float4(
478 dot(rotation_z, scale_x), dot(rotation_z, scale_y), dot(rotation_z, scale_z), decomp->y.z);
479}
480
481/* Interpolate from array of decomposed transforms. */
483 ccl_global const DecomposedTransform *motion,
484 uint numsteps,
485 float time)
486{
487 /* Figure out which steps we need to interpolate. */
488 int maxstep = numsteps - 1;
489 int step = min((int)(time * maxstep), maxstep - 1);
490 float t = time * maxstep - step;
491
492 ccl_global const DecomposedTransform *a = motion + step;
493 ccl_global const DecomposedTransform *b = motion + step + 1;
494
495 /* Interpolate rotation, translation and scale. */
496 DecomposedTransform decomp;
497 decomp.x = quat_interpolate(a->x, b->x, t);
498 decomp.y = (1.0f - t) * a->y + t * b->y;
499 decomp.z = (1.0f - t) * a->z + t * b->z;
500 decomp.w = (1.0f - t) * a->w + t * b->w;
501
502 /* Compose rotation, translation, scale into matrix. */
503 transform_compose(tfm, &decomp);
504}
505
507{
508 return isfinite_safe(tfm->x) && isfinite_safe(tfm->y) && isfinite_safe(tfm->z);
509}
510
512{
513 return isfinite_safe(decomp->x) && isfinite_safe(decomp->y) && isfinite_safe(decomp->z) &&
514 isfinite_safe(decomp->w);
515}
516
517#ifndef __KERNEL_GPU__
518
519class BoundBox2D;
520
522{
523 return memcmp(&A, &B, sizeof(DecomposedTransform)) == 0;
524}
525
527void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size);
529
530#endif
531
532/* TODO: This can be removed when we know if no devices will require explicit
533 * address space qualifiers for this case. */
534
535#define transform_point_auto transform_point
536#define transform_direction_auto transform_direction
537#define transform_direction_transposed_auto transform_direction_transposed
538
540
541#endif /* __UTIL_TRANSFORM_H__ */
unsigned int uint
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
local_group_size(16, 16) .push_constant(Type b
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#define printf
const char * label
#define sinf(x)
#define cosf(x)
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define ccl_global
#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 acosf(x)
#define fabsf(x)
CCL_NAMESPACE_BEGIN ccl_device_inline float madd(const float a, const float b, const float c)
Definition math_fast.h:29
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline float cross(const float2 a, const float2 b)
CCL_NAMESPACE_BEGIN ccl_device_inline float4 zero_float4()
Definition math_float4.h:15
#define N
#define B
VecBase< float, 4 > float4
MatBase< float, 3, 3 > float3x3
const btScalar eps
Definition poly34.cpp:11
#define min(a, b)
Definition sort.c:32
float4 & operator[](int i)
Definition transform.h:31
float4 operator[](int i) const
Definition transform.h:27
float4 y
Definition transform.h:24
float4 x
Definition transform.h:24
float4 z
Definition transform.h:24
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
bool system_cpu_support_avx2()
Definition system.cpp:227
bool system_cpu_support_sse42()
Definition system.cpp:222
Transform transform_transposed_inverse(const Transform &a)
ccl_device_inline Transform make_transform_frame(float3 N)
Definition transform.h:202
ccl_device_inline Transform euler_to_transform(const float3 euler)
Definition transform.h:175
ccl_device_inline Transform transform_identity()
Definition transform.h:296
ccl_device_inline void print_transform(const char *label, const Transform &t)
Definition transform.h:236
ccl_device void transform_motion_array_interpolate(ccl_private Transform *tfm, ccl_global const DecomposedTransform *motion, uint numsteps, float time)
Definition transform.h:482
ccl_device_inline Transform transform_empty()
Definition transform.h:383
ccl_device_inline Transform transform_rotate(float angle, float3 axis)
Definition transform.h:264
ccl_device_inline bool transform_equal_threshold(const Transform &A, const Transform &B, const float threshold)
Definition transform.h:311
ccl_device_inline void transform_set_column(Transform *t, int column, float3 value)
Definition transform.h:331
ccl_device_inline float4 quat_interpolate(float4 q1, float4 q2, float t)
Definition transform.h:392
void transform_inverse_cpu_avx2(const Transform &tfm, Transform &itfm)
ccl_device_inline Transform transform_euler(float3 euler)
Definition transform.h:289
ccl_device_inline bool transform_decomposed_isfinite_safe(ccl_private DecomposedTransform *decomp)
Definition transform.h:511
ccl_device_inline float3 transform_get_column(const Transform *t, int column)
Definition transform.h:326
struct DecomposedTransform DecomposedTransform
ccl_device_inline bool transform_negative_scale(const Transform &tfm)
Definition transform.h:363
float4 transform_to_quat(const Transform &tfm)
ccl_device_inline Transform make_transform(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l)
Definition transform.h:133
ccl_device_inline bool transform_isfinite_safe(ccl_private Transform *tfm)
Definition transform.h:506
ccl_device_inline Transform transform_translate(float3 t)
Definition transform.h:244
void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size)
ccl_device_inline Transform transform_inverse(const Transform tfm)
Definition transform.h:423
ccl_device_inline Transform transform_zero()
Definition transform.h:230
ccl_device_inline float3 transform_direction(ccl_private const Transform *t, const float3 a)
Definition transform.h:94
void transform_inverse_cpu_sse42(const Transform &tfm, Transform &itfm)
ccl_device_inline Transform transform_scale(float3 s)
Definition transform.h:254
ccl_device_inline bool transform_uniform_scale(const Transform &tfm, float &scale)
Definition transform.h:340
Transform transform_from_viewplane(BoundBox2D &viewplane)
CCL_NAMESPACE_BEGIN struct Transform Transform
ccl_device_inline bool operator!=(const Transform &A, const Transform &B)
Definition transform.h:306
ccl_device_inline bool operator==(const Transform &A, const Transform &B)
Definition transform.h:301
ccl_device_inline Transform transform_clear_scale(const Transform &tfm)
Definition transform.h:372
ccl_device_inline float3 transform_direction_transposed(ccl_private const Transform *t, const float3 a)
Definition transform.h:123
ccl_device_inline void transform_compose(ccl_private Transform *tfm, ccl_private const DecomposedTransform *decomp)
Definition transform.h:442
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
Definition transform.h:63
ccl_device_inline Transform operator*(const Transform a, const Transform b)
Definition transform.h:212
ccl_device_forceinline Transform transform_inverse_impl(const Transform tfm)
ccl_device_inline void print_float4(ccl_private const char *label, const float4 a)
ccl_device_inline bool isfinite_safe(float f)
Definition util/math.h:365
ccl_device_inline float4 float3_to_float4(const float3 a)
Definition util/math.h:540
ccl_device_inline float3 float4_to_float3(const float4 a)
Definition util/math.h:535
ccl_device_inline int clamp(int a, int mn, int mx)
Definition util/math.h:379