Режимы Aspect Fit и Aspect Fill с OpenGL ES 2.0 - PullRequest
1 голос
/ 09 июля 2020

Мне нужно добавить два новых режима содержимого для отображения моих текстур с помощью OpenGL ES 2.0: «Aspect Fit» и «Aspect Fill».

Вот изображение, поясняющее различные режимы содержимого:

введите описание изображения здесь

У меня уже есть режим содержимого «Масштабирование для заполнения», я думаю, это поведение по умолчанию.

Вот мой базовый c код вершинного шейдера для текстур:

precision highp float;

attribute vec2 aTexCoordinate;
varying vec2 vTexCoordinate;
uniform mat4 uMVPMatrix;
attribute vec4 vPosition;

void main() {
    vTexCoordinate = aTexCoordinate;
    gl_Position = uMVPMatrix * vPosition;
}

А вот мой фрагментный шейдер для текстур:

precision mediump float;

uniform vec4 vColor;
uniform sampler2D uTexture;
varying vec2 vTexCoordinate;

void main() {
    // premultiplied alpha
    vec4 texColor = texture2D(uTexture, vTexCoordinate);
    // Scale the texture RGB by the vertex color
    texColor.rgb *= vColor.rgb;
    // Scale the texture RGBA by the vertex alpha to reinstate premultiplication
    gl_FragColor = texColor * vColor.a;
    //gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}

Для режима «Aspect Fill» я подумал, что могу поиграть с координатами текстуры, чтобы обрезать изображение. Но для режима «Aspect Fit» у меня нет четкого представления о том, как я могу это сделать в шейдерах, а еще лучше с красным цветом фона, как на скриншоте.

Ответы [ 2 ]

1 голос
/ 11 июля 2020

Благодаря @ Rabbid76 и его ответу здесь , мне удалось это сделать после добавления этой части к его ответу:


    float textureAspect = (float)textureSize.width / (float)textureSize.height;
    float frameAspect = (float)frameSize.width / (float)frameSize.height;

    float scaleX = 1, scaleY = 1;
    float textureFrameRatio = textureAspect / frameAspect;
    BOOL portraitTexture = textureAspect < 1;
    BOOL portraitFrame = frameAspect < 1;

    if(contentMode == AspectFill) {
        if(portraitFrame)
            scaleX = 1.f / textureFrameRatio;
        else
            scaleY = textureFrameRatio;
    }
    else if(contentMode == AspectFit) {
        if(portraitFrame)
            scaleY = textureFrameRatio;
        else
            scaleX = 1.f / textureFrameRatio;
    }

Затем я делаю vec2(scaleX, scaleY)

1 голос
/ 09 июля 2020

Вы должны масштабировать координаты текстуры. Я рекомендую добавить форму для масштабирования текстуры:

uniform vec2 textureScale;

void main()
{
    vTexCoordinate = textureScale * (aTexCoordinate - 0.5) + 0.5;
    // [...]
}

Вычислить соотношение сторон текстуры:

aspect = textrueHeight / textureWidth

textureScale должен быть установлен в зависимости от режима :

  • «Масштаб для заполнения»: vec2(1.0, 1.0).
  • альбомный «Соотношение сторон»: vec2(1.0, aspect).
  • альбомный «Aspect Fill»: vec2(1.0/aspect, 1.0).
  • портрет «Aspect Fit»: vec2(1.0/aspect, 1.0).
  • портрет «Aspect Fill»: vec2(1.0, aspect).

Вы должны установить обтекание текстурой параметры (GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T) в режим GL_CLAMP_TO_EDGE. См. glTexParameter.

В качестве альтернативы вы можете discard лишние фрагменты во фрагментном шейдере:

void main() {
    if (vTexCoordinate.x < 0.0 || vTexCoordinate.x > 1.0 ||
        vTexCoordinate.y < 0.0 || vTexCoordinate.y > 1.0) {
    
        discard;
    }

    // [...]
}   
...