2
\$\begingroup\$

First some background info...

I have been working on a platformer game, which I draw with OpenGL. The platforms are cubes and the player is a cube.

The platforms and the player (both cubes) are given a position, from which the vertices should be drawn. However, the first cube is at position [0, 0, 0] and I would like the player to be on top of this cube. The size of the cubes and player is [0.5, 0.5, 0.5] initially.

However, I didn't manage to get the player on [0, 1, 0] (cubes are drawn from their center point I remembered), because the scaling didn't seem to work, which led me to believe the method I'm using to store the translations and scaling is inherently bad.


I am currently storing the translations and scaling in a matrix, which is part of the object. The object also holds the vertices and the VBO. Let's call it class Cube, which thus holds glm::mat4 m_transform.

I expose m_transform and pass it with glUniformMatrix4fv(shader.GetUniformLocation("model"), 1, GL_FALSE, glm::value_ptr(m_transform));

And at some point I call glDrawArrays(GL_TRIANGLES, 0, 36); to draw the platform/player cube.

So to alter the position of such a cube, I would alter m_transform. Such as: m_transform = glm::translate(m_transform, vec); where glm::vec3 vec is the desired translation to apply.

However, the issues arise when u wish to scale a cube as well, so if we scale with vec3(0, 2, 0), the translations will be twice as large. And I'm unsure where to go from here.


I've read that having different matrices for translation, rotation and scaling is the way to go, which I will try, however, I would like to know what the best practices are surrounding this subject.

Any suggestions are much appreciated!

\$\endgroup\$
1
\$\begingroup\$

With this shader, you have to pass a single model matrix, model, which is the final object transformation:

glUniformMatrix4fv(shader.GetUniformLocation("model"), 1, GL_FALSE, glm::value_ptr(m_transform));

But you still can have three different matrices, one for each transformation: translation, rotation and scale, and pass a matrix that is the product of those three transformations.

The thing to remember here is: order does matter. Because as you said, if you first translate an object, and then scale it, the translation shall be scaled, and your object won't be on wanted position.

This is why transformations are generally computed in that order:

glm::mat4 translation = glm::translate(glm::mat4(1.0f), position); // Translation matrix
glm::mat4 rotation = glm::toMat4(orientation); // Rotation matrix
glm::mat4 scale = glm::scale(glm::mat4(1.0f), scaleVector); // Scale matrix

m_transformation = trans * rot * scale; // Final transformation matrix.

See this related answer for more about transformations order.

\$\endgroup\$
  • \$\begingroup\$ To keep track of the size and position, is it best to simply do return m_translation[3] for the position and return glm::vec3(m_scale[0].x, m_scale[1].y, m_scale[2].z) for the size or have glm::vec3 m_position and update it when translating like so m_position += position and when requested, do return m_position instead. Or is there perhaps a better way? \$\endgroup\$ – Byrk Jan 24 '17 at 13:49
  • \$\begingroup\$ m_translation should be the difference between an object's position and world origin. As World origin coordinates are (0, 0, 0), m_translation does represent your object's position. So you can return it directly. \$\endgroup\$ – Aracthor Jan 25 '17 at 13:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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