Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL multiple matrix transormations

I have simple vertex shader for models

#version 330

layout(location = 0) in vec3 VertexPosition;
layout(location = 1) in vec3 VertexNormal;
layout(location = 2) in vec2 VertexUV;

out VS_GS_VERTEX
{
    vec3 vs_worldpos;
    vec3 vs_normal;
    vec2 VertexUV;
} vertex_out;

uniform mat4 modelMatrix;
uniform mat4 projectionMatrix;
uniform mat4 lookAtMatrix;

void main(void)
{
    mat4 MVP = projectionMatrix * lookAtMatrix * modelMatrix;

    gl_Position = MVP * vec4(VertexPosition, 1.0);
    gl_Normal = mat3(modelMatrix) * VertexNormal;

    vertex_out.vs_worldpos = gl_Position.xyz;
    vertex_out.vs_normal = gl_Normal;
    vertex_out.VertexUV = VertexUV;
}

and I pass there modelMatrix

  modelMat := MatrixMultiply(transMat, baseMat);
  modelMat := MatrixMultiply(modelMat, scaleMat);
  modelMat := MatrixMultiply(modelMat, rotMat);
  glUniformMatrix4fv(modelMatrix_loc, 1, false, @modelMat);

where transMat for positioning, scaleMat to enlarge whole picture and rotMat to rotate whole terrain. without scale Everything fine while baseMat is coordinates of model on terrain

baseMat := CreateTranslationMatrix(AffineVectorMake(pos.x, pos.y, pos.z));

but when I trying also to enlarge model by own model's scale (model have zero based coordinates, for example roots of tree at (0, 0, 0))

  scMat := CreateScaleMatrix(AffineVectorMake(scale, scale, scale));
  trMat := CreateTranslationMatrix(AffineVectorMake(pos.x, pos.y, pos.z));

  baseMat := MatrixMultiply(scMat, trMat);

with model's scale

models not just enlarged, they also changing coordinates and not placed on terrain anymore. Is it possible to make one model matrix with model's scaling, rotation, translation, yet another translation, scaling and rotation? Or I should do something else? Matrix math from GLScene and seems works fine.

Edit: I can't use proper order with matrices by scaling first because I have this

scaling imagescaling more
The structure of terrain is tiles of 64x64 chunks, each have base coordinates. So to put it together I need first to translate each chunk to proper position and only then scale to enlarge image and rotate with mouse. Each model also have absolute position assigned to terrain. I should scale and rotate model (own model's modifiers) and put it to proper position on terrain. transMat (to put tiles and models at the center of screen), scaleMat and rotMat shared for both terrain and models. But local scMat and trMat are for enlarge model and put it to right place.

If I leave terrain working as is with rotMat * scaleMat * transMat but using models as rotMat * transMat * trMat * scaleMat * scMat I have this models
a bit closer
1 meter closer

Edit2: changed vertex shader to

uniform mat4 modelMatrix;
uniform mat4 MVP;

void main(void)
{
    vec4 modelPos = modelMatrix * vec4(VertexPosition, 1.0);
    gl_Position = MVP * modelPos;
    gl_Normal = mat3(modelMatrix) * VertexNormal;

    vertex_out.vs_worldpos = gl_Position.xyz;
    vertex_out.vs_normal = gl_Normal;
    vertex_out.VertexUV = VertexUV;
}

and passed

modelMatrix = modelRotMat * modelScaleMat;
mvpMatrix = projMat * lookAtMat * rotMat * scaleMat * modelTransMat * transNat;

now it works as expected, thanks for help.

like image 767
user2091150 Avatar asked Sep 19 '13 15:09

user2091150


People also ask

What is OpenGL transformation matrix?

The matrix M, that contains every translations, rotations or scaling, applied to an object is named the model matrix in OpenGL. Basically, instead of sending down the OpenGL pipeline two, or more, geometrical transformation matrices we'll send a single matrix for efficiency.

Can a 3x3 matrix be used to perform a 3D translation?

All linear transformations map the origin of the domain to the origin of the range. Therefore 3x3 matrices cannot perform translation on 3D vectors since the origin in one space cannot be mapped to anything but the origin on another using linear maps.

How do I transform in OpenGL?

Formula: X = x + tx Y = y + ty where tx and ty are translation coordinates The OpenGL function is glTranslatef( tx, ty, tz );


1 Answers

You have to apply the scaling before the translation. The right order in which to apply matrices is

FinalMatrix = TranslationMatrix * RotationMatrix * ScaleMatrix;

(you may switch rotation and translation in specific cases, depending on what you want to rotate, but generally will be like this) So, if you want to combine more of them, you'll have to do it this way;

FinalMatrix = TranslationMatrix1 *TranslationMatrix2* RotationMatrix1 * RotationMatrix2 * ScaleMatrix1*ScaleMatrix2;

EDIT

So, you have models with a base position rotation and scale on your terrain. And you want to add other transforms to them from time to time. You'll need a lot of matrices. From the base coordinates on the terrain of you models, calculate TranslationMatrix2. Your CreateTranslationMatrix(AffineVectorMake(pos.x, pos.y, pos.z)) should be fine. The basic scale and rotation of your model on the terrain should also be in RotationMatrix2 and ScaleMatrix2. These three matrix hold the base scale position and orientation of each of your models on the terrain. Your final model matrix will be

ModelMatrix =  TranslationMatrix2 *RotationMatrix2 * ScaleMatrix2;

When you want to scale them or move them from that position, you can combine new transformations with those, with the formula. Let's say you want to apply a second scale, and new rotation and a new translation, whose matrices are ScaleMatrix1,RotationMatrix1, and TranslationMatrix1. Your final model matrix will be:

ModelMatrix =  TranslationMatrix1 *TranslationMatrix2*RotationMatrix1 * RotationMatrix2 * ScaleMatrix1*ScaleMatrix2;

EDIT2

If you want to keep that structure of your terrain, I think you have to scale the position of the models with the scale matrix used for the terrain. Then, from that position, compute the translation matrix of your model. Use the shared rotation matrix, and the model's own scale, like this

pos = scaleMat * pos;
trMat = CreateTranslationMatrix(AffineVectorMake(pos.x, pos.y, pos.z));
ModelMatrix = SharedRotation* scMat * trMat ;
like image 164
darius Avatar answered Nov 13 '22 07:11

darius