I am using GPUImage library for Android to apply some effects to the bitmaps. Essentialy, GPUImage accepts bitmap and uses OpenGL ES, rendering 1 x 1 cube into the frame buffer of the bitmap size. User can write custom fragment shader to control the output.
I am trying to write a fragment shader, which rotates the bitmap, given a rotation angle. Here is what I have so far:
varying vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform vec2 inputImageTextureSize;
uniform float angle;
const vec2 HALF = vec2(0.5);
void main()
{
float aSin = sin(angle);
float aCos = cos(angle);
vec2 tc = textureCoordinate;
tc -= HALF.xy;
tc *= mat2(aCos, aSin, -aSin, aCos);
tc += HALF.xy;
vec3 tex = texture2D(inputImageTexture, tc).rgb;
gl_FragColor = vec4(tex, 1.0);
}
It works, but obviously distorts the bitmap (as GPUImage viewport is set up to map 1 x 1 cube to actual bitmap size). I cannot figure out how to get rid of distortion. I should apply some extra scaling transformation, based on the angle and the inputImageTextureSize, but I failed to get the correct equation. None of the answers on StackOverflow actually works in my case. Please, help!
Thanks!
You've to take into account the aspect ration of the viewport (window).
If the window has the same aspect ration as the image, then the aspect ration can be calculated by the size of the image:
float aspect = inputImageTextureSize.x / inputImageTextureSize.y;
Scale the u component of the texture coordinate before the rotation by the aspect ration (* aspect
) and scale it by the reciprocal aspect ratio (* 1.0/aspect
) after the rotation:
tc -= HALF.xy;
tc.x *= aspect;
tc *= mat2(aCos, aSin, -aSin, aCos);
tc.x *= 1.0/aspect;
tc += HALF.xy;
To clarify the behavior, the same can be expressed with matrix operations:
float aSin = sin(angle);
float aCos = cos(angle);
float aspect = u_resolution.x / u_resolution.y;
mat2 rotMat = mat2(aCos, -aSin, aSin, aCos);
mat2 scaleMat = mat2(aspect, 0.0, 0.0, 1.0);
mat2 scaleMatInv = mat2(1.0/aspect, 0.0, 0.0, 1.0);
tc -= HALF.xy;
tc = scaleMatInv * rotMat * scaleMat * tc;
tc += HALF.xy;