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

Viv*_*ndi 1 java android opengl-es opengl-es-2.0

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

尤其是因为我希望此图像全屏显示而不损失其宽高比。我知道使用ImageView很容易。但我的OpenGL ES应用程序中需要此功能。

但是我不知道该怎么做。有人知道吗?

Ret*_*adi 5

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

  1. 如果图像的纵横比大于视图的纵横比,则顶部和底部需要黑条。
  2. 如果图像的长宽比小于视图的长宽比,则左右各需要黑条。

在不应用任何变换的情况下,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;
Run Code Online (Sandbox Code Playgroud)

我们将x和y的比例因子计算为:

float xScale = 1.0f;
float yScale = 1.0f;
if (imgAspectRatio > viewAspectRatio) {
    yScale = viewAspectRatio / imgAspectRatio;
} else {
    xScale = imgAspectRatio / viewAspectRatio;
}
Run Code Online (Sandbox Code Playgroud)

现在剩下的就是在渲染时应用这些比例因子。有多种方法可以做到这一点。您可以将它们用作输入坐标,并绘制一个四边形,该四边形在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;
}
Run Code Online (Sandbox Code Playgroud)

还有一个片段着色器,仅对纹理进行采样:

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

您传入xScale/yScale我们在上面计算出的ScaleFact统一值的值,以通常的方式设置属性位置和其他所有内容,然后渲染[-1.0,1.0] x [-1.0,1.0]四边形。

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