OpenGL ES-在片段着色器中旋转纹理而不会变形

时间:2019-07-06 13:28:11

标签: android opengl-es glsl shader gpuimage

我正在使用Android的GPUImage库将某些效果应用于位图。本质上,GPUImage接受位图并使用OpenGL ES,将1 x 1多维数据集渲染到位图大小的帧缓冲区中。用户可以编写自定义片段着色器来控制输出。

我正在尝试编写一个片段着色器,该着色器在给定旋转角度的情况下旋转位图。这是我到目前为止的内容:

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);
}

它可以工作,但是显然会扭曲位图(因为GPUImage视口设置为将1 x 1多维数据集映射到实际位图大小)。我无法弄清楚如何消除失真。我应该基于角度和inputImageTextureSize应用一些额外的缩放变换,但是我无法获得正确的方程式。在我的情况下,StackOverflow上的所有答案均不起作用。请帮忙!

谢谢!

2 个答案:

答案 0 :(得分:1)

您必须考虑视口(窗口)的宽高比。
如果窗口具有与图像相同的宽高比,则可以通过图像的大小来计算宽高比:

float aspect = inputImageTextureSize.x / inputImageTextureSize.y;

旋转前按纵横比(* aspect)缩放纹理坐标的u分量,旋转后按倒数纵横比(* 1.0/aspect)缩放:

tc -= HALF.xy;
tc.x *= aspect;
tc *= mat2(aCos, aSin, -aSin, aCos);
tc.x *= 1.0/aspect;
tc += HALF.xy;

为阐明行为,可以使用矩阵运算来表示相同的行为:

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;

答案 1 :(得分:0)

在输入和输出宽高比不同的情况下,作为对Rabbid76答案的补充:

float inputAspect = inputSize.x / inputSize.y;
float outputAspect = outputSize.x / outputSize.y;
float aspect = inputAspect / outputAspect;

// adjust aspect
tc.y *= aspect;
tc.y -= aspect * 0.5 - 0.5;

// rotate ...

这是一个示例:https://www.shadertoy.com/view/3dXBR7