Download

Trying to solve the issues I have with rotation matrices and quaternions

Hello guys!

First of all. this is a big post, so I apologize for its size. Sorry for my bad grammar, its 3:00 am here and I’m sleepy.

I’m expanding my skill mechanic and I’ve tried to use both quaternions and affine transformations/rotation matrices to do the job, using my mathematical knowledge I’ve learned long ago, on my university.

Based on the facts that quaternions are 4D vectors extended from i-numbers that should be normalized before multiply them with any vectors or generate any kind of rotation matrix (because we must bring it back to the unit sphere in the 3D Euclidean space) and the multiplication between two vectors results in a perpendicular vector (result of a cross product) that not necessarily is a unit vector and should be normalized, among other things, I tried to make an actor, captured by black hole skill, initiate an elliptic orbit around its captor.

Elliptic orbits were calculated, initially, based on the ellipse parametric equation (the FVector NextLocation = (…) part, lines 468 - 477). As you can see in the video, it works relatively well, except for ONE PROBLEM: the orbiting actor was supposed to start orbiting in the position (SkillLocation.X + radius * Cos(XYAngle), SkillLocation.Y + radius * Sin(XYAngle), SkillLocation.Z), the XYAngle is calculated in the ABlackHoleSkill::GenerateOrbitData() method), but, as you can see, is way off, In the video, the orange line is used to mark the (constantcos(0),0,0), the magenta to mark the (0,constantc sin(90),0), the cyan marking the (constantccos(180),0,0), and the yellow marking the (0,constantcsin(270),0), for visual debug purpose, as well the white line, marking the vector point to the orbiting actor initial location. I’d appreciate if someone tell me my mistake here.

Second, I tried, inside the GenerateOrbitData method, to project the PullDirection vector on the planes XY XZ and YZ, and to find the angles between these projections and the skill’s forward and right vectors, respectively. Once I’ve got these values, I increased them by a specific value and used them on rotation matrices (basically making use of Euler angles), but I didn’t get the result I was expecting. I just left the Z axis rotation matrix uncommented, to rotate the orbiting actor on the XY plane, like the parametric equation used ealier. I tried this to make the captured actor orbit not only on XY plane, but any plane, around the skill.

Here is the video: https://www.youtube.com/watch?v=aZnx…ature=youtu.be

And here is the code:

.h:
https://pastebin.com/tiBjeWpX

.cpp
https://pastebin.com/d705gbts

At the end of the video, you can see that the build just failed, ignore that, the FMatrix::TransformVector4() doesn’t work neither.

Also, in the GenerateOrbitData(), I’m using a quaternion to rotate the orbiting actor around its own center, ignore it for now.

Can you guys tell me my mistakes? Also, to avoid a gimbal lock (because I’m using Euler angles), can you tell how to do what I’m trying to do, instead using rotation matrices?

Thanks! =)

Just a little bump here to get some enlightenment about the subject

It’s easier than you’d think. Quaternions are basically a vector with a magnitude. The vector is your rotational axis in 3D space, and your magnitude is how much to rotate around it in radians. The polarity of the vector determines the direction of rotation around the axis, giving rise to the term “right-handed system”. (Using your right hand: thumb up, fingers curl in direction of rotation.)

Store your initial orientation as a quaternion created from the normal actor rotation. From then on add your rotational offsets by making a new quaternion from the rotation you want and combine the two. To use your rotation either expose SetActorRotation(Quaternion) to blueprints or get the rotator back out each frame and use it as-is.

Don’t bother trying to make quaternions from their components. They’re not too hard to understand, but getting the result you want is exceedingly difficult in game dev because of how we approach it. You’d end up lerping your current axial vector to a new axial vector and that won’t give linear rotation. God knows how you’d get the magnitude around the axis. Just use the built-in methods.

Avoiding doing any FRotator transformational operations or avoiding splitting the axes to do operations is enough to avoid gimbal lock.

Thanks for your reply!

I was looking for something like you said on forums, could you give me an example? How to add an rotation offset aka (x,y,z) translation to a quaternion, without coverting to a homogenous 4x4 matrix, to have a rotation around a point instead rotating the actor around its own center?

Maybe something like this snippet?



FQuat OrbitingActorOrientation = TempArr[Index]->GetOwner()->GetActorRotation().Quaternion;
FQuat OrientationQuat = FVector(
                                                          OrbitDataArr[Index].MajorOrbitRadius,
                                                          OrbitDataArr[Index].MajorOrbitRadius *
                                                          MajorEllipticOrbitFraction,
                                                          0.f
                                                     ).ToOrientationQuat() +
     FQuat(
                    FVector::UpVector,
                    FMath::DegreesToRadians(OrbitDataArr[Index].XYAngle)
     );
OrbitingActorOrientation *= OrientationQuat;
TempArr[Index]->GetOwner()->SetActorRotation(OrbitingActorOrientation);


EDIT: Doesn’t work this way, doesn’t rotate TempArr[Index]->GetOwner() around the BlackHoleLocation elliptically.

The order of multiplication matters with quaternions. Try switching those around to see what happens. Also try addition, as I believe this makes the second operator apply relative to the first’s orientation which it looks like you’re trying to do. I think multiplication causes each side of the operation to combine as if they are both in world space.

In any case, still don’t bother making quaternions from its component vector/magnitude like you are above. Figure out what FRotator that you want to use and convert that to a quaternion and then combine them. So if you want to rotate 60 degrees around the yaw of the current quaternion, make an FRotator(0, 0, 60), convert it to a quaternion and them combine them.

Thanks for your reply! =)

I guess I’m coding in the wrong way, but that FVector contains the X and Y offsets relatively to the semimajor radius and semiminor radius of an ellipse, but the way I’m doing is wrong, right?