🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

3D-app Euler-Rotations to UE4 Euler-Rotations

Started by
29 comments, last by ManitouVR 4 years, 11 months ago
3 hours ago, C3D_ said:

@Zakwayda Okay, here is a first try. Not sure if this is what you meant.

Is this correct?



FQuat qx(pX, 0, 0, -rX);
FQuat qz(0, 0, pZ, -rY);
FQuat qy(0, pY, 0, -rZ);

 

You appear to be building the rotation axes using the components of the actor's position, but the position is unrelated to anything having to do with rotation.

By 'world axes', I mean:


world X axis: 1 0 0
world Y axis: 0 1 0
world Z axis: 0 0 1

So it looks like your code is correct, except where you have pX, pY, and pZ, you should just have '1', i.e.:


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

 

Advertisement

Something occurred to me after posting the above, so I checked the documentation for FQuat, here:

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

As I thought might be the case, the constructor you're using (the one that takes 4 floats) is actually the 'XYZW' constructor that sets the elements of the quaternion directly. That's not what you want. You want the constructor that takes an FVector instance and a float - that's the axis-angle constructor.

This is untested, but the correct code should look something like this:


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

This may be overly obvious (maybe this was covered earlier in the thread - I can't remember), but I'll also point out that the second argument to the FQuat constructor, the angle, needs to be in radians, so you'll need to take that into account if your input data uses degrees. (Obviously the representation - radians vs degrees - would need to match when performing Euler-angle conversions as well, generally speaking.)

@Zakwayda Cool, just right in time, haha!

I was just testing all 6 possible combinations of the quaternion multiplications but every single one failed in the results.
 


void SpawnSMActor(const TCHAR *path,float sX,float sY,float sZ,float rX,float rY,float rZ,float pX,float pY,float pZ)
{
    // Transform
    FVector Scale(sX, sY, sZ);        // Scale
    FVector Position;                 // Translation
    

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

    // Position Swap the Z and Y Coordinates

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

    // Quaternions

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

    //FQuat qu = qy * qz * qx;  // Nope        3.37    , 90    , 5.35
    FQuat qu = qy * qx * qz;    // Nope        32.52    , 90    , 34.50
    //FQuat qu = qx * qy * qz;  // Nope        24.58    , 90    , 26.56
    //FQuat qu = qx * qz * qy;  // Nope        32.3    , 90    , 34.5
    //FQuat qu = qz * qx * qy;  // Nope        6.67    , 90    , 8.88
    //FQuat qu = qz * qy * qx;  // Nope        17.56    , 90    , 19.76

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

I will check out the new instructions

3D Artist

14 minutes ago, C3D_ said:

I was just testing all 6 possible combinations of the quaternion multiplications but every single one failed in the results.

Quote

I will check out the new instructions

Right, generally speaking it only has a chance of working if the correct FQuat constructor is used (it won't work with the XYZW constructor).

Also, if you're evaluating the results by comparing Euler angles, it may appear not to be working when it actually is. First, at the risk of stating the obvious, be sure you're accounting for radian-degree conversions. Also, Euler-angle representations aren't unique in that more than one Euler-angle triple can represent the same orientation, so the results could look different when they actually match. And then there's numerical error, which can cause results to differ (although not by much in most cases).

To see if it works, I'd recommend just checking visually, that is, see if the actors as instantiated in UE appear to be oriented correctly. Due to the reasons mentioned above, comparing Euler angles may not be that useful.

Yes, i check visually. Yes iam aware of floating point precision errors.

Here is the new code with the changes applyd, testing all 6 combos again. I think we come closer already: (Tested only 1 combo yet)
 


// Transform
    FVector Scale(sX, sY, sZ);        // Scale
    FVector Position;                 // Translation
    float rad = 0.0174532925199444;

    // ************************************************************************************
    // Conversion XSI Coordinate System to UE4 Coordinate System
        
    // Position Swap the Z and Y Coordinates

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

    // Quaternions

    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 * qx * qz;  // Nope        -31.48    , 56.44    , 31.48

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

 

3D Artist

10 minutes ago, C3D_ said:

Yes, i check visually. Yes iam aware of floating point precision errors.

Just for the record, when I mention things like precision error, I'm not suggesting you're not already aware. I'm just trying to be thorough.

That said, the reason I mentioned the vagaries of comparing Euler angles is that I noticed you have some comments like this one:


// Nope        -31.48    , 56.44    , 31.48

Which seemed to suggest you might be evaluating the results in that way. So, I just wanted to point out that comparing Euler angles might be misleading and that checking visually might be better.

Quote

Here is my new code with the changes applyd, testing all 6 combos again.

If the Softimage order is XYZ, then I think the order will be either qy*qz*qx or qx*qz*qy. If neither of those works though, it'd probably be worth checking all permutations, just in case there's some vagary regarding Softimage and Euler order.

@Zakwayda Sir, you did it!! Thank you, thank you, thank you!!!! :)  :) You are THE man!!

And thank you for being so precise. Please dont misunderstand me. I'am more than thankful for your precise instructions.

Maybe i did sound rude (i speak german) but i just wanted to inform you that i follow your instructions very carefully. :)

I never felt that you thought that iam not aware. (Although iam not aware of most of this code, lol! )

However, here is the code that gives the correct rotations:

Wanted UE4 Euler rotations was X -35,2644    Y 30    Z 35,2644  (Turnig 45 deg clockwise in the UP-axis and then 45 deg clockwise on the world X-axis)
 


// Quaternions

    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;    // YES!!    -35,264    , 29,999    , 35,264
    //FQuat qu = qy * qx * qz;  // Nope        -31.48    , 56.44    , 31.48
 

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

Done.thumb.png.0685f1f660af0671619c4fd17cf6aeef.png

3D Artist

21 minutes ago, C3D_ said:

@Zakwayda Sir, you did it!! Thank you, thank you, thank you!!!! :)  :) You are THE man!!

And thank you for being so precise. Please dont misunderstand me. I'am more than thankful for your precise instructions.

Maybe i did sound rude (i speak german) but i just wanted to inform you that i follow your instructions very carefully. :)

I never felt that you thought that iam not aware. (Although iam not aware of most of this code, lol! )

Oh, no worries :) I just mentioned that because I know sometimes it can be irritating to be told things you already know.

Quote

However, here is the code that gives the correct rotations:

Great! The code you posted looks correct and is what I had in mind. I hope it continues to work and gives you the correct results in all cases. (If you run into further problems though, you can always post back, and maybe we can figure it out.)

I think i tested all possible rotations so far and the results look always correct.

Thanks for your offer to let me post back anytime. I hope i dont have to, haha!

Thanks, i could not have done this alone and you will be mentioned when i give this little plugin away! :)

 

3D Artist

Here is the code for the final function. May it help somebody someday hopefully. (UE4 v 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();
}

 

3D Artist

This topic is closed to new replies.

Advertisement