Blender V5.0
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#pragma once
6
7#ifndef __KERNEL_GPU__
8# include <cstring>
9#endif
10
11#include "util/math.h"
12#include "util/types.h"
13
14#ifndef __KERNEL_GPU__
15# include "util/system.h"
16#endif
17
19
20/* Affine transformation, stored as 4x3 matrix. */
21
22struct Transform {
24
25#ifndef __KERNEL_GPU__
26 float4 operator[](int i) const
27 {
28 return *(&x + i);
29 }
31 {
32 return *(&x + i);
33 }
34#endif
35};
36
37/* Transform decomposed in rotation/translation/scale. we use the same data
38 * structure as Transform, and tightly pack decomposition into it. first the
39 * rotation (4), then translation (3), then 3x3 scale matrix (9). */
40
42 float4 x, y, z, w;
43};
44
45/* Functions */
46
47#ifdef __KERNEL_METAL__
48/* transform_point specialized for ccl_global */
50{
51 const ccl_global float3x3 &b(*(const ccl_global float3x3 *)t);
52 return (a * b).xyz + make_float3(t->x.w, t->y.w, t->z.w);
53}
54#endif
55
57{
58#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
59 const float4 aa(a.m128);
60 float4 x = t->x;
61 float4 y = t->y;
62 float4 z = t->z;
63 float4 w(_mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f));
64 _MM_TRANSPOSE4_PS(x.m128, y.m128, z.m128, w.m128);
65 float4 tmp = w;
66 tmp = madd(shuffle<2>(aa), z, tmp);
67 tmp = madd(shuffle<1>(aa), y, tmp);
68 tmp = madd(shuffle<0>(aa), x, tmp);
69 return float3(tmp.m128);
70#elif defined(__KERNEL_METAL__)
71 const ccl_private float3x3 &b(*(const ccl_private float3x3 *)t);
72 return (a * b).xyz + make_float3(t->x.w, t->y.w, t->z.w);
73#else
74 const float4 a_ = make_homogeneous(a);
75 return make_float3(dot(a_, t->x), dot(a_, t->y), dot(a_, t->z));
76#endif
77}
78
80{
81#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
82 /* NOTE: `dot()` has large lantency on Intel platforms, the following method of transpose + madd
83 * is faster. However, we did not measure on Neon platforms, it might be that `dot()` is fine
84 * there, and we can use the simpler implementation at the end of the function. */
85 float4 x = t->x;
86 float4 y = t->y;
87 float4 z = t->z;
88 float4 w(_mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f));
89 _MM_TRANSPOSE4_PS(x.m128, y.m128, z.m128, w.m128);
90
91 float4 tmp = w;
93 {
94 const float4 aa(a.val.m128);
95 tmp = madd(shuffle<2>(aa), z, tmp);
96 tmp = madd(shuffle<1>(aa), y, tmp);
97 tmp = madd(shuffle<0>(aa), x, tmp);
98 result.val = float3(tmp.m128);
99 }
100
101 {
102 const float4 dx(a.dx.m128);
103 tmp = shuffle<2>(dx) * z;
104 tmp = madd(shuffle<1>(dx), y, tmp);
105 tmp = madd(shuffle<0>(dx), x, tmp);
106 result.dx = float3(tmp.m128);
107 }
108
109 {
110 const float4 dy(a.dy.m128);
111 tmp = shuffle<2>(dy) * z;
112 tmp = madd(shuffle<1>(dy), y, tmp);
113 tmp = madd(shuffle<0>(dy), x, tmp);
114 result.dy = float3(tmp.m128);
115 }
116
117 return result;
118#elif defined(__KERNEL_METAL__)
119 const ccl_private float3x3 &b(*(const ccl_private float3x3 *)t);
120 return {(a.val * b).xyz + make_float3(t->x.w, t->y.w, t->z.w), (a.dx * b).xyz, (a.dy * b).xyz};
121#else
122 const dual4 a_ = make_homogeneous(a);
123 return make_float3(dot(a_, t->x), dot(a_, t->y), dot(a_, t->z));
124#endif
125}
126
128{
129#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
130 const float4 aa(a.m128);
131 float4 x = t->x;
132 float4 y = t->y;
133 float4 z = t->z;
134 float4 w(_mm_setzero_ps());
135 _MM_TRANSPOSE4_PS(x.m128, y.m128, z.m128, w.m128);
136 float4 tmp = shuffle<2>(aa) * z;
137 tmp = madd(shuffle<1>(aa), y, tmp);
138 tmp = madd(shuffle<0>(aa), x, tmp);
139 return float3(tmp.m128);
140#elif defined(__KERNEL_METAL__)
141 const ccl_private float3x3 &b(*(const ccl_private float3x3 *)t);
142 return (a * b).xyz;
143#else
144 const float4 a_ = make_float4(a, 0.0f);
145 return make_float3(dot(a_, t->x), dot(a_, t->y), dot(a_, t->z));
146#endif
147}
148
150 const float3 a)
151{
152 const float3 x = make_float3(t->x.x, t->y.x, t->z.x);
153 const float3 y = make_float3(t->x.y, t->y.y, t->z.y);
154 const float3 z = make_float3(t->x.z, t->y.z, t->z.z);
155
156 return make_float3(dot(x, a), dot(y, a), dot(z, a));
157}
158
160 const float b,
161 const float c,
162 const float d,
163 const float e,
164 const float f,
165 const float g,
166 const float h,
167 const float i,
168 const float j,
169 const float k,
170 const float l)
171{
172 Transform t;
173
174 t.x.x = a;
175 t.x.y = b;
176 t.x.z = c;
177 t.x.w = d;
178 t.y.x = e;
179 t.y.y = f;
180 t.y.z = g;
181 t.y.w = h;
182 t.z.x = i;
183 t.z.y = j;
184 t.z.z = k;
185 t.z.w = l;
186
187 return t;
188}
189
191{
192 Transform t;
193
194 t.x = make_float4(x, 0.0f);
195 t.y = make_float4(y, 0.0f);
196 t.z = make_float4(z, 0.0f);
197
198 return t;
199}
200
202{
203 const float cx = cosf(euler.x);
204 const float cy = cosf(euler.y);
205 const float cz = cosf(euler.z);
206 const float sx = sinf(euler.x);
207 const float sy = sinf(euler.y);
208 const float sz = sinf(euler.z);
209
210 Transform t;
211 t.x.x = cy * cz;
212 t.y.x = cy * sz;
213 t.z.x = -sy;
214
215 t.x.y = sy * sx * cz - cx * sz;
216 t.y.y = sy * sx * sz + cx * cz;
217 t.z.y = cy * sx;
218
219 t.x.z = sy * cx * cz + sx * sz;
220 t.y.z = sy * cx * sz - sx * cz;
221 t.z.z = cy * cx;
222
223 t.x.w = t.y.w = t.z.w = 0.0f;
224 return t;
225}
226
227/* Constructs a coordinate frame from a normalized normal. */
229{
230 const float3 dx0 = cross(make_float3(1.0f, 0.0f, 0.0f), N);
231 const float3 dx1 = cross(make_float3(0.0f, 1.0f, 0.0f), N);
232 const float3 dx = normalize((dot(dx0, dx0) > dot(dx1, dx1)) ? dx0 : dx1);
233 const float3 dy = normalize(cross(N, dx));
234 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);
235}
236
237#if !defined(__KERNEL_METAL__)
239{
240 const float4 c_x = make_float4(b.x.x, b.y.x, b.z.x, 0.0f);
241 const float4 c_y = make_float4(b.x.y, b.y.y, b.z.y, 0.0f);
242 const float4 c_z = make_float4(b.x.z, b.y.z, b.z.z, 0.0f);
243 const float4 c_w = make_float4(b.x.w, b.y.w, b.z.w, 1.0f);
244
245 Transform t;
246 t.x = make_float4(dot(a.x, c_x), dot(a.x, c_y), dot(a.x, c_z), dot(a.x, c_w));
247 t.y = make_float4(dot(a.y, c_x), dot(a.y, c_y), dot(a.y, c_z), dot(a.y, c_w));
248 t.z = make_float4(dot(a.z, c_x), dot(a.z, c_y), dot(a.z, c_z), dot(a.z, c_w));
249
250 return t;
251}
252#endif
253
255{
257 return zero;
258}
259
260#ifndef __KERNEL_GPU__
261
262ccl_device_inline void print_transform(const char *label, const Transform &t)
263{
264 print_float4(label, t.x);
265 print_float4(label, t.y);
266 print_float4(label, t.z);
267 printf("\n");
268}
269
271{
272 return make_transform(1, 0, 0, t.x, 0, 1, 0, t.y, 0, 0, 1, t.z);
273}
274
275ccl_device_inline Transform transform_translate(const float x, const float y, float z)
276{
278}
279
281{
282 return make_transform(s.x, 0, 0, 0, 0, s.y, 0, 0, 0, 0, s.z, 0);
283}
284
285ccl_device_inline Transform transform_scale(const float x, const float y, float z)
286{
287 return transform_scale(make_float3(x, y, z));
288}
289
291{
292 const float s = sinf(angle);
293 const float c = cosf(angle);
294 const float t = 1.0f - c;
295
296 axis = normalize(axis);
297
298 return make_transform(axis.x * axis.x * t + c,
299 axis.x * axis.y * t - s * axis.z,
300 axis.x * axis.z * t + s * axis.y,
301 0.0f,
302
303 axis.y * axis.x * t + s * axis.z,
304 axis.y * axis.y * t + c,
305 axis.y * axis.z * t - s * axis.x,
306 0.0f,
307
308 axis.z * axis.x * t - s * axis.y,
309 axis.z * axis.y * t + s * axis.x,
310 axis.z * axis.z * t + c,
311 0.0f);
312}
313
314/* Euler is assumed to be in XYZ order. */
316{
317 return transform_rotate(euler.z, make_float3(0.0f, 0.0f, 1.0f)) *
318 transform_rotate(euler.y, make_float3(0.0f, 1.0f, 0.0f)) *
319 transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f));
320}
321
323{
324 return transform_scale(1.0f, 1.0f, 1.0f);
325}
326
328{
329 /* Using memcmp because it returns true for NaN unlike component ==,
330 * which we need for set_if_different for node sockets to copy the value. */
331 return memcmp(&A, &B, sizeof(Transform)) == 0;
332}
333
335{
336 return !(A == B);
337}
338
340 const Transform &B,
341 const float threshold)
342{
343 for (int x = 0; x < 3; x++) {
344 for (int y = 0; y < 4; y++) {
345 if (fabsf(A[x][y] - B[x][y]) > threshold) {
346 return false;
347 }
348 }
349 }
350
351 return true;
352}
353
355{
356 return make_float3(t->x[column], t->y[column], t->z[column]);
357}
358
359ccl_device_inline void transform_set_column(Transform *t, const int column, const float3 value)
360{
361 t->x[column] = value.x;
362 t->y[column] = value.y;
363 t->z[column] = value.z;
364}
365
367
369{
370 /* the epsilon here is quite arbitrary, but this function is only used for
371 * surface area and bump, where we expect it to not be so sensitive */
372 const float eps = 1e-6f;
373
374 const float sx = len_squared(make_float3(tfm.x));
375 const float sy = len_squared(make_float3(tfm.y));
376 const float sz = len_squared(make_float3(tfm.z));
377 const float stx = len_squared(transform_get_column(&tfm, 0));
378 const float sty = len_squared(transform_get_column(&tfm, 1));
379 const float stz = len_squared(transform_get_column(&tfm, 2));
380
381 if (fabsf(sx - sy) < eps && fabsf(sx - sz) < eps && fabsf(sx - stx) < eps &&
382 fabsf(sx - sty) < eps && fabsf(sx - stz) < eps)
383 {
384 scale = sx;
385 return true;
386 }
387
388 return false;
389}
390
392{
393 const float3 c0 = transform_get_column(&tfm, 0);
394 const float3 c1 = transform_get_column(&tfm, 1);
395 const float3 c2 = transform_get_column(&tfm, 2);
396
397 return (dot(cross(c0, c1), c2) < 0.0f);
398}
399
401{
402 Transform ntfm = tfm;
403
407
408 return ntfm;
409}
410
412{
413 return make_transform(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
414}
415
416#endif
417
418/* Motion Transform */
419
420ccl_device_inline float4 quat_interpolate(const float4 q1, const float4 q2, const float t)
421{
422 /* Optix and MetalRT are using linear interpolation to interpolate motion transformations. */
423#if defined(__KERNEL_GPU_RAYTRACING__)
424 return normalize((1.0f - t) * q1 + t * q2);
425#else /* defined(__KERNEL_GPU_RAYTRACING__) */
426 /* NOTE: this does not ensure rotation around shortest angle, q1 and q2
427 * are assumed to be matched already in transform_motion_decompose */
428 const float costheta = dot(q1, q2);
429
430 /* possible optimization: it might be possible to precompute theta/qperp */
431
432 if (costheta > 0.9995f) {
433 /* linear interpolation in degenerate case */
434 return normalize((1.0f - t) * q1 + t * q2);
435 }
436 /* slerp */
437 const float theta = acosf(clamp(costheta, -1.0f, 1.0f));
438 const float4 qperp = normalize(q2 - q1 * costheta);
439 const float thetap = theta * t;
440 return q1 * cosf(thetap) + qperp * sinf(thetap);
441
442#endif /* defined(__KERNEL_GPU_RAYTRACING__) */
443}
444
445#ifndef __KERNEL_GPU__
446void transform_inverse_cpu_avx2(const Transform &tfm, Transform &itfm);
447#endif
448
449/* Custom cross and dot implementations that match Embree bit for bit.
450 * Normally we don't use SSE41/AVX outside the kernel, but for this it's
451 * important to match exactly for ray tracing precision. */
452
454{
455#if defined(__AVX2__) && defined(__KERNEL_SSE2__)
456 const __m128 a = (const __m128 &)a_;
457 const __m128 b = (const __m128 &)b_;
458 const __m128 a_shuffle = _mm_castsi128_ps(
459 _mm_shuffle_epi32(_mm_castps_si128(a), _MM_SHUFFLE(3, 0, 2, 1)));
460 const __m128 b_shuffle = _mm_castsi128_ps(
461 _mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(3, 0, 2, 1)));
462 const __m128 r = _mm_castsi128_ps(
463 _mm_shuffle_epi32(_mm_castps_si128(_mm_fmsub_ps(a, b_shuffle, _mm_mul_ps(a_shuffle, b))),
464 _MM_SHUFFLE(3, 0, 2, 1)));
465 return (const float3 &)r;
466#endif
467
468 return cross(a_, b_);
469}
470
472{
473#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE42__)
474 const __m128 a = (const __m128 &)a_;
475 const __m128 b = (const __m128 &)b_;
476 return _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7F));
477#endif
478
479 return dot(a_, b_);
480}
481
483{
484 /* This implementation matches the one in Embree exactly, to ensure consistent
485 * results with the ray intersection of instances. */
486 float3 x = make_float3(tfm.x.x, tfm.y.x, tfm.z.x);
487 float3 y = make_float3(tfm.x.y, tfm.y.y, tfm.z.y);
488 float3 z = make_float3(tfm.x.z, tfm.y.z, tfm.z.z);
489 const float3 w = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
490
491 /* Compute determinant. */
493
494 if (det == 0.0f) {
495 /* Matrix is degenerate (e.g. 0 scale on some axis), ideally we should
496 * never be in this situation, but try to invert it anyway with tweak.
497 *
498 * This logic does not match Embree which would just give an invalid
499 * matrix. A better solution would be to remove this and ensure any object
500 * matrix is valid. */
501 x.x += 1e-8f;
502 y.y += 1e-8f;
503 z.z += 1e-8f;
504
505 det = transform_inverse_dot(x, cross(y, z));
506 if (det == 0.0f) {
507 det = FLT_MAX;
508 }
509 }
510
511 /* Divide adjoint matrix by the determinant to compute inverse of 3x3 matrix. */
512 const float3 inverse_x = transform_inverse_cross(y, z) / det;
513 const float3 inverse_y = transform_inverse_cross(z, x) / det;
514 const float3 inverse_z = transform_inverse_cross(x, y) / det;
515
516 /* Compute translation and fill transform. */
517 Transform itfm;
518 itfm.x = make_float4(inverse_x, -transform_inverse_dot(inverse_x, w));
519 itfm.y = make_float4(inverse_y, -transform_inverse_dot(inverse_y, w));
520 itfm.z = make_float4(inverse_z, -transform_inverse_dot(inverse_z, w));
521
522 return itfm;
523}
524
526{
527 /* Optimized transform implementations. */
528#ifndef __KERNEL_GPU__
530 Transform itfm;
532 return itfm;
533 }
534#endif
535
536 return transform_inverse_impl(tfm);
537}
538
540 const ccl_private DecomposedTransform *decomp)
541{
542 /* rotation */
543 float q0;
544 float q1;
545 float q2;
546 float q3;
547 float qda;
548 float qdb;
549 float qdc;
550 float qaa;
551 float qab;
552 float qac;
553 float qbb;
554 float qbc;
555 float qcc;
556
557 q0 = M_SQRT2_F * decomp->x.w;
558 q1 = M_SQRT2_F * decomp->x.x;
559 q2 = M_SQRT2_F * decomp->x.y;
560 q3 = M_SQRT2_F * decomp->x.z;
561
562 qda = q0 * q1;
563 qdb = q0 * q2;
564 qdc = q0 * q3;
565 qaa = q1 * q1;
566 qab = q1 * q2;
567 qac = q1 * q3;
568 qbb = q2 * q2;
569 qbc = q2 * q3;
570 qcc = q3 * q3;
571
572 const float3 rotation_x = make_float3(1.0f - qbb - qcc, -qdc + qab, qdb + qac);
573 const float3 rotation_y = make_float3(qdc + qab, 1.0f - qaa - qcc, -qda + qbc);
574 const float3 rotation_z = make_float3(-qdb + qac, qda + qbc, 1.0f - qaa - qbb);
575
576 /* scale */
577 const float3 scale_x = make_float3(decomp->y.w, decomp->z.z, decomp->w.y);
578 const float3 scale_y = make_float3(decomp->z.x, decomp->z.w, decomp->w.z);
579 const float3 scale_z = make_float3(decomp->z.y, decomp->w.x, decomp->w.w);
580
581 /* compose with translation */
582 tfm->x = make_float4(
583 dot(rotation_x, scale_x), dot(rotation_x, scale_y), dot(rotation_x, scale_z), decomp->y.x);
584 tfm->y = make_float4(
585 dot(rotation_y, scale_x), dot(rotation_y, scale_y), dot(rotation_y, scale_z), decomp->y.y);
586 tfm->z = make_float4(
587 dot(rotation_z, scale_x), dot(rotation_z, scale_y), dot(rotation_z, scale_z), decomp->y.z);
588}
589
590/* Interpolate from array of decomposed transforms. */
592 const ccl_global DecomposedTransform *motion,
593 const uint numsteps,
594 const float time)
595{
596 /* Figure out which steps we need to interpolate. */
597 const int maxstep = numsteps - 1;
598 const int step = min((int)(time * maxstep), maxstep - 1);
599 const float t = time * maxstep - step;
600
601 const ccl_global DecomposedTransform *a = motion + step;
602 const ccl_global DecomposedTransform *b = motion + step + 1;
603
604 /* Interpolate rotation, translation and scale. */
605 DecomposedTransform decomp;
606 decomp.x = quat_interpolate(a->x, b->x, t);
607 decomp.y = (1.0f - t) * a->y + t * b->y;
608 decomp.z = (1.0f - t) * a->z + t * b->z;
609 decomp.w = (1.0f - t) * a->w + t * b->w;
610
611 /* Compose rotation, translation, scale into matrix. */
612 transform_compose(tfm, &decomp);
613}
614
616{
617 return isfinite_safe(tfm->x) && isfinite_safe(tfm->y) && isfinite_safe(tfm->z);
618}
619
621{
622 return isfinite_safe(decomp->x) && isfinite_safe(decomp->y) && isfinite_safe(decomp->z) &&
623 isfinite_safe(decomp->w);
624}
625
626#ifndef __KERNEL_GPU__
627
628class BoundBox2D;
629
631{
632 return memcmp(&A, &B, sizeof(DecomposedTransform)) == 0;
633}
634
637 const Transform *motion,
638 const size_t size);
640
641#endif
642
643/* TODO: This can be removed when we know if no devices will require explicit
644 * address space qualifiers for this case. */
645
646#define transform_point_auto transform_point
647#define transform_direction_auto transform_direction
648#define transform_direction_transposed_auto transform_direction_transposed
649
unsigned int uint
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define A
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
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
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define ccl_device_forceinline
#define M_SQRT2_F
#define ccl_private
#define ccl_device_inline
#define ccl_global
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define acosf(x)
#define printf(...)
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
constexpr T clamp(T, U, U) RET
MatBase< 3, 3 > float3x3
VecBase< float, 3 > float3
ccl_device_inline bool isfinite_safe(const float f)
Definition math_base.h:348
CCL_NAMESPACE_BEGIN ccl_device_inline float madd(const float a, const float b, const float c)
Definition math_fast.h:35
ccl_device_inline float len_squared(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float4 zero_float4()
Definition math_float4.h:13
#define N
#define B
const btScalar eps
Definition poly34.cpp:11
#define fabsf
#define ccl_device
#define sinf
#define make_float4
#define cosf
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
float4 & operator[](int i)
Definition transform.h:30
float4 operator[](int i) const
Definition transform.h:26
float4 y
Definition transform.h:23
float4 x
Definition transform.h:23
float4 z
Definition transform.h:23
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
bool system_cpu_support_avx2()
Definition system.cpp:220
i
Definition text_draw.cc:230
ccl_device_forceinline Transform transform_inverse_impl(const Transform tfm)
Definition transform.h:482
ccl_device_inline float3 transform_get_column(const Transform *t, const int column)
Definition transform.h:354
ccl_device_inline Transform transform_rotate(const float angle, float3 axis)
Definition transform.h:290
ccl_device_inline Transform euler_to_transform(const float3 euler)
Definition transform.h:201
ccl_device_inline Transform transform_identity()
Definition transform.h:322
ccl_device_inline void print_transform(const char *label, const Transform &t)
Definition transform.h:262
ccl_device_inline Transform transform_empty()
Definition transform.h:411
ccl_device_inline bool transform_equal_threshold(const Transform &A, const Transform &B, const float threshold)
Definition transform.h:339
Transform transform_transposed_inverse(const Transform &tfm)
Definition transform.cpp:15
ccl_device_inline float4 quat_interpolate(const float4 q1, const float4 q2, const float t)
Definition transform.h:420
void transform_inverse_cpu_avx2(const Transform &tfm, Transform &itfm)
ccl_device_forceinline float3 transform_inverse_cross(const float3 a_, const float3 b_)
Definition transform.h:453
ccl_device_inline bool transform_decomposed_isfinite_safe(ccl_private DecomposedTransform *decomp)
Definition transform.h:620
ccl_device_inline Transform make_transform_frame(const float3 N)
Definition transform.h:228
ccl_device_inline bool transform_negative_scale(const Transform &tfm)
Definition transform.h:391
float4 transform_to_quat(const Transform &tfm)
Definition transform.cpp:23
ccl_device_inline bool transform_isfinite_safe(ccl_private Transform *tfm)
Definition transform.h:615
void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, const size_t size)
ccl_device void transform_motion_array_interpolate(ccl_private Transform *tfm, const ccl_global DecomposedTransform *motion, const uint numsteps, const float time)
Definition transform.h:591
ccl_device_inline Transform transform_scale(const float3 s)
Definition transform.h:280
ccl_device_inline Transform transform_inverse(const Transform tfm)
Definition transform.h:525
ccl_device_inline Transform transform_translate(const float3 t)
Definition transform.h:270
ccl_device_inline Transform transform_zero()
Definition transform.h:254
ccl_device_inline void transform_compose(ccl_private Transform *tfm, const ccl_private DecomposedTransform *decomp)
Definition transform.h:539
ccl_device_inline Transform make_transform(const float a, const float b, const float c, const float d, const float e, const float f, const float g, const float h, const float i, const float j, const float k, const float l)
Definition transform.h:159
ccl_device_inline bool transform_uniform_scale(const Transform &tfm, float &scale)
Definition transform.h:368
Transform transform_from_viewplane(BoundBox2D &viewplane)
ccl_device_inline float3 transform_direction(const ccl_private Transform *t, const float3 a)
Definition transform.h:127
ccl_device_inline bool operator!=(const Transform &A, const Transform &B)
Definition transform.h:334
ccl_device_inline float3 transform_direction_transposed(const ccl_private Transform *t, const float3 a)
Definition transform.h:149
ccl_device_inline bool operator==(const Transform &A, const Transform &B)
Definition transform.h:327
ccl_device_inline Transform transform_euler(const float3 euler)
Definition transform.h:315
ccl_device_inline Transform transform_clear_scale(const Transform &tfm)
Definition transform.h:400
ccl_device_inline void transform_set_column(Transform *t, const int column, const float3 value)
Definition transform.h:359
ccl_device_forceinline float transform_inverse_dot(const float3 a_, const float3 b_)
Definition transform.h:471
ccl_device_inline float3 transform_point(const ccl_private Transform *t, const float3 a)
Definition transform.h:56
ccl_device_inline Transform operator*(const Transform a, const Transform b)
Definition transform.h:238
dual< float4 > dual4
Definition types_dual.h:59
dual< float3 > dual3
Definition types_dual.h:58
ccl_device_inline dual4 make_homogeneous(const dual3 a)
Definition types_dual.h:78
ccl_device_inline void print_float4(const ccl_private char *label, const float4 a)