'how to rotate and translate rectangle texture in shader

I'm trying to handle the transform of texture in fragment shader. the resolution of window is (640,360), the rotation is 30 degree, and the scale is vec2(0.5,0.5).

this is what I want: correct result here is my fragment shader:

precision mediump float;                            
varying vec2 v_texCoord;                           
uniform sampler2D s_texture;                       
mat3 makeTranslation(vec2 t) {  
    mat3 m = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, t.x, t.y, 1.0);
    return m;
}   
mat3 makeRotation( float angleInRadians ){
    float c = cos(angleInRadians);
    float s = sin(angleInRadians);
    mat3 m = mat3(c, -s, 0, s, c, 0, 0, 0, 1);
    return m;
}
mat3 makeScale(vec2 s) {
   mat3 m = mat3( s.x, 0, 0, 0, s.y, 0, 0, 0, 1);
    return m;
}

void main(){
    vec2 position = vec2(0.0,0.0);  
    vec2 scale = vec2(0.5,0.5);  
    float rotation = 30.0;  
    float r = rotation/180.0*3.14159; 
    vec2 size = vec2(640.0,480.0);

    mat3 mt = makeTranslation( translation );
    mat3 mr = makeRotation( r ); 
    mat3 ms = makeScale( 1.0/scale ); 

    //transform
    vec3 newCoord = vec3(v_texCoord.xy,1.0);                
    newCoord = mt*newCoord; 
    newCoord = mr*ms*vec3(newCoord.x - 0.5, newCoord.y - 0.5,0.0) + vec3(0.5, 0.5, 0.0);

    gl_FragColor = texture2D(s_texture, vec2(newCoord.x, newCoord.y) ); 
} 

the result is: result1
As you can see, the result is incorrect.

so, I apply a ratio of rectangle size to the texcoord.y:

//transform
float fy = 0.5*(1.0 - size.y*1.0/size.x);
newCoord.y = (newCoord.y-0.5)*size.y/size.x+fy;
newCoord = mt*newCoord; \n"
newCoord = mr*ms*vec3(newCoord.x - 0.5, newCoord.y - 0.5,0.0) + vec3(0.5, 0.5, 0.0);
newCoord.y = (newCoord.y+0.5)*size.x/size.y-fy;

what I've got: result the rectangle is correct, but the position of center point is incorrect.

So, how to get the right result? thanks.

here is the origin texture: origin texture



Solution 1:[1]

Getting the right order of operations is very important.

When you receive your texture coordinates, they are in the range [0, 1]. However, you need to translate them, so that they are in [-0.5, 0.5], before you rotate them, so that you are rotating around the center of the texture. Then apply your scale, and finally your translation.

Solution 2:[2]

you dont include screen and texture size proportions

Shadertoy code: (iChannel0 is texture, or BufA then uncomment line 26)

mat3 makeTranslation(vec2 t) {  
    mat3 m = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, t.x, t.y, 1.0);
    return m;
}   
mat3 makeRotation( float angleInRadians ){
    float c = cos(angleInRadians);
    float s = sin(angleInRadians);
    mat3 m = mat3(c, -s, 0, s, c, 0, 0, 0, 1);
    return m;
}
mat3 makeScale(vec2 s) {
   mat3 m = mat3( s.x, 0, 0, 0, s.y, 0, 0, 0, 1);
    return m;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord ){
vec2 screen_res = iResolution.xy/iResolution.y;
vec2 uv = fragCoord/iResolution.y-0.5*screen_res;

    vec2 position = vec2(0.0,0.0);  
    vec2 scale = vec2(0.5,0.5);  
    float rotation = 180.*iMouse.x/iResolution.x;  
    float r = rotation/180.0*3.14159; 
    vec2 size = vec2(640.0,480.0);
    
//vec2 target_res = vec2(textureSize(iChannel0,0).xy)/float(textureSize(iChannel0,0).y);
vec2 target_res = vec2(1.,.5);
    
    mat3 mt = makeTranslation( vec2(0.5*target_res) );
    mat3 mr = makeRotation( r ); 
    mat3 ms = makeScale( 1.0/scale ); 

    //transform
    vec3 newCoord = vec3(uv.xy,1.0);                
    newCoord = mt*newCoord; 
    
    newCoord = mr*ms*vec3(newCoord.x - 0.5*target_res.x, newCoord.y - 0.5*target_res.y,0.0) + vec3(0.5*target_res, 0.0);
    newCoord.xy*= 1./target_res;

    fragColor = texture(iChannel0, vec2(newCoord.x, newCoord.y) ); 
} 

img

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Andrew Williamson
Solution 2 Danil S