4
\$\begingroup\$

I am creating a graphical scene with OpenGL and SDL, and I'm running into a problem in regards to translating an object in its rotation direction.

Each of the graphical objects in the scene has a Transform object, which contains the object position, rotation, and scale. The following code in the Transform calculate the model for the object:

    inline glm::mat4 GetModel() const
    {
        glm::mat4 matx;
        matx = glm::translate(matx, m_translateV);
        matx = glm::rotate(matx, m_rotateV.x, glm::vec3(1.0, 0.0, 0.0));
        matx = glm::rotate(matx, m_rotateV.y, glm::vec3(0.0, 1.0, 0.0));
        matx = glm::rotate(matx, m_rotateV.z, glm::vec3(0.0, 0.0, 1.0));
        matx = glm::scale(matx, m_scaleV);

        return matx;
    }

Additionally it has getters which return a pointer to each vec3, so that I can modify it when I request it (not too important for my issue, just giving you a background).

    inline glm::vec3* GetPos() { return &m_translateV; }
    inline glm::vec3* GetRot() { return &m_rotateV; }
    inline glm::vec3* GetScale() { return &m_scaleV; }

The following code is called from my main game loop to process key inputs:

SDL_Event event;
std::shared_ptr<ENGINE::RenderObject> ro = m_renderer.GetRenderObject(0);
ENGINE::Transform t = ro->GetTransform();

if (SDL_PollEvent(&event))
{
    if (event.type == SDL_KEYDOWN)
    {
        if (event.key.keysym.sym == SDLK_ESCAPE)
        {
            m_gameState = GameState::EXIT;
        }
        if (event.key.keysym.sym == SDLK_w)
        {
            t.GetPos()->x -= glm::sin(glm::radians(t.GetRot()->y)) * 0.5;
            t.GetPos()->z -= glm::cos(glm::radians(t.GetRot()->y)) * 0.5;
        }
        if (event.key.keysym.sym == SDLK_s)
        {
            t.GetPos()->x += glm::sin(glm::radians(t.GetRot()->y)) * 0.5;
            t.GetPos()->z += glm::cos(glm::radians(t.GetRot()->y)) * 0.5;
        }
        if (event.key.keysym.sym == SDLK_a)
        {
            t.GetRot()->y += 0.1;
        }
        if (event.key.keysym.sym == SDLK_d)
        {
            t.GetRot()->y -= 0.1;
        }
    }
}

ro->SetTransform(t);

The problem I'm having is that even if I rotate my object, it keeps translating in the same direction (forward on the z-axis). The following two images should explain what I mean (the object of interest is the rotated one):

Image 1 : With rotation before translation (before pressing w): enter image description here

Image 2 : With rotation and translation: enter image description here

As you can see, even though I have rotated the object using a and d, when I press w or s to translate the object, it keeps translating in the same direction.

I have tried another case, where I create some rotation values, but I don't actually rotate the object. What happens in this case is that even though when I press a or d the object doesn't actually appear to rotate, however it will translate in the correct direction when I press w or s. The following is the code change that I tried:

if (SDL_PollEvent(&event))
{
    if (event.type == SDL_KEYDOWN)
    {
        if (event.key.keysym.sym == SDLK_ESCAPE)
        {
            m_gameState = GameState::EXIT;
        }
        if (event.key.keysym.sym == SDLK_w)
        {
            t.GetPos()->x -= glm::sin(glm::radians((float)direction)) * 0.5;
            t.GetPos()->z -= glm::cos(glm::radians((float)direction)) * 0.5;
        }
        if (event.key.keysym.sym == SDLK_s)
        {
            t.GetPos()->x += glm::sin(glm::radians((float)direction)) * 0.5;
            t.GetPos()->z += glm::cos(glm::radians((float)direction)) * 0.5;
        }
        if (event.key.keysym.sym == SDLK_a)
        {
            direction += 5; // new line
        }
        if (event.key.keysym.sym == SDLK_d)
        {
            direction -= 5; // new line
        }
    }
}

ro->SetTransform(t);

I can't seem to figure out why exactly the object doesn't translate in the correct direction when I apply rotation to it, but it does when I don't apply rotation and instead use some other value in the calculation for the x and z values. I am uploading the model matrix normally to the vertex shader.

Hope the question/issue is clear. I will provide any additional code if needed.

Thanks

