mirror of
https://github.com/blender/blender
synced 2026-10-25 03:07:01 +03:00
The main goal is to bring a bit of structure to the use of quaternions in the Cycles kernel. Prior to this change there was no dedicated quaternion type and float4 was used instead, and quaternions are stored as (x, y, z, w) matching naming between the quaternion and float4 fields. However, Blender uses (w, x, y, z) quaternion order for attributes, which is different from what Cycles uses. Without dedicated type this either leads to different quaternion orders depending whether it comes from attribute, or makes it intrinsically not possible to use implicit sharing. This change introduces Cycles Quaternion type which is compatible with Blender attribute math::Quaternion in both layout and alignment, making it possible to benefit from implicit sharing and use a nice structure in the kernel. This change does not modify the existing quaternion usage in the kernel which is currently used for transform decomposition and interpolation. There is currently no SIMD for the Quaternion type, which allows to avoid any special alignment requirement and share attributes with Blender, but performance might not be ideal. This attribute type will be used for representing gaussian splat rotation. The attribute access and interpolation matches behavior prior to this change. Added some basic tests for quaternion attribute access for RGB and alpha, mesh and volume attributes. Ref #159470 Pull Request: https://projects.blender.org/blender/blender/pulls/163342
108 lines
3.1 KiB
C
108 lines
3.1 KiB
C
/* SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
#pragma once
|
|
|
|
#include "util/math_base.h"
|
|
#include "util/types_float3.h"
|
|
#include "util/types_float4.h"
|
|
#include "util/types_quaternion.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
ccl_device_inline Quaternion operator-(const Quaternion q)
|
|
{
|
|
return make_quaternion(-q.w, -q.x, -q.y, -q.z);
|
|
}
|
|
|
|
ccl_device_inline Quaternion operator*(const float a, const Quaternion q)
|
|
{
|
|
return make_quaternion(a * q.w, a * q.x, a * q.y, a * q.z);
|
|
}
|
|
ccl_device_inline Quaternion operator*(const Quaternion q, const float a)
|
|
{
|
|
return make_quaternion(q.w * a, q.x * a, q.y * a, q.z * a);
|
|
}
|
|
|
|
ccl_device_inline Quaternion operator+(const Quaternion a, const Quaternion b)
|
|
{
|
|
return make_quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z);
|
|
}
|
|
|
|
ccl_device_inline Quaternion operator-(const Quaternion a, const Quaternion b)
|
|
{
|
|
return make_quaternion(a.w - b.w, a.x - b.x, a.y - b.y, a.z - b.z);
|
|
}
|
|
|
|
ccl_device_inline ccl_private Quaternion &operator+=(ccl_private Quaternion &a, const Quaternion b)
|
|
{
|
|
a = a + b;
|
|
return a;
|
|
}
|
|
|
|
ccl_device_inline ccl_private Quaternion &operator-=(ccl_private Quaternion &a, const Quaternion b)
|
|
{
|
|
a = a - b;
|
|
return a;
|
|
}
|
|
|
|
ccl_device_inline float dot(const Quaternion a, const Quaternion b)
|
|
{
|
|
return a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z;
|
|
}
|
|
|
|
ccl_device_inline Quaternion normalized(const Quaternion q)
|
|
{
|
|
const float len = sqrtf(dot(q, q));
|
|
if (len != 0.0f) {
|
|
const float len_inv = 1.0f / len;
|
|
return make_quaternion(q.w * len_inv, q.x * len_inv, q.y * len_inv, q.z * len_inv);
|
|
}
|
|
return identity_quaternion();
|
|
}
|
|
|
|
/* Linear interpolation around the shortest angle.
|
|
* The caller is responsible for ensuring the input quaternions are normalized. */
|
|
ccl_device_inline Quaternion lerp(const Quaternion q1, const Quaternion q2, const float t)
|
|
{
|
|
/* TODO(sergey): Add assert that the quaternions are normalized? */
|
|
/* Ensure rotation around shortest angle, negated quaternions are the same. */
|
|
const Quaternion q2_shortest_angle = dot(q1, q2) >= 0.0f ? q2 : -q2;
|
|
return normalized((1.0f - t) * q1 + t * q2_shortest_angle);
|
|
}
|
|
|
|
ccl_device_template_spec Quaternion make_zero()
|
|
{
|
|
return make_quaternion(0.0f, 0.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
ccl_device_inline float3 make_float3(const Quaternion q)
|
|
{
|
|
/* Matches legacy storage and attribute access: make_float3(make_float4(q.w, q.x, q.y, q.z)) */
|
|
return make_float3(q.w, q.x, q.y);
|
|
}
|
|
|
|
ccl_device_inline float4 make_float4(const Quaternion q)
|
|
{
|
|
/* Matches legacy storage and attribute access: make_float4(q.w, q.x, q.y, q.z) */
|
|
return make_float4(q.w, q.x, q.y, q.z);
|
|
}
|
|
|
|
/* mix() on quaternions is used from generic attribute sampling and interpolation.
|
|
* Define it as a float4 mix for the compatibility until we can change the way quaternion
|
|
* attributes behave. */
|
|
ccl_device_inline Quaternion mix(const Quaternion a, const Quaternion b, const float t)
|
|
{
|
|
return a + t * (b - a);
|
|
}
|
|
|
|
ccl_device_inline void copy_v4_qt(ccl_private float *r, const Quaternion val)
|
|
{
|
|
r[0] = val.w;
|
|
r[1] = val.x;
|
|
r[2] = val.y;
|
|
r[3] = val.z;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|