Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly move the camera in the direction it's facing

I'm trying to figure out how to make the camera in directx move based on the direction it's facing.

Right now the way I move the camera is by passing the camera's current position and rotation to a class called PositionClass. PositionClass takes keyboard input from another class called InputClass and then updates the position and rotation values for the camera, which is then passed back to the camera class.

I've written some code that seems to work great for me, using the cameras pitch and yaw I'm able to get it to go in the direction I've pointed the camera.

However, when the camera is looking straight up (pitch=90) or straight down (pitch=-90), it still changes the cameras X and Z position (depending on the yaw).

The expected behavior is while looking straight up or down it will only move along the Y axis, not along the X or Z axis.

Here's the code that calculates the new camera position

void PositionClass::MoveForward(bool keydown)
{
float radiansY, radiansX;


// Update the forward speed movement based on the frame time
// and whether the user is holding the key down or not.
if(keydown)
{
    m_forwardSpeed += m_frameTime * m_acceleration;

    if(m_forwardSpeed > (m_frameTime * m_maxSpeed))
    {
        m_forwardSpeed = m_frameTime * m_maxSpeed;
    }
}
else
{
    m_forwardSpeed -= m_frameTime * m_friction;

    if(m_forwardSpeed < 0.0f)                                                               
    {
        m_forwardSpeed = 0.0f;
    }
}

// ToRadians() just multiplies degrees by 0.0174532925f
radiansY = ToRadians(m_rotationY); //yaw
radiansX = ToRadians(m_rotationX); //pitch

// Update the position.
m_positionX += sinf(radiansY) * m_forwardSpeed;
m_positionY += -sinf(radiansX) * m_forwardSpeed;
m_positionZ += cosf(radiansY) * m_forwardSpeed;

return;
 }

The significant portion is where the position is updated at the end.

So far I've only been able to deduce that I have horrible math skills.

So, can anyone help me with this dilemma? I've created a fiddle to help test out the math.

Edit: The fiddle uses the same math I used in my MoveForward function, if you set pitch to 90 you can see that the Z axis is still being modified

like image 569
Andy Avatar asked Dec 26 '22 05:12

Andy


2 Answers

Thanks to Chaosed0's answer, I was able to figure out the correct formula to calculate movement in a specific direction.

The fixed code below is basically the same as above but now simplified and expanded to make it easier to understand.


First we determine the amount by which the camera will move, in my case this was m_forwardSpeed, but here I will define it as offset.

float offset = 1.0f;

Next you will need to get the camera's X and Y rotation values (in degrees!)

float pitch = camera_rotationX;
float yaw   = camera_rotationY;

Then we convert those values into radians

float pitchRadian = pitch * (PI / 180); // X rotation
float yawRadian   = yaw   * (PI / 180); // Y rotation

Now here is where we determine the new position:

float newPosX = offset *  sinf( yawRadian ) * cosf( pitchRadian );
float newPosY = offset * -sinf( pitchRadian );
float newPosZ = offset *  cosf( yawRadian ) * cosf( pitchRadian );

Notice that we only multiply the X and Z positions by the cosine of pitchRadian, this is to negate the direction and offset of your camera's yaw when it's looking straight up (90) or straight down (-90).

And finally, you need to tell your camera the new position, which I won't cover because it largely depends on how you've implemented your camera. Apparently doing it this way is out of the norm, and possibly inefficient. However, as Chaosed0 said, it's what makes the most sense to me!

like image 89
Andy Avatar answered Jan 25 '23 02:01

Andy


To be honest, I'm not entirely sure I understand your code, so let me try to provide a different perspective.

The way I like to think about this problem is in spherical coordinates, basically just polar in 3D. Spherical coordinates are defined by three numbers: a radius and two angles. One of the angles is yaw, and the other should be pitch, assuming you have no roll (I believe there's a way to get phi if you have roll, but I can't think of how currently). In conventional mathematics notation, theta is your yaw and phi is your pitch, with radius being your move speed, as shown below.

Spherical coordinates

Note that phi and theta are defined differently, depending on where you look.

Basically, the problem is to obtain a point m_forwardSpeed away from your camera, with the right pitch and yaw. To do this, we set the "origin" to your camera position, obtain a spherical coordinate, convert it to cartesian, and then add it to your camera position:

float radius = m_forwardSpeed;
float theta = m_rotationY;
float phi = m_rotationX

//These equations are from the wikipedia page, linked above
float xMove = radius*sinf(phi)*cosf(theta);
float yMove = radius*sinf(phi)*sinf(theta);
float zMove = radius*cosf(phi);

m_positionX += xMove;
m_positionY += yMove;
m_positionZ += zMove;

Of course, you can condense a lot of this code, but I expanded it for clarity.

You can think about this like drawing a sphere around your camera. Each of the points on the sphere is a potential position in the next timestep, depending on the camera's rotation.

This is probably not the most efficient way to do it, but in my opinion it's certainly the easiest way to think about it. It actually looks like this is nearly exactly what you're trying to do in your code, but the operations on the angles are just a little bit off.

like image 41
Chaosed0 Avatar answered Jan 25 '23 02:01

Chaosed0