Android OpenGL ES全屏显示宽高比图像

时间:2014-06-19 14:20:10

标签: java android opengl-es opengl-es-2.0

我希望在我的OpenGL应用程序中全屏显示图像,而不会失去其宽高比。我知道我可以将图像作为纹理绘制到“立方体”或2d平面上。但是,当我只是想展示一张2D图像时,我不确定这是否真的是最好的方式。

特别是因为我希望这个图像是全屏而不会失去其宽高比。我知道使用ImageView很容易。但我需要在我的OpenGL ES应用程序中使用它。

但我不知道如何做到这一点。任何人都有任何想法?

1 个答案:

答案 0 :(得分:4)

由于图像的宽高比和视图的宽高比通常不同,因此有两种情况。纵横比定义为宽度/高度:

  1. 如果图像的纵横比大于视图的纵横比,则顶部和底部需要黑条。
  2. 如果图像的宽高比小于视图的宽高比,则左右两侧需要黑条。
  3. 在未应用任何变换的情况下,OpenGL使用在x方向和y方向上具有[-1.0,1.0]范围的坐标系。因此,如果您在两个方向上绘制四边形覆盖[-1.0,1.0],它将填充整个视图。由于我们不希望在两个方向中的一个方向上填充整个范围,我们需要缩小情况1中的y坐标和情况2中的x坐标。所需的缩放量对应于两个长宽比。

    使用以下值:

    float imgAspectRatio = (float)imgWidth / (float)imgHeight;
    float viewAspectRatio = (float)viewWidth / (float)viewHeight;
    

    我们将x和y的缩放因子计算为:

    float xScale = 1.0f;
    float yScale = 1.0f;
    if (imgAspectRatio > viewAspectRatio) {
        yScale = viewAspectRatio / imgAspectRatio;
    } else {
        xScale = imgAspectRatio / viewAspectRatio;
    }
    

    现在剩下的就是在渲染时应用这些比例因子。有多种方法可以做到这一点。您可以将它们用作输入坐标,并绘制一个四边形,在x方向上跨越[-xScale,xScale],在y方向上跨越[-yScale,yScale]。或者您可以在着色器中应用缩放,我认为它稍微优雅一些​​。在这种情况下,您仍然在两个方向上绘制范围为[-1.0,1.0]的四边形,并使用可能如下所示的顶点着色器:

    #version 100
    uniform vec2 ScaleFact;
    attribute vec2 Position;
    varying vec2 TexCoord;
    void main() {
        gl_Position = vec4(ScaleFact * Position, 0.0, 1.0);
        TexCoord = 0.5 * Position + 0.5;
    }
    

    一个片段着色器,只是对纹理进行采样:

    #version 100
    precision mediump float;
    uniform sampler2D Tex;
    varying vec2 TexCoord;
    void main() {
        gl_FragColor = texture2D(Tex, TexCoord);
    }
    

    您传递我们上面计算的xScale/yScale值作为ScaleFact制服的值,设置属性位置以及您通常的其他方式,然后渲染[-1.0, 1.0] x [-1.0,1.0] quad。

    在着色器中进行缩放的优点是,您仍然可以轻松地从单个输入属性派生位置和纹理坐标。如果传入缩放位置,则可能需要在纹理坐标中传递单独的属性。这也是一件非常好的事情。