Search code examples
opengl-esglslshader

Aspect Fit and Aspect Fill content mode with OpenGL ES 2.0


I need to add two new content modes to display my textures with OpenGL ES 2.0 : "Aspect Fit" and "Aspect Fill'.

Here's an image explaining the different content modes :

I already have the "Scale to fill" content mode, which is the default behavior I guess.

Here's my basic vertex shader code for textures :

precision highp float;

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

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

And here's my fragment shader for textures :

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

For the "Aspect Fill" mode, I thought I could play with the texture coordinates to crop the image. But for the "Aspect Fit" mode, I don't have a clear idea on how I could do it in the shaders, and even better with a red background color like in the screenshot.


Solution

  • Thanks to @Rabbid76 and his answer here , I managed to do it after adding this part to his answer :

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

    Then I do vec2(scaleX, scaleY)