0
\$\begingroup\$

I have been trying to figure this out for a while now, and can't seem to get a working method. I am building a space ship movement with the following movement keys:

P = accelerate (move forward)

A = yaw left

D = yaw right

W = pitch down

S = pitch up

The following the code I have to perform the movements for keys A,D,W and S. They all work as expected. I just can't figure out how to move forward at the angle the space ship is.

void Player::yawRight(float deltaTime)
{
    this->yaw -= this->rotationAngle * deltaTime;

    if (this->yaw < 0.0f) {
        this->yaw = 360.0f;
    }

    cout << "yawRight: " + to_string(this->yaw) << endl;

    this->yawQuat = glm::angleAxis(glm::radians(this->yaw), glm::vec3(0, 1, 0));
    this->pitchQuat = glm::angleAxis(glm::radians(this->pitch), glm::vec3(0, 0, 1));
    this->rollQuat = glm::angleAxis(glm::radians(this->roll), glm::vec3(0, 0, 1));

    glm::mat4 rotationMatrix = glm::toMat4(glm::normalize(this->yawQuat * this->pitchQuat * this->rollQuat));

    this->model = glm::mat4(1.0f);
    this->model = glm::translate(this->model, this->position) * rotationMatrix;
}

void Player::yawLeft(float deltaTime)
{
    this->yaw += this->rotationAngle * deltaTime;

    if (this->yaw > 360.0f) {
        this->yaw = 0.0f;
    }

    cout << "yawLeft: " + to_string(this->yaw) << endl;

    this->yawQuat = glm::angleAxis(glm::radians(this->yaw), glm::vec3(0, 1, 0));
    this->pitchQuat = glm::angleAxis(glm::radians(this->pitch), glm::vec3(0, 0, 1));
    this->rollQuat = glm::angleAxis(glm::radians(this->roll), glm::vec3(0, 0, 1));

    glm::mat4 rotationMatrix = glm::toMat4(glm::normalize(this->yawQuat * this->pitchQuat * this->rollQuat));

    this->model = glm::mat4(1.0f);
    this->model = glm::translate(this->model, this->position) * rotationMatrix;
}

void Player::pitchDown(float deltaTime)
{
    this->pitch += this->rotationAngle * deltaTime;

    if (this->pitch > 360.0f) {
        this->pitch = 0.0f;
    }

    cout << "pitchDown: " + to_string(this->pitch) << endl;

    this->yawQuat = glm::angleAxis(glm::radians(this->yaw), glm::vec3(0, 1, 0));
    this->pitchQuat = glm::angleAxis(glm::radians(this->pitch), glm::vec3(0, 0, 1));
    this->rollQuat = glm::angleAxis(glm::radians(this->roll), glm::vec3(0, 0, 1));

    glm::mat4 rotationMatrix = glm::toMat4(glm::normalize(this->yawQuat * this->pitchQuat * this->rollQuat));

    this->model = glm::mat4(1.0f);
    this->model = glm::translate(this->model, this->position) * rotationMatrix;
}

void Player::pitchUp(float deltaTime)
{
    this->pitch -= this->rotationAngle * deltaTime;

    if (this->pitch < 0.0f) {
        this->pitch = 360.0f;
    }

    cout << "pitchDown: " + to_string(this->pitch) << endl;

    this->yawQuat = glm::angleAxis(glm::radians(this->yaw), glm::vec3(0, 1, 0));
    this->pitchQuat = glm::angleAxis(glm::radians(this->pitch), glm::vec3(0, 0, 1));
    this->rollQuat = glm::angleAxis(glm::radians(this->roll), glm::vec3(0, 0, 1));

    glm::mat4 rotationMatrix = glm::toMat4(glm::normalize(this->yawQuat * this->pitchQuat * this->rollQuat));

    this->model = glm::mat4(1.0f);
    this->model = glm::translate(this->model, this->position) * rotationMatrix;
}


void Player::accelerate(float deltaTime)
{
    float x = cos(glm::radians(this->yaw)) * cos(glm::radians(this->pitch));
    float y = sin(glm::radians(this->pitch));
    float z = sin(glm::radians(this->yaw)) * cos(glm::radians(this->pitch));

    glm::vec3 front = glm::vec3(x,y,z);
    front = glm::normalize(front);
    glm::vec3 right = glm::normalize(glm::cross(front, glm::vec3(0, 1, 0)));

    glm::mat4 rotationMatrix = glm::toMat4(glm::normalize(this->yawQuat * this->pitchQuat * this->rollQuat));

    this->position += front * 0.01f;

    this->model = glm::mat4(1.0f);
    this->model = glm::translate(this->model, this->position) * rotationMatrix;
}

