由于图像的长宽比和视图的长宽比通常会不同,因此有两种情况。纵横比定义为宽度/高度:
- 如果图像的长宽比大于视图的长宽比,则需要在顶部和底部设置黑条。
- 如果图像的长宽比小于视图的长宽比,则需要在右侧和左侧设置黑条。
在不应用任何变换的情况下,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] 四边形。
在着色器中进行缩放的优点是您仍然可以轻松地从单个输入属性导出位置和纹理坐标。如果您传递缩放位置,您可能需要一个单独的属性来传递纹理坐标。这也是一件非常好的事情。