Spaces:
Runtime error
Runtime error
| /* | |
| * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| #pragma once | |
| #include "Transform.h" | |
| namespace Math | |
| { | |
| inline Transform Transform::FromRotation(const Quaternion& rotation) | |
| { | |
| return Transform(rotation); | |
| } | |
| inline Transform Transform::FromTranslation(const Vector& translation) | |
| { | |
| return Transform(Quaternion::Identity, translation); | |
| } | |
| inline Transform Transform::FromScale(float uniformScale) | |
| { | |
| return Transform(Quaternion::Identity, Vector::Zero, uniformScale); | |
| } | |
| inline Transform Transform::FromTranslationAndScale(const Vector& translation, float uniformScale) | |
| { | |
| return Transform(Quaternion::Identity, translation, uniformScale); | |
| } | |
| inline Transform Transform::FromRotationBetweenVectors(const Vector sourceVector, const Vector targetVector) | |
| { | |
| return Transform(Quaternion::FromRotationBetweenNormalizedVectors(sourceVector, targetVector)); | |
| } | |
| inline Transform Transform::Lerp(const Transform& from, const Transform& to, float t) | |
| { | |
| Quaternion const rotation = Quaternion::NLerp(Quaternion(from.m_rotation), Quaternion(to.m_rotation), t); | |
| Vector const translationAndScale = Vector::Lerp(from.m_translationScale, to.m_translationScale, t); | |
| Transform lerped(NoInit); | |
| lerped.m_rotation = rotation; | |
| lerped.m_translationScale = translationAndScale; | |
| return lerped; | |
| } | |
| inline Transform Transform::Slerp(const Transform& from, const Transform& to, float t) | |
| { | |
| Quaternion const rotation = Quaternion::SLerp(Quaternion(from.m_rotation), Quaternion(to.m_rotation), t); | |
| Vector const translationAndScale = Vector::Lerp(Vector(from.m_translationScale), Vector(to.m_translationScale), t); | |
| Transform lerped(NoInit); | |
| lerped.m_rotation = rotation; | |
| lerped.m_translationScale = translationAndScale; | |
| return lerped; | |
| } | |
| inline Transform Transform::FastSlerp(const Transform& from, const Transform& to, float t) | |
| { | |
| Quaternion const rotation = Quaternion::FastSLerp(Quaternion(from.m_rotation), Quaternion(to.m_rotation), t); | |
| Vector const translationAndScale = Vector::Lerp(Vector(from.m_translationScale), Vector(to.m_translationScale), t); | |
| Transform lerped(NoInit); | |
| lerped.m_rotation = rotation; | |
| lerped.m_translationScale = translationAndScale; | |
| return lerped; | |
| } | |
| inline Transform Transform::Delta(const Transform& from, const Transform& to) | |
| { | |
| ASSERT(from.m_rotation.IsNormalized() && to.m_rotation.IsNormalized()); | |
| ASSERT(!from.m_translationScale.IsW0() && !to.m_translationScale.IsW0()); | |
| Transform result; | |
| Vector const inverseScale = from.GetInverseScaleVector(); | |
| Vector const deltaScale = to.GetScaleVector() * inverseScale; | |
| // If we have negative scaling, we need to use matrices to calculate the deltas | |
| Vector const minScale = Vector::Min(from.m_translationScale.GetSplatW(), to.m_translationScale.GetSplatW()); | |
| if (minScale.IsAnyLessThan(Vector::Zero)) | |
| { | |
| // Multiply the transforms using matrices to get the correct rotation and then remove the scale; | |
| Matrix const toMtx = to.ToMatrix(); | |
| Matrix const fromMtx = from.ToMatrix(); | |
| Matrix resultMtx = toMtx * fromMtx.GetInverse(); | |
| resultMtx.RemoveScaleFast(); | |
| // Apply back the signs from the final scale | |
| Vector const sign = deltaScale.GetSign(); | |
| resultMtx[0] *= sign.GetSplatX(); | |
| resultMtx[1] *= sign.GetSplatY(); | |
| resultMtx[2] *= sign.GetSplatZ(); | |
| result.m_rotation = resultMtx.GetRotation(); | |
| ASSERT(result.m_rotation.IsNormalized()); | |
| result.m_translationScale = Vector::Select(resultMtx.GetTranslation(), deltaScale, Vector::Select0001); | |
| } | |
| else | |
| { | |
| Quaternion const fromInverseRotation = from.m_rotation.GetInverse(); | |
| result.m_rotation = to.m_rotation * fromInverseRotation; | |
| Vector const deltaTranslation = to.m_translationScale - from.m_translationScale; | |
| Vector const translation = fromInverseRotation.RotateVector(deltaTranslation) * inverseScale; | |
| result.m_translationScale = Vector::Select(translation, deltaScale, Vector::Select0001); | |
| } | |
| return result; | |
| } | |
| inline Transform Transform::DeltaNoScale(const Transform& from, const Transform& to) | |
| { | |
| Quaternion const inverseFromRotation = from.m_rotation.GetInverse(); | |
| Vector const deltaTranslation = to.GetTranslation() - from.GetTranslation(); | |
| Transform delta; | |
| delta.m_rotation = to.m_rotation * inverseFromRotation; | |
| delta.m_translationScale = inverseFromRotation.RotateVector(deltaTranslation).GetWithW1(); | |
| return delta; | |
| } | |
| inline void Transform::DirectlySetRotation(Transform& transform, Quaternion&& rotation) | |
| { | |
| transform.m_rotation = rotation; | |
| } | |
| inline void Transform::DirectlySetRotation(Transform& transform, const Quaternion& rotation) | |
| { | |
| transform.m_rotation = rotation; | |
| } | |
| inline void Transform::DirectlySetTranslationScale(Transform& transform, Vector&& translationScale) | |
| { | |
| transform.m_translationScale = translationScale; | |
| } | |
| inline void Transform::DirectlySetTranslationScale(Transform& transform, const Vector& translationScale) | |
| { | |
| transform.m_translationScale = translationScale; | |
| } | |
| inline Transform::Transform(NoInit_t) | |
| : m_rotation(NoInit) | |
| , m_translationScale(NoInit) | |
| { | |
| } | |
| inline Transform::Transform(const Matrix& m) | |
| { | |
| Vector mTranslation, mScale; | |
| m.Decompose(m_rotation, mTranslation, mScale); | |
| ASSERT(Math::IsNearEqual(mScale.GetX(), mScale.GetY()) && Math::IsNearEqual(mScale.GetY(),mScale.GetZ())); | |
| m_translationScale = Vector::Select(mTranslation, mScale, Vector::Select0001); | |
| } | |
| inline Transform::Transform(const Quaternion& rotation, const Vector& translation, float scale) | |
| : m_rotation(rotation) | |
| , m_translationScale(Vector::Select(translation, Vector(scale), Vector::Select0001)) | |
| { | |
| } | |
| inline Transform::Transform(const AxisAngle& rotation) | |
| : m_rotation(rotation) | |
| , m_translationScale(Vector::UnitW) | |
| { | |
| } | |
| inline Matrix Transform::ToMatrix() const | |
| { | |
| return Matrix(m_rotation, m_translationScale.GetWithW1(), m_translationScale.GetSplatW()); | |
| } | |
| inline Matrix Transform::ToMatrixNoScale() const | |
| { | |
| return Matrix(m_rotation, m_translationScale.GetWithW1(), Vector::One); | |
| } | |
| inline EulerAngles Transform::ToEulerAngles() const | |
| { | |
| return m_rotation.ToEulerAngles(); | |
| } | |
| inline Vector Transform::GetAxisX() const | |
| { | |
| return m_rotation.RotateVector(Vector::UnitX); | |
| } | |
| inline Vector Transform::GetAxisY() const | |
| { | |
| return m_rotation.RotateVector(Vector::UnitY); | |
| } | |
| inline Vector Transform::GetAxisZ() const | |
| { | |
| return m_rotation.RotateVector(Vector::UnitZ); | |
| } | |
| inline Vector Transform::GetRightVector() const | |
| { | |
| return m_rotation.RotateVector(Vector::WorldRight); | |
| } | |
| inline Vector Transform::GetForwardVector() const | |
| { | |
| return m_rotation.RotateVector(Vector::WorldForward); | |
| } | |
| inline Vector Transform::GetUpVector() const | |
| { | |
| return m_rotation.RotateVector(Vector::WorldUp); | |
| } | |
| inline bool Transform::IsIdentity() const | |
| { | |
| return m_rotation.IsIdentity() && m_translationScale.IsEqual4(Vector::UnitW); | |
| } | |
| inline bool Transform::IsRigidTransform() const | |
| { | |
| return GetScale() == 1.0f; | |
| } | |
| inline void Transform::MakeRigidTransform() | |
| { | |
| SetScale(1.0f); | |
| } | |
| inline Transform& Transform::Inverse() | |
| { | |
| ASSERT(!m_translationScale.IsW0()); | |
| Quaternion const inverseRotation = m_rotation.GetInverse(); | |
| m_rotation = inverseRotation; | |
| Vector const inverseScale = GetInverseScaleVector(); | |
| Vector const inverselyScaledTranslation = inverseScale * m_translationScale.GetWithW0(); | |
| Vector const inverselyRotatedTranslation = inverseRotation.RotateVector(inverselyScaledTranslation); | |
| Vector const inverseTranslation = inverselyRotatedTranslation.GetNegated().SetW0(); | |
| m_translationScale = Vector::Select(inverseTranslation, inverseScale, Vector::Select0001); | |
| return *this; | |
| } | |
| inline Transform Transform::GetInverse() const | |
| { | |
| Transform inverse = *this; | |
| return inverse.Inverse(); | |
| } | |
| inline Transform Transform::GetDeltaToOther(const Transform& targetTransform) const | |
| { | |
| return Transform::Delta(*this, targetTransform); | |
| } | |
| inline Transform Transform::GetDeltaFromOther(const Transform& startTransform) const | |
| { | |
| return Transform::Delta(startTransform, *this); | |
| } | |
| inline const Quaternion& Transform::GetRotation() const | |
| { | |
| return m_rotation; | |
| } | |
| inline void Transform::SetRotation(const Quaternion& rotation) | |
| { | |
| ASSERT(rotation.IsNormalized()); | |
| m_rotation = rotation; | |
| } | |
| inline void Transform::AddRotation(const Quaternion& delta) | |
| { | |
| ASSERT(delta.IsNormalized()); | |
| m_rotation = delta * m_rotation; | |
| } | |
| inline const Vector& Transform::GetTranslation() const | |
| { | |
| return m_translationScale; | |
| } | |
| inline const Vector& Transform::GetTranslationAndScale() const | |
| { | |
| return m_translationScale; | |
| } | |
| inline void Transform::SetTranslation(const Vector& newTranslation) | |
| { | |
| m_translationScale = Vector::Select(newTranslation, m_translationScale, Vector::Select0001); | |
| } | |
| inline void Transform::SetTranslationAndScale(const Vector& newTranslationScale) | |
| { | |
| ASSERT(newTranslationScale.GetW() != 0.0f); | |
| m_translationScale = newTranslationScale; | |
| } | |
| inline void Transform::AddTranslation(const Vector& translationDelta) | |
| { | |
| m_translationScale += translationDelta.GetWithW0(); | |
| } | |
| inline Vector Transform::GetTranslationAsVector() const | |
| { | |
| return m_translationScale.GetWithW0(); | |
| } | |
| inline Vector Transform::GetTranslationAsPoint() const | |
| { | |
| return m_translationScale.GetWithW1(); | |
| } | |
| inline float Transform::GetScale() const | |
| { | |
| return m_translationScale.GetW(); | |
| } | |
| inline Vector Transform::GetScaleVector() const | |
| { | |
| return m_translationScale.GetSplatW(); | |
| } | |
| inline Vector Transform::GetInverseScaleVector() const | |
| { | |
| return m_translationScale.GetSplatW().GetInverse(); | |
| } | |
| inline void Transform::SetScale(float uniformScale) | |
| { | |
| m_translationScale.SetW(uniformScale); | |
| } | |
| inline bool Transform::HasScale() const | |
| { | |
| return m_translationScale.GetW() != 1.0f; | |
| } | |
| inline bool Transform::HasNegativeScale() const | |
| { | |
| return m_translationScale.GetW() < 0.0f; | |
| } | |
| inline Vector Transform::TranslateVector(const Vector& vector) const | |
| { | |
| return vector + m_translationScale.GetWithW0(); | |
| } | |
| inline Vector Transform::ScaleVector(const Vector& vector) const | |
| { | |
| return vector * GetScaleVector(); | |
| } | |
| inline Vector Transform::TransformPoint(const Vector& point) const | |
| { | |
| ASSERT(!m_translationScale.IsW0()); | |
| Vector transformedPoint = point * m_translationScale.GetSplatW(); | |
| transformedPoint = (m_translationScale + m_rotation.RotateVector(transformedPoint)).GetWithW0(); | |
| return transformedPoint; | |
| } | |
| inline Vector Transform::TransformPointNoScale(const Vector& point) const | |
| { | |
| Vector transformedPoint = (m_translationScale + m_rotation.RotateVector(point)).GetWithW0();; | |
| return transformedPoint; | |
| } | |
| inline Vector Transform::RotateVector(const Vector& vector) const | |
| { | |
| return m_rotation.RotateVector(vector); | |
| } | |
| inline Vector Transform::TransformNormal(const Vector& vector) const | |
| { | |
| return RotateVector(vector); | |
| } | |
| inline Vector Transform::InverseRotateVector(const Vector& vector) const | |
| { | |
| return m_rotation.RotateVectorInverse(vector); | |
| } | |
| inline Vector Transform::InverseTransformPoint(const Vector& point) const | |
| { | |
| ASSERT(!m_translationScale.IsW0()); | |
| Vector const shiftedPoint = point - m_translationScale; | |
| Vector const unrotatedShiftedPoint = m_rotation.RotateVectorInverse(shiftedPoint); | |
| Vector const inverseScale = GetInverseScaleVector(); | |
| Vector const result = unrotatedShiftedPoint * inverseScale; | |
| return result; | |
| } | |
| inline Vector Transform::InverseTransformPointNoScale(const Vector& point) const | |
| { | |
| Vector const shiftedPoint = point - m_translationScale; | |
| Vector const unrotatedShiftedPoint = m_rotation.RotateVectorInverse(shiftedPoint); | |
| return unrotatedShiftedPoint; | |
| } | |
| inline Vector Transform::TransformVector(const Vector& vector) const | |
| { | |
| ASSERT(!m_translationScale.IsW0()); | |
| Vector transformedVector = vector * GetScaleVector(); | |
| transformedVector = m_rotation.RotateVector(transformedVector); | |
| return transformedVector; | |
| } | |
| inline Vector Transform::TransformVectorNoScale(const Vector& vector) const | |
| { | |
| return RotateVector(vector); | |
| } | |
| inline Vector Transform::InverseTransformVector(const Vector& vector) const | |
| { | |
| ASSERT(!m_translationScale.IsW0()); | |
| Vector const unrotatedVector = m_rotation.RotateVectorInverse(vector); | |
| Vector const inverseScale = GetInverseScaleVector(); | |
| Vector const result = unrotatedVector * inverseScale; | |
| return result; | |
| } | |
| inline Vector Transform::InverseTransformVectorNoScale(const Vector& vector) const | |
| { | |
| return m_rotation.RotateVectorInverse(vector); | |
| } | |
| inline Transform Transform::operator*(const Transform& rhs) const | |
| { | |
| Transform transform = *this; | |
| transform *= rhs; | |
| return transform; | |
| } | |
| inline Transform& Transform::operator*=(const Transform& rhs) | |
| { | |
| Vector const scale = GetScaleVector(); | |
| Vector const rhsScale = rhs.GetScaleVector(); | |
| Vector const minScale = Vector::Min(scale, rhsScale); | |
| Vector const finalScale = scale * rhsScale; | |
| if (minScale.IsAnyLessThan(Vector::Zero)) | |
| { | |
| // Multiply the transforms using matrices to | |
| // get the correct rotation and then remove the scale; | |
| Matrix const lhsMtx = ToMatrix(); | |
| Matrix const rhsMtx = rhs.ToMatrix(); | |
| Matrix resultMtx = lhsMtx * rhsMtx; | |
| resultMtx.RemoveScaleFast(); | |
| // Apply back the signs from the final scale | |
| Vector const sign = finalScale.GetSign(); | |
| resultMtx[0] *= sign.GetSplatX(); | |
| resultMtx[1] *= sign.GetSplatY(); | |
| resultMtx[2] *= sign.GetSplatZ(); | |
| m_rotation = resultMtx.GetRotation(); | |
| ASSERT(m_rotation.IsNormalized()); | |
| m_translationScale = Vector::Select(resultMtx.GetTranslation(), finalScale, Vector::Select0001); | |
| } | |
| else | |
| { | |
| // Normal case | |
| m_rotation = m_rotation * rhs.m_rotation; | |
| m_rotation.Normalize(); | |
| Vector const translation = rhs.m_rotation.RotateVector(m_translationScale * rhsScale) + rhs.m_translationScale; | |
| m_translationScale = Vector::Select(translation, finalScale, Vector::Select0001); | |
| } | |
| return *this; | |
| } | |
| inline bool Transform::IsNearEqual(const Transform& rhs, const Radians angleThreshold, float translationScaleThreshold) const | |
| { | |
| if (!m_rotation.IsNearEqual(rhs.m_rotation, angleThreshold)) | |
| { | |
| return false; | |
| } | |
| if (!m_translationScale.IsNearEqual4(rhs.m_translationScale, translationScaleThreshold)) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| inline bool Transform::operator==(const Transform& rhs) const | |
| { | |
| if (m_translationScale != rhs.m_translationScale) | |
| { | |
| return false; | |
| } | |
| if (m_rotation != rhs.m_rotation) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| inline bool Transform::operator!=(const Transform& rhs) const | |
| { | |
| return !operator==(rhs); | |
| } | |
| } | |