Problem with rotation of objects using directional vectors (banking?)

Started by
7 comments, last by JoeJ 6 years, 3 months ago

I've been puzzling over this for days now, and have hit a wall so need some help!

I'm using VR motion controllers in Unreal Engine. I need an object to follow along with the motion controller, but to maintain a certain orientation. If the motion controller / object were to move around on the flat XY plane (UE4 is Z up so the XY plane is the horizontal plane), the top of the object would be pointing upwards, and the object just turns corners following the direction of movement (turning much like a car would when driving around). At each tick, I am taking the current position of the motion controller, and making a normalised directional vector using (CurrentPositionXYZ - PreviousPositionXYZ).

Using this direction (forward vector), I am then making a rotation from the forward and up vectors. In order to do that I am first finding out the right vector by taking the cross product of a global up vector (0,0,1) with the forward vector. Then I take the cross product of the right and forward vectors to get the actual up vector. Then I make the rotation with forward and up vectors.

Here is what this looks like if the motion controller movement were to be locked to the XY plane and move in a circle.

XY_Flat.gif.39c9d6e22b5d5c9a54cca2a97c2f10d9.gif

All looks good, and exactly what I was hoping for. However, if the circular movement was to occur in either of the other planes (XZ or YZ) then we have a problem at two points on the circle when the forward (directional) vector lines up with the global up vector I'm using. Because these calculations have no way of knowing that the object is moving in a certain direction, when the direction changes to move from negative Y to positive Y, for example, the whole thing flips.

Here's what this looks like with a circle drawn in the YZ plane:

YCircle_Flip.gif.745a1efce8488e83350f53a5dd3e4c99.gif 

This is obviously no good, as it breaks the consistency of movement. As such, I wrote some logic that detects if the X or Y value crosses 0 when the direction is pointing up/down, and then reverses the global up vector. Assuming there is no movement/value in X, the movement graph for this looks like this:

Graph_01.PNG.366c8f494ae52df0b03861c03fcea8e6.PNG

Red = X; Green = Y; Blue = Z  || Circle in YZ plane starting movement in -Y direction.

And with the up vector flip logic added, it looks like this:

YCircle_NoX.gif.1a02310ed5309b9cdaf1656cf6e36ada.gif

Looking good!

Except there's a massive problem. This all works fine if the movement is constrained to a plane (in this case the YZ plane, but also works perfectly in the XZ plane), but breaks down if the circular movement is drawn eve slightly off-axis. Here's what happens:

YCircle_0_2X.gif.b53ca3e78fa516e4b4e6e6af3dd4a585.gif

There's a section where everything flips. The size of that section is determined by the magnitude of X, and relates to the part of the graph pointed to in this diagram:

Graph_01_CloseUp.PNG.2fe365baafd0367c69b74e95103b5587.PNG

Here X is set at a constant -0.2.

As soon as the Y value passes the value of X and approaches zero, the value in X starts having greater and greater influence over the direction, and then as Y starts moving further away from zero again, the influence drops away again. Although this makes sense, it's not what I want, and I can't figure out how to achieve what I want. I'm having trouble even defining the nature of the problem. Perhaps (probably) I'm doing this in a really stupid way, and there's a much simpler solution for what I'm trying to achieve. I could really use some help!

Given a progression of known locations through 3D space, what is the best way to move an object along them such that its axes bank (if that's the correct term) realistically and don't do any weird flipping around? All help massively appreciated!

 

 

Advertisement

It looks like UE is using an Euler controller for rotation, which is always going to have flipping issues.  3D rotations can't properly be described by only 3 values, but Euler angles make sense to our brains, especially for animating.  I can think of two solutions:

1: Add a parent node located at the center of the circle, and just rotate that instead of trying to move AND rotate the orbiting node.

2: Make your "up vector" point to the center of rotation (ie, the center of the circle) instead of the world up.

I'm just using the circle here as an abstract (and perfect) example. What's actually going on is the player is moving their hand freely through space in whatever direction they want, and I am trying to attach an object to their hand position that behaves in the way described above. So unfortunately I don't think either of your suggestions will work, unless I'm misunderstanding something...

Nope, you're right. Neither will work really.  I was thinking you were just following circles.

What makes it complicated is the inverted loops in all three axes.  I think you may have to reverse your thinking.  It sounds like the player input affects the position and then you try to simulate the banking/rotation.  I worked on an airplane game and we did the opposite.  The player input controlled the banking/rotation and the position was calculated from there.  Is that possible in your game?

Ah, that's interesting. What's the best way to control the banking/rotation while avoiding axis flips etc? Do you do it by adding/subtracting from a rotation rather than setting it outright?

I think your problem comes from using the velocity of the controller, which can have any direction so flipping cases when combining this with a fixed direction are unavoidable. (This is not a problem of euler angles. It's the same problem than trying to build a smooth tangent space over the surface of a sphere - again flipping is unavoidable.)

If you use  e.g. the vector from player belly to controller instead velocity you could build a stable orientation from that.

Or simply control rotation about up direction by controller horizontal position and rotation about horizontal direction by controller vertical position (like controlling FPS camera with mouse).

 

Edit: So VR motion controllers do not provide any orientation data? Otherwise you could use that of course.

@JoeJ: the VR controllers do provide orientation data, but that's not what I want. If I simply wanted the object to have the same orientation and position as the motion controller, it would be as simple as parenting the object to the motion controller. This is what you do for the mesh used to represent the hand/controller of the player, for example.

What I want is a situation where the position of the object is aligned with the position of the motion controller, but the orientation is governed by the movement of the controller. Think of the way a child holds a toy airplane and flies it around. Imagine he makes the plane do a loop-the-loop: as he moves his hand in a circular motion, he has to rotate it at the same time to make the plane look like it's following the direction of the loop. I am trying to work out how to achieve the same thing without the child having to rotate his hand. In other words, imagine that child simply moves his hand in a loop-the-loop and the plane rotates itself as if it were flying that loop (as if he was rotating his hand). The hand holding the plane could actually be oriented in any direction, it's the movement/direction that governs the orientation of the plane.

I know this probably seems rather strange. Intuitively, I feel like it must be possible somehow though. But I think trying to achieve it solely from a normalised direction vector, as I am currently trying, is not going to work. It's not enough data, or not the correct data.

Nice explantation, i think what you wont can be achieved this way:

You make the difference vector as before from previous to current position to get a target front direction. (You may blend this vector with the previous one for some filtering).

You select the objects front vector from its global world transform to have the current front direction.

Then generate a rotation from current to target direction and apply this rotation to the object.

 

This will be stable, but the ubjects up vector is not constrained, so the aeroplane may get upside down.

You can optionally fix this by making the object turn up SLOWLY, so only at max angular velocity. This turns flipping cases into slow oscillation in the worst case (which should not happen except the player has fun making the object trying to get up either this or the other way around. As lonfg s it happens slowly, it will be fine anyways.)

This topic is closed to new replies.

Advertisement