microsoft / DirectXTK

The DirectX Tool Kit (aka DirectXTK) is a collection of helper classes for writing DirectX 11.x code in C++
https://walbourn.github.io/directxtk/
MIT License
2.54k stars 506 forks source link

Keyboard and mouse uses inconsistent coordinate systems, resulting in incorrect movement #447

Open jkinz3 opened 4 months ago

jkinz3 commented 4 months ago

If you follow the keyboard and mouse tutorial and implement a basic first person camera, the movement is incorrect. move

In this provided GIF, you can see that as i'm looking down while pressing E to move up (locally), it begins to move be down (locally). And when I press W to move forward (locally) it moves me backwards (locally). I narrowed it down to the trigonometry calculations used to create the lookAt vector. It appears to assume that forward is +Z. This is inconsistent with the quaternion transform function used to rotate the input vector, which follows SimpleMaths convention of forward being -Z. Looks like that tutorial needs the trig calculations rewritten and unfortunately i'm not mathy enough to know what needs to be changed and submit a pull request for it.

walbourn commented 4 months ago

Standard modern math notation uses row-major matrices, column vectors, post-multiplication, and right-handed coordinates.

OpenGL uses column-major matrices, column vectors, post-multiplication, and right-handed viewing coordinates, where -Z is 'forward'.

DirectXMath (the underlying library used by SimpleMath) uses row-major matrices, row vectors, pre-multiplication, and left-handed viewing coordinates consistent with classic "DirectX" math setup. In this case +Z is 'forward' into the screen.

Note the DirectXMath library provides both LH and RH versions of handed matrix functions so it can actually support either style.

SimpleMath uses row-major matrices, row vectors, pre-multiplication, and right-handed viewing coordinates consistent with XNA Game Studio.

And just to be fun, the HLSL compiler default is to use column-major layout, but you can opt into row-major.

You may find this blog post helpful to read.

With that out of the way, the keyboard & mouse tutorial lesson uses a "WASD" style control scheme for the XY plane, and Spacebar/X for the Z movement. Traditionally "E" and "Q" in the WASD scheme are used for rotation or look left/right, so don't really follow how you implemented your controls.

jkinz3 commented 4 months ago

I understand the difference between row major and column major (although pre and post multiplication was a new one). And I know the actual bindings are that of taste. Probably didn't need to comment on them. My bad lol. My point was simply that there are basically two methods being used to generate the local forward vector. One uses a quaternion to transform users forward input, the other uses raw trig. Both yield different and opposing results as the pitch changes. The result is that when the camera points down almost at all and presses forward, they move backwards because the math says their forward vector is the opposite of the vector used for the lookAt vector.
Are you saying this is expected behavior? If so, then disregard. But imho, anyone coming into this tutorial series would get very confused as to why they're moving the opposite direction of the key they're pressing.

walbourn commented 4 months ago

Are you using the 'orbit style' or the 'free camera' style?

jkinz3 commented 4 months ago

I'm using the free camera.

walbourn commented 2 weeks ago

From your description, it sounds like you have different keyboard controls than the tutorial which is:

if (kb.Up || kb.W)
    move.y += 1.f;

if (kb.Down || kb.S)
    move.y -= 1.f;

if (kb.Left || kb.A)
    move.x += 1.f;

if (kb.Right || kb.D)
    move.x -= 1.f;

if (kb.PageUp || kb.Space)
    move.z += 1.f;

if (kb.PageDown || kb.X)
    move.z -= 1.f;

What code are you actually using?

jkinz3 commented 2 weeks ago

Yeah so I had remapped the controls to be WASD but the issue still applies with the original code. Here's a gif with the exact same controls as the tutorial (and your reply by extension). I mov e forward using Space, then look straight down, then hold Space. Instead of moving forward, it moves me backward, meaning the lookAt vector is transformed differently than the Move vector. That's because the lookAt vector is being calculated assuming +Z is forward but the Quaternion class that is apart of SimpleMatch assumes -Z is forward, aligning with the XNA framework. I hope this helps. Let me know if you have any other questions

nautilus

walbourn commented 2 weeks ago

SimpleMath uses "right-handed" coordinate systems which is why +Z is 'into' the scene. That is also why in the tutorial I was using XMMatrixLookAtRH rather than XMMatrixLookAtLH.

When I'm using the "not orbit" style camera, Page Up pulls you in 'closer' and Page Down makes you 'further' as I would expect. Of course, that is 'relative' to the view location because it's intended to be an "FPS" style camera.

I did notice in the Orbit style, it would make sense to use m_radius -= move.z; instead to get the same 'closer' / 'further' behavior so I'll update the tutorial to note that.

jkinz3 commented 2 weeks ago

Apologies but I think you misremembered it. Left-handed coordinate systems have +Z going forward (into the scene) and Right-handed means -Z is forward (into the scene). SimpleMath defines a Forward constant as const Vector3 Vector3::Forward = { 0.f, 0.f, -1.f };

Regardless, the main issue is that in the non orbit style of movement in the tutorial, if you look down, pressing forward (either Space or Page Up) doesn't pull you in 'closer', it makes you further away. In the GIF I previously posted, you can see that i'm pressing Page Up and it's moving me away from the cup model.

walbourn commented 2 weeks ago

I just tried out the test apps I used for the tutorial which are on GitHub and the behavior is as I described it. I wonder if there is some difference in the code in the markdown and the code in the test app?

Right on the +Z/-Z. Dealing with both handedness can be confusing for sure.

jkinz3 commented 2 weeks ago

So you’re saying that in your test app, you look down, then press Page Up, and you don’t move backwards? Next time I’m on my computer I can check it out too. Bizarre

On Fri, Aug 16, 2024 at 3:27 PM Chuck Walbourn @.***> wrote:

I just tried out the test apps I used for the tutorial which are on GitHub https://github.com/walbourn/directxtk-tutorials and the behavior is as I described it. I wonder if there is some difference in the code in the markdown and the code in the test app?

Right on the +Z/-Z. Dealing with both handedness can be confusing for sure.

— Reply to this email directly, view it on GitHub https://github.com/microsoft/DirectXTK/issues/447#issuecomment-2294187329, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABQG6QP6GBNROWQR4UDMFHLZRZODZAVCNFSM6AAAAABHASUZYKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEOJUGE4DOMZSHE . You are receiving this because you authored the thread.Message ID: @.***>

walbourn commented 2 weeks ago

Ah, I see now. Let me do some digging.