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