c++ - 如何将欧拉旋转从一个坐标系转换到另一个坐标系?右手 Y 向上到左手 Z 向上

标签 c++ unreal-engine4

我为 UE4 编写了一个插件,用于在 UE4 关卡中匹配和生成静态网格物体 Actors。
该插件从每个脚本从 Softimage XSI 导出的文本文件(缩放、旋转、变换)中读取坐标。一切正常。但不是旋转。

我知道跟坐标系有关系。 但我究竟如何从一种转换为另一种?

到目前为止我认为我发现了什么(不是 100% 肯定)
XSI 是右手 Y 向上,旋转顺序 XYZ
UE4是左手Z向上,旋转顺序XZY

在这两个应用程序中,我都有以度为单位的欧拉角。
所以在我的 3D 软件 (Softimage XSI) 中,我有 XYZ 度数,我将其存储到磁盘上的文本文件中。
一行一行,每一行都是一个对象。
在 UE4 中,插件读取此行并在关卡中生成一个 SM Actor。

+++++ 新信息+++++

您好,感谢您到目前为止的回答!

我做了一个视频来展示细节,展示情况。

https://www.youtube.com/watch?v=sWX84FxZTw0


+++++ Actor 生成函数+++++

void SpawnSMActor(const TCHAR *path,float sX,float sY,float sZ,float rX,float rY,float rZ,float pX,float pY,float pZ) 
{
    // Load Static Mesh from given Reference Path from UE4 Explorer
    UStaticMesh* StaMesh = LoadObject<UStaticMesh>(nullptr, path);

    // Transform
    FVector objectScale(sX, sY, sZ);        // Scale

    // ********************************************************************************
    // Conversion XSI Coordinate System to UE4 Coordinate System

    FVector NewPosition;
    FRotator NewRotation;

    // We just simply swap the Z and Y Coordinates

    NewPosition.X = pX * 100; //    TX
    NewPosition.Y = pZ * 100; //    TZ
    NewPosition.Z = pY * 100; //    TY

    // We just simply swap the Pitch(Y) and Yaw(Z) angles

    NewRotation.Roll =  rX;     //  RX
    NewRotation.Pitch = rZ;     //  RZ
    NewRotation.Yaw =   -rY;    //  RY

    FRotator NewobjectRotation(NewRotation.Quaternion());

    FTransform objectTransform(NewobjectRotation, NewPosition, objectScale);

    // ********************************************************************************

    // Creating the Actor and Positioning it in the World based on the Static Mesh
    UWorld* currentWorld = GEditor->GetEditorWorldContext().World();
    ULevel* currentLevel = currentWorld->GetCurrentLevel();
    UClass* StaticMeshClass = AStaticMeshActor::StaticClass();
    AActor* NewActorCreated = GEditor->AddActor(currentLevel, StaticMeshClass, objectTransform, true, RF_Public | RF_Standalone | RF_Transactional);
    AStaticMeshActor* smActor = Cast<AStaticMeshActor>(NewActorCreated);

    smActor->GetStaticMeshComponent()->SetStaticMesh(StaMesh);
    smActor->SetActorScale3D(objectScale);

    // ID Name & Visible Name
    //smActor->Rename(TEXT("MyStaticMeshInTheWorld"));
    //smActor->SetActorLabel("MyStaticMeshInTheWorld");

    GEditor->EditorUpdateComponents();
    smActor->GetStaticMeshComponent()->RegisterComponentWithWorld(currentWorld);
    currentWorld->UpdateWorldComponents(true, false);
    smActor->RerunConstructionScripts();
    GLevelEditorModeTools().MapChangeNotify();
}


如果我在我的 3D 应用程序中将对象沿 UP 轴顺时针旋转 45 度
并在 X 轴上顺时针旋转 45 度,我得到:

X -54,7356 °
Y -30°
Z 35,2644 °

如果我在 UE4 中执行相同的旋转,我会得到:

X -35,2644°
Y 30°
Z 35,2644 °

所以这些将是 UE4 中的正确旋转角度!

但是使用上面列出的代码我得到:

X -54,7355 °
Y 35,2643 °
Z 30°

那是错误的!因为它看起来只是翻转了一些位置。这些角度与我的 3D 应用中的角度基本相同。

Picture



这是我第二次尝试在没有 UE4 API 的情况下解决转换问题。
我知道它不完整,我仍然不完全理解我必须采取的步骤。

