Translate and scale a rectangle with OpenGL 3+

I want to translate and scale a rectangle to specific coordinates. At this time I have to scale the rectangle only in the y plane. The translation works well, I have problems with the scaling, the rectangle is not placed at the right position. I tried to apply another solutions I found here and in another posts in stack overflow without success. This should be very easy, but I can’t find the solution. I become from my source the top, bottom, left and right coordinates. This is a part of the code. Vertex and Fragment Shader:

 vertexShaderSource = "#version 150 
"
"in vec2 aPos;
"
"in vec4 aColor;
"
"uniform mat4 projection;
"
"uniform mat4 model;
"
"uniform bool isLine;
"
"out vec4 oColor;
"
"void main() {
"
"   gl_Position =  projection *  model * vec4(aPos, 0.0, 1.0);
"
"   oColor = aColor;
"
"}
";
fragmentShaderSource = "#version 150 
"
"in vec4 oColor;
"
"out vec4 outColor; 
"
"void main() {
"
"     outColor = oColor;
"
"}
"; 

Vertices:


GLfloat vertices[] = {
    // positions                           //colors              //alpha
    coordsLine->lineRight, coordsLine->top, 0.8f, 0.498f, 0.1960f, 0.4f,   // top right
    coordsLine->lineRight, coordsLine->bottom, 0.8f, 0.498f, 0.1960f, 0.4f, // bottom right
    coordsLine->lineLeft, coordsLine->bottom, 0.8f, 0.498f, 0.1960f, 0.4f, // bottom left
    coordsLine->lineLeft, coordsLine->top, 0.8f, 0.498f, 00.1960f, 0.4f // top left
};
 

Projection:


projection = glm::ortho(0.f, (float)dev->GetWidth(),(float)dev->GetHeight(), 0.f,  0.f, 1.f);
projection = glm::scale(projection, glm::vec3(dev->GetXScale(), dev->GetYScale(), 1.f));

Before the render loop:


tempLineLeft = coordsLine->lineLeft;
tempLineTop = coordsLine->top;lineHeight = coordsLine->bottom - coordsLine->top;
sourceLineMiddleHeight =(coordsLine->bottom - coordsLine->top) / 2.f;
sourceLineMiddleWidth = (coordsLine->lineRight - coordsLine->lineLeft) / 2.f;

I have to scale the projection to a device. This is working well without problems. Here is the translation and scaling, inside the render loop:


//Inside the Render Loop

if(tempLineLeft != coordsLine->lineLeft) {
    glUseProgram(shaderProgram);
    if(lineHeight != coordsLine->bottom - coordsLine->top) {
        destinationLineMiddleHeight = (coordsLine->bottom - coordsLine->top) / 2.f;
        scaleY = (coordsLine->bottom - coordsLine->top) / lineHeight;
        model = glm::translate(model, glm::vec3(coordsLine->lineLeft - tempLineLeft, coordsLine->top - tempLineTop, 0.f));
        model = glm::translate(model, glm::vec3(0.f, destinationLineMiddleHeight, 0.f));
        model = glm::scale(model, glm::vec3(1.f, scaleY, 1.f));

        }
        else 
           model = glm::translate(model, glm::vec3(coordsLine->lineLeft - tempLineLeft, coordsLine->top - tempLineTop, 0.f));

    }

            
        
if(lineHeight != coordsLine->bottom - coordsLine->top)
    lineHeight = coordsLine->bottom - coordsLine->top;
tempLineLeft = coordsLine->lineLeft;
tempLineTop = coordsLine->top;
sourceLineMiddleHeight =(coordsLine->bottom - coordsLine->top) / 2.f;
sourceLineMiddleWidth = (coordsLine->lineRight - coordsLine->lineLeft) / 2.f;

glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

I don’t use glm and I don’t have the time to analyse your code, but here is the general procedure.

A 4x4 scaling matrix (S) looks like this:

x 0 0 0
0 y 0 0
0 0 z 0
0 0 0 1

where x,y,z are the scaling factors in each direction.

A 4x4 translation matrix (T) looks like this:

1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 1

where x,y,z are the translations in each direction.

Now you have multiple column vectors with 4 entries (V) that represent your geometry. To scale and translate it correctly, the multiplication order matters. First scale!

S * V

Then translate

T * S * V

This should give your desired result.

And before you make the next mistake…

If you have rotations too it is:

T * R * S * V

The real problem is the following: when I scale the object, it is jumping upwards/downwards, I have to translate it back to the target coordinates, and this doesn’t works. I take some pictures, maybe it’s clear what I’m meaning:
Object witouth Scale:
[ATTACH=CONFIG]1895[/ATTACH]
Object scaled:
[ATTACH=CONFIG]1896[/ATTACH]

This should be a trivial problem, I cann’t find an equation to solve that.
In my shader, glPosition is defined by glPosition = projection * model * vec4(aPos, 0.0, 1.0), I understand that.

Its all abaout coordinate systems and transformations between them. I think you are messing something up at the marked position;

glPosition = projection * model * vec4(aPos, 0.0, 1.0)

The vector is ment to be in modelspace if you use the posted tranformations and your vector is not. Modelspace is a coordinate system which is attached to the object you want to draw and it knows nothing about its screen position.

Short example how it is supposed to be:
You want to draw a rectangle, then the center might have the value [0,0] in modelspace while the corners are at [-1,-1],[1,-1],[1,1],[-1,1]. Now you want to draw this rectangle on the screen with the center at the location [500,200] and with a width of 100 and a height of 200. Our original object has a width and height of 2, so we need to multiply its x values with 50 and its y values with 100. Transformation matrix:

50  0    0  0
0   100  0  0
0   0    1  0
0   0    0  1

We do:

S * V

Now the object s corner values are [-50,-100],[50,-100],[50,100],[-50,100]. Now we translate it to its final position by adding 500 to the x values and 200 to the y values. Transformation matrix:


1  0  0  500
0  1  0  200
0  0  1  0
0  0  0  1

We do:

T * S * V

The objects corners are now at [450,100],[550,100],[550,300],[450,300]. You see that we have the desired size and position of the center.

The model matrix you are using (or at least should be using) is nothing else than the combination of the three transformation matrices:

M = T * R * S

So what you did is the following: You applied the translation already to your vector and then multiplied the model matrix. Assuming you did not do any translation in your model matrix then you basically switched the transformation order: You first translated and afterwards you scaled.
So what happens with the rectangle in the example if we do the same?

After applying the translation matrix our values are: [499,199],[501,199],[501,201],[499,201]

Now do the scaling by multiplying the Scaling matrix. The result is: [24950, 19900],[25050,19900],[25050,20100],[24950,20100]

By substracting the x and y limits you will see that the size of the rectangle is still correct, but its position is way off target. Does it sound familiar?

So the correct way to fix your problem would be to remove aPos from your vector and replace it with a fixed number (depending on the current vertex). Add the translation to your model matrix at the right spot. Then it should work. If you want it quick and dirty you can also do the following (still assuming that there is no translation in your model matrix):

projection * (model * vec4(x, y, z, 1.0) + vec4(aPos, 0.0, 0.0))

Where x,y and z are the corner values (vertex values) of your rectangle.

Greetings