R3nzSkin

您所在的位置:网站首页 r3nzskin官网 R3nzSkin

R3nzSkin

2023-05-06 09:15| 来源: 网络整理| 查看: 265

I'm currently attempting to create a first-person space flight camera.

First, allow me to define what I mean by that.

Notice that I am currently using Row-Major matrices in my math library (meaning, the basis vectors in my 4x4 matrices are laid out in rows, and the affine translation part is in the fourth row). Hopefully this helps clarify the order in which I multiply my matrices.

What I have so Far

So far, I have successfully implemented a simple first-person camera view. The code for this is as follows:

fn fps_camera(&mut self) -> beagle_math::Mat4 { let pitch_matrix = beagle_math::Mat4::rotate_x(self.pitch_in_radians); let yaw_matrix = beagle_math::Mat4::rotate_y(self.yaw_in_radians); let view_matrix = yaw_matrix.get_transposed().mul(&pitch_matrix.get_transposed()); let translate_matrix = beagle_math::Mat4::translate(&self.position.mul(-1.0)); translate_matrix.mul(&view_matrix) }

This works as expected. I am able to walk around and look around with the mouse.

What I am Attempting to do

However, an obvious limitation of this implementation is that since pitch and yaw is always defined relative to a global "up" direction, the moment I pitch more than 90 degrees, getting the world to essentially being upside-down, my yaw movement is inverted.

What I would like to attempt to implement is what could be seen more as a first-person "space flight" camera. That is, no matter what your current orientation is, pitching up and down with the mouse will always translate into up and down in the game, relative to your current orientation. And yawing left and right with your mouse will always translate into a left and right direction, relative to your current orientation.

Unfortunately, this problem has got me stuck for days now. Bear with me, as I am new to the field of linear algebra and matrix transformations. So I must be misunderstanding or overlooking something fundamental. What I've implemented so far might thus look... stupid and naive :) Probably because it is.

What I've Tried so far

The way that I always end up coming back to thinking about this problem is to basically redefine the world's orientation every frame. That is, in a frame, you translate, pitch, and yaw the world coordinate space using your view matrix. You then somehow redefine this orientation as being the new default or zero-rotation. By doing this, you can then, in your next frame apply new pitch and yaw rotations based on this new default orientation, which (by my thinking, anyways), would mean that mouse movement will always translate directly to up, down, left, and right, no matter how you are oriented, because you are basically always redefining the world coordinate space in terms relative to what your previous orientation was, as opposed to the simple first-person camera, which always starts from the same initial coordinate space.

The latest code I have which attempts to implement my idea is as follows:

fn space_camera(&mut self) -> beagle_math::Mat4 { let previous_pitch_matrix = beagle_math::Mat4::rotate_x(self.previous_pitch); let previous_yaw_matrix = beagle_math::Mat4::rotate_y(self.previous_yaw); let previous_view_matrix = previous_yaw_matrix.get_transposed().mul(&previous_pitch_matrix.get_transposed()); let pitch_matrix = beagle_math::Mat4::rotate_x(self.pitch_in_radians); let yaw_matrix = beagle_math::Mat4::rotate_y(self.yaw_in_radians); let view_matrix = yaw_matrix.get_transposed().mul(&pitch_matrix.get_transposed()); let translate_matrix = beagle_math::Mat4::translate(&self.position.mul(-1.0)); // SAVES self.previous_pitch += self.pitch_in_radians; self.previous_yaw += self.yaw_in_radians; // RESETS self.pitch_in_radians = 0.0; self.yaw_in_radians = 0.0; translate_matrix.mul(&(previous_view_matrix.mul(&view_matrix))) }

This, however, does nothing to solve the issue. It actually gives the exact same result and problem as the fps camera.

My thinking behind this code is basically: Always keep track of an accumulated pitch and yaw (in the code that is the previous_pitch and previous_yaw) based on deltas each frame. The deltas are pitch_in_radians and pitch_in_yaw, as they are always reset each frame.

I then start off by constructing a view matrix that would represent how the world was orientated previously, that is the previous_view_matrix. I then construct a new view matrix based on the deltas of this frame, that is the view_matrix.

I then attempt to do a view matrix that does this:

Translate the world in the opposite direction of what represents the camera's current position. Nothing is different here from the FPS camera. Orient that world according to what my orientation has been so far (using the previous_view_matrix. What I would want this to represent is the default starting point for the deltas of my current frame's movement. Apply the deltas of the current frame using the current view matrix, represented by view_matrix

My hope was that in step 3, the previous orientation would be seen as a starting point for a new rotation. That if the world was upside-down in the previous orientation, the view_matrix would apply a yaw in terms of the camera's "up", which would then avoid the problem of inverted controls.

I must surely be either attacking the problem from the wrong angle, or misunderstanding essential parts of matrix multiplication with rotations.

Can anyone help pin-point where I'm going wrong?

[EDIT] - Rolling even when you only pitch and yaw the camera

For anyone just stumbling upon this, I fixed it by a combination of the marked answer and Locke's answer (ultimately, in the example given in my question, I also messed up the matrix multiplication order).

Additionally, when you get your camera right, you may stumble upon the odd side-effect that holding the camera stationary, and just pitching and yawing it about (such as moving your mouse around in a circle), will result in your world slowly rolling as well.

This is not a mistake, this is how rotations work in 3D. Kevin added a comment in his answer that explains it, and additionally, I also found this GameDev Stack Exchange answer explaining it in further detail.



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3