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

时间:2019-07-14 07:39:12

标签: c++ unreal-engine4

我为UE4编写了一个插件,用于将静态网格物体Actor匹配并生成到UE4级别。
该插件从文本文件(Scale,Rotation,Transformation)读取坐标,该文本文件按脚本从Softimage XSI导出。一切正常。但不是旋转。

我知道它与坐标系有关。 但是我该如何准确地从一个转换为另一个呢?

到目前为止,我认为我发现了什么(不确定100%)
XSI为右手Y-up,旋转顺序为XYZ
UE4左旋Z-up,旋转顺序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)原始坐标系。
不知道这是否是必要的,但是我将Wikipedia中有关Euler的信息放入了C ++代码中的矩阵。
这是所有Tait–Bryan角度矩阵中的6个:
它是否正确?如果是这样,我将如何定义
(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
    }
}

2 个答案:

答案 0 :(得分:1)

好的,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();
}

答案 1 :(得分:0)

您可以在UE4中使用FTransform变换旋转方式。 这为您提供了一个转换矩阵,我相信可以解决您的问题。

https://api.unrealengine.com/INT/API/Runtime/Core/Math/FTransform/index.html

  

由比例,旋转(作为四元数)和   翻译。

     

转换可用于将一个空间转换为另一个空间,例如   通过将位置和方向从本地空间转换为   世界空间。

从外观上看,听起来像您只需要交换Z和Y坐标值以及俯仰和偏航值即可进行旋转。

例如:

Pitch = Yaw;
Yaw = Pitch;

这是一个代码示例,说明如何在UE4 C ++中执行此操作

// We just simply swap the Z and Y Coordinates
FVector NewPosition;
NewPosition.X = InPosition.X;
NewPosition.Y = InPosition.Z;
NewPosition.Z = InPosition.Y;
SetActorLocation(NewPosition);

因此,我们只需交换YZ坐标。

现在我们可以对旋转进行相同的操作,注意命名有些不同,但是UE4很快解释了一下,这是一张图片:

enter image description here

// We just simply swap the Pitch(Y) and Yaw(Z) angles
FRotator NewRotation;
NewRotation.Roll = InRotation.X;
NewRotation.Pitch = InRotation.Z;
NewRotation.Yaw = InRotation.Y;
SetActorRotation(NewRotation.Quaternion());

现在从您的问题中我不能确定轴的方向,但是如果网格沿相反的方向移动,则可以简单地取轴的负值,例如:

FVector NewPosition;
NewPosition.X = -InPosition.X; // Note the - in front of InPosition.X; You can also multiply with -1
NewPosition.Y = InPosition.Z;
NewPosition.Z = InPosition.Y;
SetActorLocation(NewPosition);

在这里,我们将InPosition.X设为负数来移动-InPosition.X,则方向相反。 在两个不同的坐标系之间进行转换应该很简单。