但希望它是一个开始。
正如@DavidC.Rankin 上面提到的,我需要定义 (1) 原始坐标系。
不确定这是否是必需的,但我将维基百科中关于欧拉的信息放入 C++ 代码中的矩阵。
这是所有 6 个 Tait-Bryan 角矩阵:
它是否正确?如果是这样,我将如何定义
(2) 目标坐标系 ?
(3) 轮换顺序 ?

#include "pch.h"
#include <iostream>
#include <string>
#include "linalg.h"
using namespace linalg::aliases;
using namespace std;

float x,y,z;

//Pre

void MatrixXZY(float3 angles, float3x3& matrix);
void MatrixXYZ(float3 angles, float3x3& matrix);
void MatrixYXZ(float3 angles, float3x3& matrix);
void MatrixYZX(float3 angles, float3x3& matrix);
void MatrixZYX(float3 angles, float3x3& matrix);
void MatrixZXY(float3 angles, float3x3& matrix);

void PrintMatrix(string name, float3 angles, float3x3& matrix);
void MatrixDecomposeYXZ(float3x3& matrix, float3& angles);




int main()
{
    float3 AnglesIn = { 0, 0, 0 };
    float3 AnglesOut;
    float3x3 Matrix;  // Matrix [Spalte][Zeile]

    cout << "-----------------------------" << endl;
    cout << "Input" << endl;
    cout << AnglesIn[0] << " " << AnglesIn[1] << " " << AnglesIn[2] << " " << endl;
    cout << "-----------------------------" << endl << endl;

    MatrixXZY(AnglesIn, Matrix);
    PrintMatrix("XZY", AnglesIn, Matrix);
    MatrixXYZ(AnglesIn, Matrix);
    PrintMatrix("XYZ", AnglesIn, Matrix);

    MatrixYXZ(AnglesIn, Matrix);
    PrintMatrix("YXZ", AnglesIn, Matrix);
    MatrixDecomposeYXZ(Matrix, AnglesOut);
    cout << "-----------------------------" << endl;
    cout << AnglesOut.x << " " << AnglesOut.y << " " << AnglesOut.z << " " << endl;
    cout << "-----------------------------" << endl << endl;


    MatrixYZX(AnglesIn, Matrix);
    PrintMatrix("YZX", AnglesIn, Matrix);

    MatrixZYX(AnglesIn, Matrix);
    PrintMatrix("ZYX", AnglesIn, Matrix);
    MatrixZXY(AnglesIn, Matrix);
    PrintMatrix("ZXY", AnglesIn, Matrix);

}



void MatrixXZY(float3 angles, float3x3& matrix)
{
    float cosX = cosf(angles.x);     // X
    float sinX = sinf(angles.x);

    float cosY = cosf(angles.y);     // Y
    float sinY = sinf(angles.y);

    float cosZ = cosf(angles.z);     // Z
    float sinZ = sinf(angles.z);


    matrix[0][0] = cosZ * cosY;                         // Spalte 1
    matrix[0][1] = sinX * sinY + cosX * cosY * sinZ;
    matrix[0][2] = cosY * sinX * sinZ - cosX * sinY;

    matrix[1][0] = -sinZ;                               // Spalte 2
    matrix[1][1] = cosX * cosZ;
    matrix[1][2] = cosZ * sinX;

    matrix[2][0] = cosZ * sinY;                         // Spalte 3
    matrix[2][1] = cosX * sinZ * sinY - cosY * sinX;
    matrix[2][2] = cosX * cosY + sinX * sinZ * sinY;

}
void MatrixXYZ(float3 angles, float3x3& matrix)
{
    float cosX = cosf(angles.x);     // X
    float sinX = sinf(angles.x);

    float cosY = cosf(angles.y);     // Y
    float sinY = sinf(angles.y);

    float cosZ = cosf(angles.z);     // Z
    float sinZ = sinf(angles.z);


    matrix[0][0] = cosY * cosZ;                         // Spalte 1
    matrix[0][1] = cosX * sinZ + cosZ * sinX * sinY;
    matrix[0][2] = sinX * sinZ - cosX * cosZ * sinY;

    matrix[1][0] = -cosY * sinZ;                        // Spalte 2
    matrix[1][1] = cosX * cosZ - sinX * sinY * sinZ;
    matrix[1][2] = cosZ * sinX + cosX * sinY * sinZ;

    matrix[2][0] = sinY;                                // Spalte 3
    matrix[2][1] = -cosY * sinX;
    matrix[2][2] = cosX * cosY;

}

