【发布时间】:2019-11-23 07:31:40
【问题描述】:
我为 UE4 编写了一个插件,用于将静态网格体 Actor 匹配并生成到 UE4 的关卡中。
该插件从每个脚本从 Softimage XSI 导出的文本文件(Scale、Rotation、Transformation)中读取坐标。一切都已经奏效了。但不是轮换。
我知道它与坐标系有关。 但是我究竟如何从一种转换到另一种呢?
我认为到目前为止我发现了什么(不是 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 应用程序中的角度基本相同。
这是我第二次尝试在不使用 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
}
}
【问题讨论】:
-
请展示并解释更多您尝试过的内容。它可能有助于提供一个读取数据的代码基础来转换它们(不是,即只是通过不变地传递它,即为实际代码制作一个占位符)并以所需的形式输出/转发它们。如果你有一些东西可以完成这项工作并且只是无法正确轮换,那么就为它制作一个minimal reproducible example。
-
必须定义(1)原坐标系; (2)目标坐标系; (3) 轮换顺序。然后你可以形成你的转换矩阵。请参阅Euler angles - Wikipedia 作为一个示例。大约有 4 种不同的方法来选择坐标系统和旋转顺序。 (维基百科也不错)
-
@DavidC.Rankin 你好大卫,谢谢。这是一个真正有帮助的答案。我需要知道实现目标的步骤。现在我也许可以自己弄清楚了。
-
我发布的答案好运吗?
标签: c++ unreal-engine4