Code issue: Vector motion based on forward vector.

hazmhox

Moderator
Featured Contributor
Messages
1,502
Reactions
7,318
Points
173
Yo coders!

I got and issue with a vector computation. I'm somewhat "okish" with vectors for basic calculations, but this one, I can't figure out.

I want to control the Window Camera left/right and up/down motions based on it's forward vector no matter the rotation on other axis.
Here's two shot to explain the situation:

maestro-vector-forward01.jpg

On this shot, it's the "easy" situation. The forward vector point to Selene, only X and Y are rotated, so if I'm animating a motion, moving the camera will follow the axis as expected.












maestro-vector-forward02.jpg
On that one, the Z vector is rotated, which suddenly makes the left/right/up/down controls incorrect since "visually" the preview of the shot is correct, but the vectors are rotated.










The idea is to always move based on the orientation of the preview. So, only use the forward axis as a reference and move up/down/left/right based on the world up vector compensated for the forward vector of the camera. I'm just unable to figure out the calculation for this.

I'm kind of starting to believe I would simply have to change the calculations based on the camera and the preview orientation. But I'm wondering if my initial approach is doable ( I suspect so, but I might not have the braincells to do so :p)

If you have any insights I'd be super happy!
Cheers!
 
: D

C#:
                switch (Direction)
                {
                    case "Backward":
                        motion = CameraAtom.mainController.control.rotation * Vector3.back;
                        break;
                    case "Up":
                        motion = Vector3.up;
                        break;
                    case "Down":
                        motion = Vector3.down;
                        break;
                    case "Left":
                        motion = Quaternion.AngleAxis(-90, Vector3.up) * CameraAtom.mainController.control.forward;
                        break;
                    case "Right":
                        motion = Quaternion.AngleAxis(90, Vector3.up) * CameraAtom.mainController.control.forward;
                        break;
                    default:
                        motion = CameraAtom.mainController.control.rotation * Vector3.forward;
                        break;
                }
               CameraAtom.mainController.MoveControl( CameraAtom.mainController.control.position + motion * Time.deltaTime );

This is the cleaned up version with "somewhat" working code.

The "Up" and "Down" version are temporary, the original code wasn't working as expected, I'm just leaving a clean temporary code in there.

The "Left" and "Right" are working ALMOST as expected... but the more the camera is tilted on the X axis, the more the camera moves up or down depending on the tilt direction. If the X rotation is at zero, it works perfectly.
 
I'm not sure I understand what the issue is, I tried your method and it moves the controller left/right relative to its forward axis when left/right is triggered, it doesn't flip, regardless of how the controller is rotated. Here's the code I tried

C#:
class MoveTest : MVRScript
{
    FreeControllerV3 _controller;

    public override void Init()
    {
        _controller = containingAtom.mainController;
        CreateButton("Left").AddListener(Left);
        CreateButton("Right").AddListener(Right);
    }

    void Left() => Move(Quaternion.AngleAxis(-90, Vector3.up) * _controller.control.forward);
    void Right() => Move(Quaternion.AngleAxis(90, Vector3.up) * _controller.control.forward);
    void Move(Vector3 motion) => _controller.MoveControl(_controller.control.position + motion * Time.deltaTime * 10);
}

Maybe you can record a video to illustrate the issue?
 
Yup of course! Thank you for looking into this everlaster : )

Here you go! You'll see the "bug" (or incorrect behavior might be better) happens at the moment I'm tilting the X axis.
If it's tilted at 90°, the buttons even go only in the same direction (either up, or down).

 
Well that's fun...

I can now confirm that in the test plugin when X is rotated.

ChatGPT says you need to project the forward vector onto the horizontal plane, effectively ignoring the vertical component. This works for me

C#:
void Left() => Move(Quaternion.AngleAxis(-90, Vector3.up) * ZeroY(_controller.control.forward));
void Right() => Move(Quaternion.AngleAxis(90, Vector3.up) * ZeroY(_controller.control.forward));

Vector3 ZeroY(Vector3 vector) => new Vector3(vector.x, 0, vector.z);

void Move(Vector3 motion) => _controller.MoveControl(_controller.control.position + motion * Time.deltaTime * 10);
 
This is indeed fixing the issue! why the fuck did I not think of zeroing out the Y vector? Nice catch!
I should think more often about ChatGPT, I never have the reflex to do so.

Thank you very much for your time everlaster <3 <3
 
Btw it would be correct to do new Vector3(vector.x, 0, vector.z).normalized to prevent shrinking the length when the y component is zeroed, since the forward vector itself is normalized.
 
Btw it would be correct to do new Vector3(vector.x, 0, vector.z).normalized to prevent shrinking the length when the y component is zeroed, since the forward vector itself is normalized.

Thank you! I wouldn't have thought of that : )
 
I'm late to the party I guess, but yeah, it's clear what was happening. You rotated the tilted forward vector around the static up vector, which forms an angle != 90 degrees with the forward vector in this case. So you are actually precessing the forward vector around the world up direction, leading to an up or down component in the result.
1731082363766.png
 
I'd skip the AngleAxis and just use Vector3.Cross(Vector3.up, forward).normalized for the left motion vector. This should be more performant as well.
 
Last edited:
I'd skip the AngleAxis and just use Vector3.Cross(Vector3.up, forward).normalized for the left motion vector. This should be more performant as well.

So, Vector3.Cross then negate to get the opposite direction I suppose?
 
So, Vector3.Cross then negate to get the opposite direction I suppose?
Yes.

Does this have to work for when the forward vector is rotated straight up or down? Because both solutions will fail in this case.
 
In case it does, I have to disappoint you. There is no way to decide what is left or right if you only have 2 collinear vectors to base your decision on. You have to rely on the other axis in this case.
 
Yes I was afraid of the potential "gimbal lock" situation :p

Technically yes. it should... but to be honest, having a shot where you're at "0" exactly pointing up or down is highly unlikely. That said, as I'm writing it, up definitely, but down could be a possibility (I made several top down shots in the past).

So all and all, if I want to handle that situation I should look at the rotation and do a conditional check on a straight up/down rotation I guess.
 
Yes. I'd use the right vector then. It is parallel to the world x-z-plane if z points up, so the behavior should be rather intuitive.
 
Np mate. Get back to me if there are still issues :)

Our gleam band plugin is almost ready btw. I'm just stuck with the issue that my approach to delaying the light movement is fps dependent. And adjusting it every frame is too expensive for my taste.
 
Ho nice! Can't wait to see this : )

Funny thing: I was tweaking the rotation implementation through the UI for the camera. And realized that VAM has a native bug. If you completely zero out the camera rotation (0,0,0), and you simply want to do a +45° on the X axis, it works up until the third click on the +45. At the fourth click, it flips back to a 90,0,0 vector. And you can never pass this threshold with the UI buttons.

The threshold changes depending on the button clicked. It gets shorter depending on the value you're clicking ( +0.5 / +5 / +45 ). The .5 even "gimbal locks" between 89.5 and 90 and you see the Y and Z axis flipping between 0 and 180°.

I'm suddenly less ashamed to struggle with vector shits if meshed does too lol ( well probably not struggle in the case of meshed but at least did a buggy booboo :p )
 
Back
Top Bottom