void MatrixYXZ(float3 angles, float3x3& matrix)
{
    float cosX = cosf(angles.x);     // X
    float sinX = sinf(angles.x);

    float cosY = cosf(angles.y);     // Y
    float sinY = sinf(angles.y);

    float cosZ = cosf(angles.z);     // Z
    float sinZ = sinf(angles.z);

    matrix[0][0] = cosY * cosZ + sinY * sinX * sinZ;    // Spalte 1
    matrix[0][1] = cosX * sinZ;
    matrix[0][2] = cosY * sinX * sinZ - cosZ * sinY;

    matrix[1][0] = cosZ * sinY * sinX - cosY * sinZ;    // Spalte 2
    matrix[1][1] = cosX * cosZ;
    matrix[1][2] = cosY * cosZ * sinX + sinY * sinZ;

    matrix[2][0] = cosX * sinY;                         // Spalte 3
    matrix[2][1] = -sinX;
    matrix[2][2] = cosY * cosX;

}
void MatrixYZX(float3 angles, float3x3& matrix)
{
    float cosX = cosf(angles.x);     // X
    float sinX = sinf(angles.x);

    float cosY = cosf(angles.y);     // Y
    float sinY = sinf(angles.y);

    float cosZ = cosf(angles.z);     // Z
    float sinZ = sinf(angles.z);


    matrix[0][0] = cosY * cosZ;                         // Spalte 1
    matrix[0][1] = sinZ;
    matrix[0][2] = -cosZ * sinY;

    matrix[1][0] = sinY * sinX - cosY * cosX * sinZ;    // Spalte 2
    matrix[1][1] = cosZ * cosX;
    matrix[1][2] = cosY * sinX + cosX * sinY * sinZ;

    matrix[2][0] = cosX * sinY + cosY * sinZ * sinX;    // Spalte 3
    matrix[2][1] = -cosZ * sinX;
    matrix[2][2] = cosY * cosX - sinY * sinZ * sinX;

}

void MatrixZYX(float3 angles, float3x3& matrix)
{
    float cosX = cosf(angles.x);     // X
    float sinX = sinf(angles.x);

    float cosY = cosf(angles.y);     // Y
    float sinY = sinf(angles.y);

    float cosZ = cosf(angles.z);     // Z
    float sinZ = sinf(angles.z);


    matrix[0][0] = cosZ * cosY;                         // Spalte 1
    matrix[0][1] = cosY * sinZ;
    matrix[0][2] = -sinY;

    matrix[1][0] = cosZ * sinY * sinX - cosX * sinZ;    // Spalte 2
    matrix[1][1] = cosZ * cosX + sinZ * sinY * sinX;
    matrix[1][2] = cosY * sinX;

    matrix[2][0] = sinZ * sinX + cosZ * cosX * sinY;    // Spalte 3
    matrix[2][1] = cosX * sinZ * sinY - cosZ * sinX;
    matrix[2][2] = cosY * cosX;

}
void MatrixZXY(float3 angles, float3x3& matrix)
{
    float cosX = cosf(angles.x);     // X
    float sinX = sinf(angles.x);

    float cosY = cosf(angles.y);     // Y
    float sinY = sinf(angles.y);

    float cosZ = cosf(angles.z);     // Z
    float sinZ = sinf(angles.z);


    matrix[0][0] = cosZ * cosY - sinZ * sinX * sinY;        // Spalte 1
    matrix[0][1] = cosY * sinZ + cosZ * sinX * sinY;
    matrix[0][2] = -cosX * sinY;

    matrix[1][0] = -cosX * sinZ;                            // Spalte 2
    matrix[1][1] = cosZ * cosX;
    matrix[1][2] = sinX;

    matrix[2][0] = cosZ * sinY + cosY * sinZ * sinX;        // Spalte 3
    matrix[2][1] = sinZ * sinY - cosZ * cosY * sinX;
    matrix[2][2] = cosX * cosY;

}