\$\endgroup\$
1
  • \$\begingroup\$ Please shorten up your question by removing everything that is irrelevant. \$\endgroup\$
    – Kromster
    Feb 11, 2015 at 9:17

3 Answers 3

2
\$\begingroup\$

What are the effects of this:

inline glm::mat4 GetModel() const
{
    glm::mat4 matx;
    matx = glm::scale(matx, m_scaleV);
    matx = glm::rotate(matx, m_rotateV.x, glm::vec3(1.0, 0.0, 0.0));
    matx = glm::rotate(matx, m_rotateV.y, glm::vec3(0.0, 1.0, 0.0));
    matx = glm::rotate(matx, m_rotateV.z, glm::vec3(0.0, 0.0, 1.0));
    matx = glm::translate(matx, m_translateV);
    return matx;
}

(A little confused by the graphics; I may need to revise this when you reply)

I use XNA primarily and am not quite familiar enough to provide 100% code yet. That being said, to calculate character-forward, I would do something like this.

W:  t.GetPos() += ((0, 0, -1) * t.GetRot()); //Vector3.Forward * t.Rotation
S:  t.GetPos() += ((0, 0, +1) * t.GetRot()); //Vector3.Backward * t.Rotation
\$\endgroup\$
0
\$\begingroup\$

I am working on similar project right now and I think that you have two problems. First is that you compute direction in a wrong way. Try changing signs before sin and cos. For example:

if (event.key.keysym.sym == SDLK_w)
{
    t.GetPos()->x += glm::sin(glm::radians(t.GetRot()->y)) * 0.5;
    t.GetPos()->z -= glm::cos(glm::radians(t.GetRot()->y)) * 0.5;
    // or:
    // t.GetPos()->x -= glm::sin(glm::radians(t.GetRot()->y)) * 0.5;
    // t.GetPos()->z += glm::cos(glm::radians(t.GetRot()->y)) * 0.5;
}
if (event.key.keysym.sym == SDLK_s)
{
    t.GetPos()->x -= glm::sin(glm::radians(t.GetRot()->y)) * 0.5;
    t.GetPos()->z += glm::cos(glm::radians(t.GetRot()->y)) * 0.5;
    // or:
    // t.GetPos()->x += glm::sin(glm::radians(t.GetRot()->y)) * 0.5;
    // t.GetPos()->z -= glm::cos(glm::radians(t.GetRot()->y)) * 0.5;
}

Secondly, change the order of a model matrix rotation to

inline glm::mat4 GetModel() const
{
    glm::mat4 matx(1.0);
    matx = glm::translate(matx, m_translateV);
    matx = glm::rotate(matx, m_rotateV.z, glm::vec3(0.0, 0.0, 1.0));
    matx = glm::rotate(matx, m_rotateV.y, glm::vec3(0.0, 1.0, 0.0));
    matx = glm::rotate(matx, m_rotateV.x, glm::vec3(1.0, 0.0, 0.0));
    matx = glm::scale(matx, m_scaleV);

    return matx;
}

You can find here a good explanation of the order of matrices rotation.

\$\endgroup\$
1
  • \$\begingroup\$ Using + for both sin and cos makes sense here. This code is for translation in a particular direction. \$\endgroup\$
    – Thomas
    Oct 13, 2015 at 13:47
0
\$\begingroup\$

In 3d programming, the sooner you stop using angles to represent rotations, the easier 3d programming becomes. It's ok to use angles to rotate something, it just muddys the water when you use them to represent something's overall rotation.

So instead of resolving the direction to move something through rotation angles, try it through your transform's columns which represent the exact directions you want the object to go anyway.

Currently you can get position, rotation, and scale. It is easy to also get forward, backward, right, left, up, down too. These are the directions you are trying to calculate with your angles.

psuedo code:

//assuming you have a Y-up system:
Vec3 forward = (transform[2][0],transform[2][1],transform[2][2]);//column 3 of your transform. Possibly m8,m9,m10 of the transform in openGL
forward.Normalize();
Vec3 backwards = forwards * -1f;
//for right, it is column 1 of your transform
//for up, it is column 2 of your transform

//then simply update position using these vectors:
pos += forward * speed;//when w is keyed
pos += right * speed;//when d is keyed
Pos += backward * speed;//when s is keyed
//etc.

If you are trying to do this to a camera's view matrix, you must invert the view matrix and use that.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .