mirror of
https://github.com/openharmony/ace_ace_engine.git
synced 2026-07-18 12:45:07 -04:00
ede2aaa223
Signed-off-by: kangchongtao <kangchongtao@huawei.com> Change-Id: Ic0fc40d272c7986dec2463680b7b0fe7f5ee72d2 Signed-off-by: kangchongtao <kangchongtao@huawei.com>
654 lines
21 KiB
C++
654 lines
21 KiB
C++
/*
|
|
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "base/geometry/transform_util.h"
|
|
|
|
namespace OHOS::Ace {
|
|
namespace {
|
|
|
|
float Length3(const float v[3])
|
|
{
|
|
double vd[3] = { v[0], v[1], v[2] };
|
|
return static_cast<float>(std::sqrt(vd[0] * vd[0] + vd[1] * vd[1] + vd[2] * vd[2]));
|
|
}
|
|
|
|
template<int n>
|
|
float Dot(const float* a, const float* b)
|
|
{
|
|
double total = 0.0;
|
|
for (int i = 0; i < n; ++i) {
|
|
total += a[i] * b[i];
|
|
}
|
|
return static_cast<float>(total);
|
|
}
|
|
|
|
template<int n>
|
|
void Combine(float* out, const float* a, const float* b, double scaleA, double scaleB)
|
|
{
|
|
for (int i = 0; i < n; ++i) {
|
|
out[i] = static_cast<float>(a[i] * scaleA + b[i] * scaleB);
|
|
}
|
|
}
|
|
|
|
void Cross3(float out[3], const float a[3], const float b[3])
|
|
{
|
|
float x = a[1] * b[2] - a[2] * b[1];
|
|
float y = a[2] * b[0] - a[0] * b[2];
|
|
float z = a[0] * b[1] - a[1] * b[0];
|
|
out[0] = x;
|
|
out[1] = y;
|
|
out[2] = z;
|
|
}
|
|
|
|
// Returns false if the matrix cannot be normalized.
|
|
bool Normalize(Matrix4& m)
|
|
{
|
|
if (NearZero(m.Get(3, 3))) {
|
|
return false;
|
|
}
|
|
float scale = 1.0f / m.Get(3, 3);
|
|
for (int i = 0; i < 4; i++) {
|
|
for (int j = 0; j < 4; j++) {
|
|
auto value = m.Get(i, j) * scale;
|
|
m.Set(i, j, value);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Matrix4 BuildPerspectiveMatrix(const DecomposedTransform& decomp)
|
|
{
|
|
Matrix4 matrix = Matrix4::CreateIdentity();
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
matrix.Set(3, i, decomp.perspective[i]);
|
|
}
|
|
return matrix;
|
|
}
|
|
|
|
Matrix4 BuildTranslationMatrix(const DecomposedTransform& decomp)
|
|
{
|
|
Matrix4 matrix = Matrix4::CreateIdentity();
|
|
float dx = decomp.translate[0];
|
|
float dy = decomp.translate[1];
|
|
float dz = decomp.translate[2];
|
|
if (NearZero(dx) && NearZero(dy) && NearZero(dz)) {
|
|
return matrix;
|
|
}
|
|
|
|
matrix.Set(0, 3, dx);
|
|
matrix.Set(1, 3, dy);
|
|
matrix.Set(2, 3, dz);
|
|
return matrix;
|
|
}
|
|
|
|
Matrix4 BuildRotationMatrix(const DecomposedTransform& decomp)
|
|
{
|
|
Matrix4 matrix4;
|
|
double x = decomp.quaternion.GetX();
|
|
double y = decomp.quaternion.GetY();
|
|
double z = decomp.quaternion.GetZ();
|
|
double w = decomp.quaternion.GetW();
|
|
|
|
matrix4.Set(0, 0, static_cast<float>(1.0 - 2.0 * (y * y + z * z)));
|
|
matrix4.Set(1, 0, static_cast<float>(2.0 * (x * y + z * w)));
|
|
matrix4.Set(2, 0, static_cast<float>(2.0 * (x * z - y * w)));
|
|
matrix4.Set(3, 0, 0);
|
|
|
|
matrix4.Set(0, 1, static_cast<float>(2.0 * (x * y - z * w)));
|
|
matrix4.Set(1, 1, static_cast<float>(1.0 - 2.0 * (x * x + z * z)));
|
|
matrix4.Set(2, 1, static_cast<float>(2.0 * (y * z + x * w)));
|
|
matrix4.Set(3, 1, 0);
|
|
|
|
matrix4.Set(0, 2, static_cast<float>(2.0 * (x * z + y * w)));
|
|
matrix4.Set(1, 2, static_cast<float>(2.0 * (y * z - x * w)));
|
|
matrix4.Set(2, 2, static_cast<float>(1.0 - 2.0 * (x * x + y * y)));
|
|
matrix4.Set(3, 2, 0);
|
|
|
|
matrix4.Set(0, 3, 0);
|
|
matrix4.Set(1, 3, 0);
|
|
matrix4.Set(2, 3, 0);
|
|
matrix4.Set(3, 3, 1);
|
|
|
|
return matrix4;
|
|
}
|
|
|
|
Matrix4 BuildSkewMatrix(const DecomposedTransform& decomp)
|
|
{
|
|
Matrix4 matrix = Matrix4::CreateIdentity();
|
|
|
|
Matrix4 temp = Matrix4::CreateIdentity();
|
|
if (decomp.skew[2]) {
|
|
temp.Set(1, 2, decomp.skew[2]);
|
|
matrix = matrix * temp;
|
|
}
|
|
|
|
if (decomp.skew[1]) {
|
|
temp.Set(1, 2, 0);
|
|
temp.Set(0, 2, decomp.skew[1]);
|
|
matrix = matrix * temp;
|
|
}
|
|
|
|
if (decomp.skew[0]) {
|
|
temp.Set(0, 2, 0);
|
|
temp.Set(0, 1, decomp.skew[0]);
|
|
matrix = matrix * temp;
|
|
}
|
|
return matrix;
|
|
}
|
|
|
|
Matrix4 BuildScaleMatrix(const DecomposedTransform& decomp)
|
|
{
|
|
Matrix4 matrix = Matrix4::CreateIdentity();
|
|
matrix.SetScale(decomp.scale[0], decomp.scale[1], decomp.scale[2]);
|
|
return matrix;
|
|
}
|
|
|
|
Matrix4 ComposeTransform(const Matrix4& perspective, const Matrix4& translation, const Matrix4& rotation,
|
|
const Matrix4& skew, const Matrix4& scale)
|
|
{
|
|
Matrix4 matrix = Matrix4::CreateIdentity();
|
|
matrix = matrix * perspective;
|
|
matrix = matrix * translation;
|
|
matrix = matrix * rotation;
|
|
matrix = matrix * skew;
|
|
matrix = matrix * scale;
|
|
return matrix;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TranslateOperation TranslateOperation::Blend(
|
|
const TranslateOperation& to, const TranslateOperation& from, float progress)
|
|
{
|
|
TranslateOperation ret;
|
|
float scaleA = progress;
|
|
float scaleB = 1 - progress;
|
|
ret.dx = to.dx * scaleA + from.dx * scaleB;
|
|
ret.dy = to.dy * scaleA + from.dy * scaleB;
|
|
ret.dz = to.dz * scaleA + from.dz * scaleB;
|
|
|
|
return ret;
|
|
}
|
|
|
|
ScaleOperation ScaleOperation::Blend(const ScaleOperation& to, const ScaleOperation& from, float progress)
|
|
{
|
|
ScaleOperation ret;
|
|
float scaleA = progress;
|
|
float scaleB = 1 - progress;
|
|
ret.scaleX = to.scaleX * scaleA + from.scaleX * scaleB;
|
|
ret.scaleY = to.scaleY * scaleA + from.scaleY * scaleB;
|
|
ret.scaleZ = to.scaleZ * scaleA + from.scaleZ * scaleB;
|
|
return ret;
|
|
}
|
|
|
|
SkewOperation SkewOperation::Blend(const SkewOperation& to, const SkewOperation& from, float progress)
|
|
{
|
|
SkewOperation ret;
|
|
float scaleA = progress;
|
|
float scaleB = 1 - progress;
|
|
ret.skewX = to.skewX * scaleA + from.skewX * scaleB;
|
|
ret.skewY = to.skewY * scaleA + from.skewY * scaleB;
|
|
return ret;
|
|
}
|
|
|
|
RotateOperation RotateOperation::Blend(const RotateOperation& to, const RotateOperation& from, float progress)
|
|
{
|
|
RotateOperation ret;
|
|
float scaleA = progress;
|
|
float scaleB = 1 - progress;
|
|
ret.angle = to.angle * scaleA + from.angle * scaleB;
|
|
ret.dx = to.dx;
|
|
ret.dy = to.dy;
|
|
ret.dz = to.dz;
|
|
// rotate vector is (0,0,0) is error
|
|
if (NearZero(ret.dx) && NearZero(ret.dy) && NearZero(ret.dz)) {
|
|
ret.dx = from.dx;
|
|
ret.dy = from.dy;
|
|
ret.dz = from.dz;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
PerspectiveOperation PerspectiveOperation::Blend(
|
|
const PerspectiveOperation& to, const PerspectiveOperation& from, float progress)
|
|
{
|
|
PerspectiveOperation ret;
|
|
ret.distance = from.distance + (to.distance - from.distance) * progress;
|
|
return ret;
|
|
}
|
|
|
|
TransformOperation TransformOperation::Blend(
|
|
const TransformOperation& to, const TransformOperation& from, float progress)
|
|
{
|
|
TransformOperation ret;
|
|
if (to.type_ == from.type_ && to.type_ == TransformOperationType::UNDEFINED) {
|
|
return ret;
|
|
} else if (to.type_ == TransformOperationType::UNDEFINED) {
|
|
ret.type_ = from.type_;
|
|
BlendInner(Create(ret.type_), from, progress, ret);
|
|
} else if (from.type_ == TransformOperationType::UNDEFINED) {
|
|
ret.type_ = to.type_;
|
|
BlendInner(to, Create(ret.type_), progress, ret);
|
|
} else if (to.type_ == from.type_) {
|
|
ret.type_ = to.type_;
|
|
BlendInner(to, from, progress, ret);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
TransformOperation TransformOperation::Create(TransformOperationType type)
|
|
{
|
|
TransformOperation ret;
|
|
ret.type_ = type;
|
|
switch (ret.type_) {
|
|
case TransformOperationType::TRANSLATE:
|
|
ret.translateOperation_ = TranslateOperation();
|
|
break;
|
|
case TransformOperationType::SCALE:
|
|
ret.scaleOperation_ = ScaleOperation();
|
|
break;
|
|
case TransformOperationType::SKEW:
|
|
ret.skewOperation_ = SkewOperation();
|
|
break;
|
|
case TransformOperationType::ROTATE:
|
|
ret.rotateOperation_ = RotateOperation();
|
|
break;
|
|
case TransformOperationType::MATRIX:
|
|
ret.matrix4_ = Matrix4::CreateIdentity();
|
|
break;
|
|
case TransformOperationType::PERSPECTIVE:
|
|
ret.perspectiveOperation_ = PerspectiveOperation();
|
|
break;
|
|
case TransformOperationType::UNDEFINED:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void TransformOperation::BlendInner(
|
|
const TransformOperation& to, const TransformOperation& from, float progress, TransformOperation& ret)
|
|
{
|
|
switch (ret.type_) {
|
|
case TransformOperationType::TRANSLATE:
|
|
ret.translateOperation_ =
|
|
TranslateOperation::Blend(to.translateOperation_, from.translateOperation_, progress);
|
|
break;
|
|
case TransformOperationType::SCALE:
|
|
ret.scaleOperation_ = ScaleOperation::Blend(to.scaleOperation_, from.scaleOperation_, progress);
|
|
break;
|
|
case TransformOperationType::SKEW:
|
|
ret.skewOperation_ = SkewOperation::Blend(to.skewOperation_, from.skewOperation_, progress);
|
|
break;
|
|
case TransformOperationType::ROTATE:
|
|
ret.rotateOperation_ = RotateOperation::Blend(to.rotateOperation_, from.rotateOperation_, progress);
|
|
break;
|
|
case TransformOperationType::MATRIX: {
|
|
DecomposedTransform toTransform;
|
|
DecomposedTransform fromTransform;
|
|
if (TransformUtil::DecomposeTransform(toTransform, to.matrix4_) &&
|
|
TransformUtil::DecomposeTransform(fromTransform, from.matrix4_)) {
|
|
auto result = TransformUtil::BlendDecomposedTransforms(toTransform, fromTransform, progress);
|
|
ret.matrix4_ = TransformUtil::ComposeTransform(result);
|
|
} else {
|
|
LOGE("DecomposeTransform failed");
|
|
}
|
|
break;
|
|
}
|
|
case TransformOperationType::PERSPECTIVE:
|
|
ret.perspectiveOperation_ =
|
|
PerspectiveOperation::Blend(to.perspectiveOperation_, from.perspectiveOperation_, progress);
|
|
break;
|
|
case TransformOperationType::UNDEFINED:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::string DecomposedTransform::ToString() const
|
|
{
|
|
std::string out;
|
|
out.append("translate: ")
|
|
.append(std::to_string(translate[0]))
|
|
.append(" ")
|
|
.append(std::to_string(translate[1]))
|
|
.append(" ")
|
|
.append(std::to_string(translate[2]))
|
|
.append("\n")
|
|
.append("scale: ")
|
|
.append(std::to_string(scale[0]))
|
|
.append(" ")
|
|
.append(std::to_string(scale[1]))
|
|
.append(" ")
|
|
.append(std::to_string(scale[2]))
|
|
.append("\n")
|
|
.append("skew: ")
|
|
.append(std::to_string(skew[0]))
|
|
.append(" ")
|
|
.append(std::to_string(skew[1]))
|
|
.append(" ")
|
|
.append(std::to_string(skew[2]))
|
|
.append("\n")
|
|
.append("perspective: ")
|
|
.append(std::to_string(perspective[0]))
|
|
.append(" ")
|
|
.append(std::to_string(perspective[1]))
|
|
.append(" ")
|
|
.append(std::to_string(perspective[2]))
|
|
.append(" ")
|
|
.append(std::to_string(perspective[3]))
|
|
.append("\n")
|
|
.append("quaternion: ")
|
|
.append(std::to_string(quaternion.GetX()))
|
|
.append(" ")
|
|
.append(std::to_string(quaternion.GetY()))
|
|
.append(" ")
|
|
.append(std::to_string(quaternion.GetZ()))
|
|
.append(" ")
|
|
.append(std::to_string(quaternion.GetW()))
|
|
.append("\n");
|
|
return out;
|
|
}
|
|
|
|
TransformOperations TransformOperations::Blend(
|
|
const TransformOperations& to, const TransformOperations& from, float progress)
|
|
{
|
|
TransformOperations result;
|
|
to.BlendInner(from, progress, result);
|
|
return result;
|
|
}
|
|
|
|
std::size_t TransformOperations::MatchingLength(const TransformOperations& to, const TransformOperations& from) const
|
|
{
|
|
auto numOperations = std::min(to.operations_.size(), from.operations_.size());
|
|
|
|
for (std::size_t i = 0; i < numOperations; i++) {
|
|
auto& first = to.operations_[i];
|
|
auto& second = from.operations_[i];
|
|
|
|
if (first.type_ != TransformOperationType::UNDEFINED || second.type_ != TransformOperationType::UNDEFINED) {
|
|
if (first.type_ != second.type_) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return std::max(to.operations_.size(), from.operations_.size());
|
|
}
|
|
|
|
void TransformOperations::ParseOperationsToMatrix(std::vector<TransformOperation>& operations)
|
|
{
|
|
for (auto& operation : operations) {
|
|
ParseOperationToMatrix(operation);
|
|
}
|
|
}
|
|
|
|
void TransformOperations::ParseOperationToMatrix(TransformOperation& operation)
|
|
{
|
|
switch (operation.type_) {
|
|
case TransformOperationType::TRANSLATE: {
|
|
auto& translate = operation.translateOperation_;
|
|
float dx = translate.dx.Value();
|
|
float dy = translate.dy.Value();
|
|
float dz = translate.dz.Value();
|
|
operation.matrix4_ = Matrix4::CreateTranslate(dx, dy, dz);
|
|
break;
|
|
}
|
|
case TransformOperationType::SCALE: {
|
|
auto& scale = operation.scaleOperation_;
|
|
operation.matrix4_ = Matrix4::CreateScale(scale.scaleX, scale.scaleY, scale.scaleZ);
|
|
break;
|
|
}
|
|
case TransformOperationType::SKEW: {
|
|
auto& skew = operation.skewOperation_;
|
|
operation.matrix4_ = Matrix4::CreateSkew(skew.skewX, skew.skewY);
|
|
break;
|
|
}
|
|
case TransformOperationType::ROTATE: {
|
|
auto& rotate = operation.rotateOperation_;
|
|
operation.matrix4_ = Matrix4::CreateRotate(rotate.angle, rotate.dx, rotate.dy, rotate.dz);
|
|
break;
|
|
}
|
|
case TransformOperationType::PERSPECTIVE: {
|
|
auto& perspective = operation.perspectiveOperation_;
|
|
double distance = perspective.distance.Value();
|
|
operation.matrix4_ = Matrix4::CreatePerspective(distance);
|
|
break;
|
|
}
|
|
case TransformOperationType::MATRIX:
|
|
case TransformOperationType::UNDEFINED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void TransformOperations::BlendInner(const TransformOperations& from, float progress, TransformOperations& out) const
|
|
{
|
|
auto matchPrefix = MatchingLength(*this, from);
|
|
auto fromSize = from.operations_.size();
|
|
auto toSize = operations_.size();
|
|
|
|
// find most match type transform
|
|
for (std::size_t i = 0; i < matchPrefix; i++) {
|
|
const auto& fromTransformOperation = i >= fromSize ? TransformOperation() : from.operations_[i];
|
|
const auto& toTransformOperation = i >= toSize ? TransformOperation() : operations_[i];
|
|
out.operations_.push_back(TransformOperation::Blend(toTransformOperation, fromTransformOperation, progress));
|
|
}
|
|
// type not match
|
|
if (matchPrefix < std::max(fromSize, toSize)) {
|
|
TransformOperation fromTransformOperation;
|
|
fromTransformOperation.type_ = TransformOperationType::MATRIX;
|
|
fromTransformOperation.matrix4_ = from.ComputerRemaining(matchPrefix);
|
|
TransformOperation toTransformOperation;
|
|
toTransformOperation.type_ = TransformOperationType::MATRIX;
|
|
toTransformOperation.matrix4_ = ComputerRemaining(matchPrefix);
|
|
out.operations_.push_back(TransformOperation::Blend(toTransformOperation, fromTransformOperation, progress));
|
|
}
|
|
}
|
|
|
|
Matrix4 TransformOperations::ComputerRemaining(std::size_t startOffset) const
|
|
{
|
|
Matrix4 result = Matrix4::CreateIdentity();
|
|
for (auto i = startOffset; i < operations_.size(); i++) {
|
|
result = result * operations_[i].matrix4_;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DecomposedTransform TransformUtil::BlendDecomposedTransforms(
|
|
const DecomposedTransform& to, const DecomposedTransform& from, double progress)
|
|
{
|
|
DecomposedTransform ret;
|
|
Combine<3>(ret.translate, to.translate, from.translate, progress, 1.0 - progress);
|
|
Combine<3>(ret.scale, to.scale, from.scale, progress, 1.0 - progress);
|
|
Combine<3>(ret.skew, to.skew, from.skew, progress, 1.0 - progress);
|
|
Combine<4>(ret.perspective, to.perspective, from.perspective, progress, 1.0 - progress);
|
|
ret.quaternion = from.quaternion.Slerp(to.quaternion, progress);
|
|
return ret;
|
|
}
|
|
|
|
bool TransformUtil::DecomposeTransform(DecomposedTransform& out, const Matrix4& transform)
|
|
{
|
|
Matrix4 matrix = transform;
|
|
|
|
if (!Normalize(matrix)) {
|
|
return false;
|
|
}
|
|
|
|
Matrix4 perspectiveMatrix = matrix;
|
|
for (int i = 0; i < 3; i++) {
|
|
perspectiveMatrix.Set(3, i, 0.0);
|
|
}
|
|
perspectiveMatrix.Set(3, 3, 1.0);
|
|
|
|
if (NearZero(std::abs(perspectiveMatrix.Determinant()))) {
|
|
return false;
|
|
}
|
|
|
|
if (!NearZero(matrix.Get(3, 0)) || !NearZero(matrix.Get(3, 1)) || !NearZero(matrix.Get(3, 2))) {
|
|
double rhs[4] = { matrix.Get(3, 0), matrix.Get(3, 1), matrix.Get(3, 2), matrix.Get(3, 3) };
|
|
|
|
Matrix4 inversePerspectiveMatrix = Matrix4::Invert(perspectiveMatrix);
|
|
Matrix4 transposedInversePerspectiveMatrix = inversePerspectiveMatrix;
|
|
|
|
transposedInversePerspectiveMatrix.Transpose();
|
|
transposedInversePerspectiveMatrix.MapScalars(rhs, 4);
|
|
|
|
for (int32_t i = 0; i < 4; i++) {
|
|
out.perspective[i] = rhs[i];
|
|
}
|
|
} else {
|
|
// No perspective.
|
|
for (int i = 0; i < 3; ++i)
|
|
out.perspective[i] = 0.0;
|
|
out.perspective[3] = 1.0;
|
|
}
|
|
|
|
for (int32_t i = 0; i < 3; i++) {
|
|
out.translate[i] = matrix.Get(i, 3);
|
|
}
|
|
|
|
// Copy of matrix is stored in column major order to facilitate column-level
|
|
// operations.
|
|
float column[3][3];
|
|
for (int32_t i = 0; i < 3; i++) {
|
|
for (int32_t j = 0; j < 3; j++) {
|
|
column[i][j] = matrix.Get(j, i);
|
|
}
|
|
}
|
|
|
|
// Compute X scale factor and normalize first column.
|
|
out.scale[0] = Length3(column[0]);
|
|
if (out.scale[0] != 0.0) {
|
|
column[0][0] /= out.scale[0];
|
|
column[0][1] /= out.scale[0];
|
|
column[0][2] /= out.scale[0];
|
|
}
|
|
|
|
// Compute XY shear factor and make 2nd column orthogonal to 1st.
|
|
out.skew[0] = Dot<3>(column[0], column[1]);
|
|
Combine<3>(column[1], column[1], column[0], 1.0, -out.skew[0]);
|
|
|
|
// Now, compute Y scale and normalize 2nd column.
|
|
out.scale[1] = Length3(column[1]);
|
|
if (out.scale[1] != 0.0) {
|
|
column[1][0] /= out.scale[1];
|
|
column[1][1] /= out.scale[1];
|
|
column[1][2] /= out.scale[1];
|
|
}
|
|
|
|
out.skew[0] /= out.scale[1];
|
|
|
|
// Compute XZ and YZ shears, orthogonalize the 3rd column.
|
|
out.skew[1] = Dot<3>(column[0], column[2]);
|
|
Combine<3>(column[2], column[2], column[0], 1.0, -out.skew[1]);
|
|
out.skew[2] = Dot<3>(column[1], column[2]);
|
|
Combine<3>(column[2], column[2], column[1], 1.0, -out.skew[2]);
|
|
|
|
// Next, get Z scale and normalize the 3rd column.
|
|
out.scale[2] = Length3(column[2]);
|
|
if (out.scale[2] != 0.0) {
|
|
column[2][0] /= out.scale[2];
|
|
column[2][1] /= out.scale[2];
|
|
column[2][2] /= out.scale[2];
|
|
}
|
|
|
|
out.skew[1] /= out.scale[2];
|
|
out.skew[2] /= out.scale[2];
|
|
|
|
// At this point, the matrix is orthonormal.
|
|
// Check for a coordinate system flip. If the determinant
|
|
// is -1, then negate the matrix and the scaling factors.
|
|
// only 1 axis is flipped when the determinant is negative. Verify if it is
|
|
// correct to flip all of the scales and matrix elements, as this introduces
|
|
// rotation for the simple case of a single axis scale inversion.
|
|
float pdum3[3];
|
|
Cross3(pdum3, column[1], column[2]);
|
|
if (Dot<3>(column[0], pdum3) < 0) {
|
|
for (int i = 0; i < 3; i++) {
|
|
out.scale[i] *= -1.0;
|
|
for (int j = 0; j < 3; ++j)
|
|
column[i][j] *= -1.0;
|
|
}
|
|
}
|
|
|
|
// See https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion.
|
|
// Note: deviating from spec (http://www.w3.org/TR/css3-transforms/)
|
|
// which has a degenerate case of zero off-diagonal elements in the
|
|
// orthonormal matrix, which leads to errors in determining the sign
|
|
// of the quaternions.
|
|
double q_xx = column[0][0];
|
|
double q_xy = column[1][0];
|
|
double q_xz = column[2][0];
|
|
double q_yx = column[0][1];
|
|
double q_yy = column[1][1];
|
|
double q_yz = column[2][1];
|
|
double q_zx = column[0][2];
|
|
double q_zy = column[1][2];
|
|
double q_zz = column[2][2];
|
|
|
|
double r, s, t, x, y, z, w;
|
|
t = q_xx + q_yy + q_zz;
|
|
if (t > 0) {
|
|
r = std::sqrt(1.0 + t);
|
|
s = 0.5 / r;
|
|
w = 0.5 * r;
|
|
x = (q_zy - q_yz) * s;
|
|
y = (q_xz - q_zx) * s;
|
|
z = (q_yx - q_xy) * s;
|
|
} else if (q_xx > q_yy && q_xx > q_zz) {
|
|
r = std::sqrt(1.0 + q_xx - q_yy - q_zz);
|
|
s = 0.5 / r;
|
|
x = 0.5 * r;
|
|
y = (q_xy + q_yx) * s;
|
|
z = (q_xz + q_zx) * s;
|
|
w = (q_zy - q_yz) * s;
|
|
} else if (q_yy > q_zz) {
|
|
r = std::sqrt(1.0 - q_xx + q_yy - q_zz);
|
|
s = 0.5 / r;
|
|
x = (q_xy + q_yx) * s;
|
|
y = 0.5 * r;
|
|
z = (q_yz + q_zy) * s;
|
|
w = (q_xz - q_zx) * s;
|
|
} else {
|
|
r = std::sqrt(1.0 - q_xx - q_yy + q_zz);
|
|
s = 0.5 / r;
|
|
x = (q_xz + q_zx) * s;
|
|
y = (q_yz + q_zy) * s;
|
|
z = 0.5 * r;
|
|
w = (q_yx - q_xy) * s;
|
|
}
|
|
|
|
out.quaternion.SetX(static_cast<float>(x));
|
|
out.quaternion.SetY(static_cast<float>(y));
|
|
out.quaternion.SetZ(static_cast<float>(z));
|
|
out.quaternion.SetW(static_cast<float>(w));
|
|
|
|
return true;
|
|
}
|
|
|
|
Matrix4 TransformUtil::ComposeTransform(const struct DecomposedTransform& decomp)
|
|
{
|
|
Matrix4 perspective = BuildPerspectiveMatrix(decomp);
|
|
Matrix4 translation = BuildTranslationMatrix(decomp);
|
|
Matrix4 rotation = BuildRotationMatrix(decomp);
|
|
Matrix4 skew = BuildSkewMatrix(decomp);
|
|
Matrix4 scale = BuildScaleMatrix(decomp);
|
|
|
|
return OHOS::Ace::ComposeTransform(perspective, translation, rotation, skew, scale);
|
|
}
|
|
|
|
} // namespace OHOS::Ace
|