void PrintMatrix(string name, float3 angles, float3x3& matrix)
{
    cout << "-----------------------------" << endl;
    cout << name << "-Matrix" << endl;
    cout << "-----------------------------" << endl;

    cout << matrix[0][0] << " " << matrix[1][0] << " " << matrix[2][0] << " " << endl;
    cout << matrix[0][1] << " " << matrix[1][1] << " " << matrix[2][1] << " " << endl;
    cout << matrix[0][2] << " " << matrix[1][2] << " " << matrix[2][2] << " " << endl;
    cout << "-----------------------------" << endl << endl << endl;
}



void MatrixDecomposeYXZ(float3x3& matrix, float3& angles)
{
    angles.x = asinf(-matrix[2][1]);                        //              X
    if (cosf(angles.x) > 0.0001)                            // Not at poles X
    {
        angles.y = atan2f(matrix[2][0], matrix[2][2]);      //              Y
        angles.z = atan2f(matrix[0][1], matrix[1][1]);      //              Z
    }
    else
    {
        angles.y = 0.0f;                                    //              Y
        angles.z = atan2f(-matrix[1][0], matrix[0][0]);     //              Z
    }
}

最佳答案

好的,Zakwayda 先生在 gamedev.net 上解决了这个问题(谢谢!)-> Link
Softimage XSI 2015 到 Unreal Engine 4.22.3

void SpawnSMActor(const TCHAR *path,float sX,float sY,float sZ,float rX,float rY,float rZ,float pX,float pY,float pZ) 
{
    float rad = 0.0174532925199444; // FQuat needs Radians. So degree * Pi/180 | Pi/180 = 0.0174532...

    // Transform
    FVector Scale(sX, sY, sZ);      // Scale
    FVector Position;               // Translation

    // ************************************************************************************
    // Conversion XSI Coordinate System to UE4 Coordinate System

    // Position - Swap Z and Y axis and correct Position Scaling

    Position.X = pX * 100; 
    Position.Y = pZ * 100; 
    Position.Z = pY * 100; 

    // Quaternions - Convert Rotations from XSI to UE4

    FQuat qx(FVector(1, 0, 0), -rX * rad);
    FQuat qz(FVector(0, 0, 1), -rY * rad);
    FQuat qy(FVector(0, 1, 0), -rZ * rad);

    FQuat qu = qy * qz * qx; // Change Rotation Order if necessary

    FRotator Rotation(qu);
    FTransform Transform(Rotation, Position, Scale);

    // ************************************************************************************
    // Load Static Mesh from given Reference Path from UE4 Explorer

    UStaticMesh* StaMesh = LoadObject<UStaticMesh>(nullptr, path);

    // Creating the Actor and Positioning it in the World based on the Static Mesh
    UWorld* currentWorld = GEditor->GetEditorWorldContext().World();
    ULevel* currentLevel = currentWorld->GetCurrentLevel();
    UClass* StaticMeshClass = AStaticMeshActor::StaticClass();
    AActor* NewActorCreated = GEditor->AddActor(currentLevel, StaticMeshClass, Transform, true, RF_Public | RF_Standalone | RF_Transactional);
    AStaticMeshActor* smActor = Cast<AStaticMeshActor>(NewActorCreated);

    smActor->GetStaticMeshComponent()->SetStaticMesh(StaMesh);
    smActor->SetActorScale3D(Scale);

    // ID Name & Visible Name
    //smActor->Rename(TEXT("MyStaticMeshInTheWorld"));
    //smActor->SetActorLabel("MyStaticMeshInTheWorld");

    GEditor->EditorUpdateComponents();
    smActor->GetStaticMeshComponent()->RegisterComponentWithWorld(currentWorld);
    currentWorld->UpdateWorldComponents(true, false);
    smActor->RerunConstructionScripts();
    GLevelEditorModeTools().MapChangeNotify();
}

关于c++ - 如何将欧拉旋转从一个坐标系转换到另一个坐标系?右手 Y 向上到左手 Z 向上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57025469/

相关文章:

c++ - 无法在其他类 C++ 之前访问类

c++ - 如何检测插入/插入Oculus触摸 Controller ?

c++ - 如何在虚幻引擎中添加小部件

c++ - 处理与 TriggerSphere 和其他 Actor 的重叠?

python - UE4.27中的景观创建

java - C++ web 框架,如 spring for Java

c++ - Gtk+ 删除 Gtk::Treeview 上第一列的填充/边距

c++ - Linux下c++中的绝对文件路径

c++ - 基于修改后的quick_sort的nth_element实现,未按预期工作

c++ - 由于某种原因,客户端未调用服务器 RPC