OpenGL ES - вращение текстуры во фрагментном шейдере без искажений - PullRequest
2 голосов
/ 06 июля 2019

Я использую библиотеку GPUImage для Android, чтобы применить некоторые эффекты к растровым изображениям. По сути, 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 на самом деле не работает в моем случае. Пожалуйста, помогите!

Спасибо!

1 Ответ

1 голос
/ 06 июля 2019

Необходимо учитывать соотношение сторон окна просмотра.
Если окно имеет то же соотношение сторон, что и изображение, соотношение сторон можно рассчитать по размеру изображения:

float aspect = inputImageTextureSize.x / inputImageTextureSize.y;

Масштабирование компонента u координаты текстуры до поворота по соотношению сторон (* aspect) и масштабирование по обратному соотношению сторон (* 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;
...