Search code examples
matrixrotationwebglcoordinate-transformation

How do I correct the matrix's scaling when rotating when aspect ratio is not 1:1


I have a rotating matrix with a texture on it. When the orthographic scene's aspect ratio is 1:1, like 600px and 600px, it rotates perfectly. But if I increase for example the height to 1200 I get a few problems. It looks as if the matrix's horixontal axis is scaled as if it wasn't rotated.

Lets say I have a sscene of 600x1200, and my matrix is suposed to be 30x30. If the matrix is not rotated, it's x scale should be 0.05*600 which is 30px. If I rotate the matrix 90 degrees it's x scale should be 0.025*1200 which is 30px. However I have nothing that compensates this and the matrix scale is the same always, as if it isn't being rotated.

enter image description here

How do I compensate for this?

Here is my vertex shader code:

void main()
{   

fragColor = vertColor;

vTextureCoord = (vec4(aTextureCoord.x, aTextureCoord.y, 0.0, 1.0)).xy * uvScale + uvOffset;
vTextureCoordBg = (vec4(aTextureCoord, 0.0, 1.0)).xy * uvScaleBg + uvOffsetBg;


mat4 worldPosTrans = mat4(
    vec4(scale.x*cos(rotateZ),  scale.x*-sin(rotateZ),  0.0,            0.0), 
    vec4(scale.y*sin(rotateZ),  scale.y*cos(rotateZ),   0.0,            0.0), 
    vec4(0.0,                   0.0,                    scale.z,        0.0), 
    vec4(translation.x,         translation.y,          translation.z,  1.0));



gl_Position = (uPMatrix * worldPosTrans) * vec4(vertPosition.x + vertPosFixAfterRotate.x, vertPosition.y + vertPosFixAfterRotate.y, vertPosition.z, 1.0);

}

I tried to decrease the x scale as the angle approached 90 and 270 degrees with Math.sin but it didn't work as expected.


Solution

  • In general the aspect ratio is encoded to the projection matrix. The projection matrix is the last transformation which is applied to the vertex coordinates.

    If you want to aply the aspect ration in the vertex shader, it works like this:

    Aspect matrix:

    float aspect = width / height;
    
    mat4 aspect_mat = mat4(
        vec4(1.0/aspect, 0.0, 0.0, 0.0), 
        vec4(0.0,        1.0, 0.0, 0.0), 
        vec4(0.0,        0.0, 1.0, 0.0), 
        vec4(0.0,        0.0, 0.0, 1.0)); 
    
    mat4 model_mat = mat4(
        vec4(scale.x*cos(rotateZ),  scale.x*-sin(rotateZ),  0.0,            0.0), 
        vec4(scale.y*sin(rotateZ),  scale.y*cos(rotateZ),   0.0,            0.0), 
        vec4(0.0,                   0.0,                    scale.z,        0.0), 
        vec4(translation.x,         translation.y,          translation.z,  1.0));
    
    mat4 worldPosTrans = aspect_mat * model_mat;
    

    This results in:

    mat4 worldPosTrans = mat4(
        vec4(scale.x*cos(rotateZ)/aspect,  scale.x*-sin(rotateZ),  0.0,           0.0), 
        vec4(scale.y*sin(rotateZ)/aspect,  scale.y*cos(rotateZ),   0.0,           0.0), 
        vec4(0.0,                          0.0,                    scale.z,       0.0), 
        vec4(translation.x/aspect,         translation.y,          translation.z, 1.0));