void Player::accelerate(float deltaTime)
{
    // get the forward vector
    float x = cos(glm::radians(this->yaw)) * cos(glm::radians(this->pitch));
    float y = sin(glm::radians(this->pitch));
    float z = sin(glm::radians(this->yaw)) * cos(glm::radians(this->pitch));

    glm::vec3 front = glm::vec3(x,y,z);
    front = glm::normalize(front);

    glm::mat4 rotationMatrix = glm::toMat4(glm::normalize(this->yawQuat * this->pitchQuat * this->rollQuat));

    // update the position
    // this is incorrect
    this->position += front * 0.01f;

    this->model = glm::mat4(1.0f);
    this->model = glm::translate(this->model, this->position) * rotationMatrix;
}

Note: the actual code is crappy as it has a lot of reptition, I will fix that.

For the accelerate() method I get the forwad vector from the yaw and pitch, but it doesn't move in the right direction. Can someone provide me a guide or an explanation as to how I can make the ship move forward in the orientation it current is in? Thanks!

\$\endgroup\$
  • \$\begingroup\$ Can you show us some example cases, indicating the direction you expect the object to move, versus the direction it actually moves? By comparing the relationship between the right & wrong output, we can often deduce a pattern to the symptoms that helps track down the root cause. \$\endgroup\$ – DMGregory Dec 4 '18 at 12:42
2
\$\begingroup\$

I'm not sure if this question is actually about quaternions or about orienting an object in 3D space via Euler angles. It seems your main concern is object orientation, so that is what I'll focus on in this answer.

For the sake of this answer:
x-axis rotation: pitch
y-axis rotation: yaw
z-axis rotation: roll

//orient the game object in 3D space and move it (pseudo-code)
void MoveGameObject(float xMove, float yMove)
{
    //add the move amount for this frame to the rotation angles
    gYaw += xMove;
    gPitch += yMove;

    //make sure: 90 > pitch > -90
    if(gPitch < -90.0f)
    {
        gPitch = -90.0f;
    }
    else if(gPitch > 90.0f)
    {
        gPitch = 90.0f;
    }

    //convert: degrees->radians
    float yawRad = gYaw * (3.14 / 180.0f);
    float pitchRad = gPitch * (3.14 / 180.0f);

    //convert orientation to spherical coordinates
    Vector3 tar;
    tar.x = cos(yawRad) * cos(pitchRad);
    tar.y = sin(pitchRad);
    tar.z = sin(yawRad) * cos(pitchRad);
    tar.normalize();

    //move forward
    if(direction == FORWARD)
    {
        position += tar * speed;
    }
    //move back
    if(direction == BACK)
    {
        position -= tar * speed;
    }
    //move left
    if (direction == LEFT)
    {
        Vector3 leftVector = tar;
        leftVector = leftVec.crossproduct(0, 1, 0);
        leftVector.normalize();
        position -= leftVector * speed;
    }
    //move right
    if(direction == RIGHT)
    {
        Vector3 rightVector = tar;
        rightVector = rightVector.crossproduct(0, 1, 0);
        rightVector.normalize();
        position += rightVector * speed;
    }
}

This code will move your object in the correct direction based on its orientation.
An excellent tutorial on this sort of thing.

\$\endgroup\$
  • \$\begingroup\$ You probably don't need to normalize tar - it's unit length by construction, to within floating point precision. ;) \$\endgroup\$ – DMGregory Dec 4 '18 at 14:04
0
\$\begingroup\$

The most common problem for beginners, is the multiplication order of the rotational matrices, and determine what coordinate system is used left/right handed, and whether axis-Y is up or forward etc. You'll need to know exact understanding what being used, and what your math will result into.

\$\endgroup\$
  • \$\begingroup\$ This looks more like a comment, and doesn't appear to offer a solution for how to move an object along its local forward vector after rotating it. Can you edit your answer to elaborate? \$\endgroup\$ – DMGregory Dec 4 '18 at 12:40

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.