0

I have a model I'm trying to move through the air in OpenGL with GLSL and, ultimately, have it spin as it flies. I started off just trying to do a static rotation. Here's an example of the result:

image

The gray track at the bottom is on the floor. The little white blocks all over the place represent an explosion chunk model and are supposed to shoot up and bounce on the floor.

Without rotation, if the model matrix is just an identity, everything works perfectly.

When introducing rotation, it looks they move based on their rotation. That means that some of them, when coming to a stop, rest in the air instead of the floor. (That slightly flatter white block on the gray line next to the red square is not the same as the other little ones. Placeholders!)

I'm using glm for all the math. Here are the relevant lines of code, in order of execution. This particular model is rendered instanced so each entity's position and model matrix get uploaded through the uniform buffer.

Object creation:

// should result in a model rotated along the Y axis
auto quat = glm::normalize(glm::angleAxis(RandomAngle, glm::vec3(0.0, 1.0, 0.0))); 
myModelMatrix = glm::toMat4(quat);

Vertex shader:

struct Instance
{
    vec4 position;
    mat4 model;
};

layout(std140) uniform RenderInstances
{
    Instance instance[500];
} instances;

layout(location = 1) in vec4 modelPos;
layout(location = 2) in vec4 modelColor;
layout(location = 3) out vec4 fragColor;

void main()
{
    fragColor = vec4(modelColor.r, modelColor.g, modelColor.b, 1);
    vec4 pos = instances.instance[gl_InstanceID].position + modelPos;

    gl_Position = camera.projection * camera.view * instances.instance[gl_InstanceID].model * pos;
}

I don't know where I went wrong. I do know that if I make the model matrix do a simple translation, that works as expected, so at least the uniform buffer works. The camera is also a uniform buffer shared across all shaders, and that works fine. Any comments on the shader itself are also welcome. Learning!

Ross Lombardi
  • 95
  • 2
  • 7
  • You need to translate the center of rotation to position `(0,0,0)` then rotate and than translate back. Also there is a difference if you are rotating around object's local axises or world's ... see [Understanding 4x4 homogenous transform matrices](http://stackoverflow.com/a/28084380/2521214) especially bullet **#5** – Spektre Feb 07 '16 at 09:53
  • I know the basics of homogenous coordinates. Unless I am sorely mistaken, I don't have that problem. The model's local coordinates begin at 0, the box's center. It gets moved to a world position in the first two lines of the shader. If I do have that problem, it would help a lot if you could point it out because I can't see it. This is probably due to order of something but I don't know where. I suppose I should see what the complete transformation matrix looks like. If the origin column is not 0, I have problems. – Ross Lombardi Feb 07 '16 at 11:03
  • It isn't. Final row in the matrix has a w of over 100. More in the morning. Late. Bed. At one point I had the multiplication of view and model reversed. That did me no good. – Ross Lombardi Feb 07 '16 at 11:10
  • @Spektre, that doesn't help. A more detailed explanation would be nice. – Ross Lombardi Feb 07 '16 at 21:18

1 Answers1

0

The translation to each vertex's final destination is happening before the rotating. It was this that I didn't realize was happening, even though I know to do rotations before translations.

Here's the shader code:

void main()
{
    fragColor = vec4(modelColor.r, modelColor.g, modelColor.b, 1);
    vec4 pos = instances.instance[gl_InstanceID].position + modelPos;

    gl_Position = camera.projection * camera.view * instances.instance[gl_InstanceID].model * pos;
}

Due to the associative nature of matrix multiplication, this can also be:

gl_Position = (projection * (view * (model * pos)));

Even though the multiplication happens left to right, the transformations happen right to left.

This is the old code to generate the model matrix:

renderc.ModelMatrix = glm::toMat4(glm::normalize(animc.Rotation));

This will result in the rotation happening with the model not at the origin, due to the translation at the end of the gl_Position = line.

This is now the code that generates the model matrix:

renderc.ModelMatrix = glm::translate(pos);
renderc.ModelMatrix *= glm::toMat4(glm::normalize(animc.Rotation));
renderc.ModelMatrix *= glm::translate(-pos);

Translate to the origin (-pos), rotate, then translate back (+pos).

Ross Lombardi
  • 95
  • 2
  • 7