Android OpenGL 2 滚动纹理随时间推移质量下降
Android OpenGL 2 Scrolling Texture Loses Quality Over Time
我正在尝试使用 OpenGL 2 ES 为 Android 创建一个简单的游戏,该游戏使用背景的重复滚动纹理。我设法绘制纹理,滚动它,然后重复。它在最初几秒钟内效果非常好,然后图像质量开始下降 - 变得非常像素化。大约 10 秒后,滚动图像几乎无法识别。
纹理使用传递给 u_Scroll 的浮点值滚动 automatically/infinitely。
片段着色器:
precision mediump float;
uniform float u_Scroll;
uniform sampler2D u_TextureUnit;
varying vec2 v_TextureCoordinates;
void main()
{
gl_FragColor = texture2D(u_TextureUnit, vec2(v_TextureCoordinates.x, v_TextureCoordinates.y + u_Scroll));
}
加载纹理方法
public static int loadBackgroundTexture(Context context, int resourceId) {
final int [] textureObjectIds = new int[1];
glGenTextures(1, textureObjectIds, 0);
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
return textureObjectIds[0];
}
来自渲染器的 onDraw:
public void onDrawFrame(GL10 gl) {
glClear(GL_COLOR_BUFFER_BIT);
multiplyMM(viewProjectionMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
invertM(invertedViewProjectionMatrix, 0, viewProjectionMatrix, 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
positionBackgroundInScene();
backgroundProgram.useProgram();
backgroundProgram.setUniforms(modelViewProjectionMatrix, texture[1]);
background.bindData(backgroundProgram);
background.draw();
positionAngelInScene(angelPosition.x, angelPosition.y, angelPosition.z);
textureProgram.useProgram();
textureProgram.setUniforms(modelViewProjectionMatrix, texture[0]);
angel.bindData(textureProgram);
angel.draw();
}
我对此很陌生,所以我不确定 post 还有哪些其他代码。为什么我的背景纹理一开始很好,但随着时间的推移会退化?不幸的是,我没有足够高的代表 post 截图。
看起来您在滚动时只是 incrementing/decrementing u_Scroll
值,并依靠纹理 GL_REPEAT
行为让您无限滚动。
这里的问题很可能是浮点精度。 medium
浮点值,这是您用于纹理坐标数学的值,在典型实现中只有大约 0.1%(10 位)的相对精度。
为了说明这一点的含义,假设您已经滚动了 10 次,并且您的纹理坐标范围现在介于 10.0 和 11.0 之间。在 0.1% 的相对精度下,您可以在此范围内表示的浮点值之间的增量约为 0.01。或者换句话说,您可以表示 10.0 到 11.0 之间的大约 100 个值。如果你的质地是512x512,你只能用你的纹理坐标定位每 5 个像素。
使用它的一个选项是将浮点精度更改为 highp
。但不能保证所有 ES 2.0 实现都支持它。
除非我误解了你在做什么,否则应该有一个非常简单的解决方案:在你的应用程序代码中将你用来设置 u_Scroll
的值范围保持在 0.0 和 1.0 之间。
您的应用程序代码中可能有逻辑上看起来像这样的代码,用于将用户输入转换为滚动:
if (scrollRight) {
scrollValue += scrollIncrement;
} else if (scrollLeft) {
scrollValue -= scrollIncrement;
}
...
glUniform1f(scrollLoc, scrollValue);
将此更改为:
if (scrollRight) {
scrollValue += scrollIncrement;
if (scrollValue > 1.0f) {
scrollValue -= 1.0f;
}
} else if (scrollLeft) {
scrollValue -= scrollIncrement;
if (scrollValue < 0.0f) {
scrollValue += 1.0f;
}
}
...
glUniform1f(scrollLoc, scrollValue);
这将使 scrollValue
保持在 0.0 和 1.0 之间,这允许您在片段着色器中使用 medium
纹理坐标的完整相对精度。
我正在尝试使用 OpenGL 2 ES 为 Android 创建一个简单的游戏,该游戏使用背景的重复滚动纹理。我设法绘制纹理,滚动它,然后重复。它在最初几秒钟内效果非常好,然后图像质量开始下降 - 变得非常像素化。大约 10 秒后,滚动图像几乎无法识别。
纹理使用传递给 u_Scroll 的浮点值滚动 automatically/infinitely。
片段着色器:
precision mediump float;
uniform float u_Scroll;
uniform sampler2D u_TextureUnit;
varying vec2 v_TextureCoordinates;
void main()
{
gl_FragColor = texture2D(u_TextureUnit, vec2(v_TextureCoordinates.x, v_TextureCoordinates.y + u_Scroll));
}
加载纹理方法
public static int loadBackgroundTexture(Context context, int resourceId) {
final int [] textureObjectIds = new int[1];
glGenTextures(1, textureObjectIds, 0);
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
return textureObjectIds[0];
}
来自渲染器的 onDraw:
public void onDrawFrame(GL10 gl) {
glClear(GL_COLOR_BUFFER_BIT);
multiplyMM(viewProjectionMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
invertM(invertedViewProjectionMatrix, 0, viewProjectionMatrix, 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
positionBackgroundInScene();
backgroundProgram.useProgram();
backgroundProgram.setUniforms(modelViewProjectionMatrix, texture[1]);
background.bindData(backgroundProgram);
background.draw();
positionAngelInScene(angelPosition.x, angelPosition.y, angelPosition.z);
textureProgram.useProgram();
textureProgram.setUniforms(modelViewProjectionMatrix, texture[0]);
angel.bindData(textureProgram);
angel.draw();
}
我对此很陌生,所以我不确定 post 还有哪些其他代码。为什么我的背景纹理一开始很好,但随着时间的推移会退化?不幸的是,我没有足够高的代表 post 截图。
看起来您在滚动时只是 incrementing/decrementing u_Scroll
值,并依靠纹理 GL_REPEAT
行为让您无限滚动。
这里的问题很可能是浮点精度。 medium
浮点值,这是您用于纹理坐标数学的值,在典型实现中只有大约 0.1%(10 位)的相对精度。
为了说明这一点的含义,假设您已经滚动了 10 次,并且您的纹理坐标范围现在介于 10.0 和 11.0 之间。在 0.1% 的相对精度下,您可以在此范围内表示的浮点值之间的增量约为 0.01。或者换句话说,您可以表示 10.0 到 11.0 之间的大约 100 个值。如果你的质地是512x512,你只能用你的纹理坐标定位每 5 个像素。
使用它的一个选项是将浮点精度更改为 highp
。但不能保证所有 ES 2.0 实现都支持它。
除非我误解了你在做什么,否则应该有一个非常简单的解决方案:在你的应用程序代码中将你用来设置 u_Scroll
的值范围保持在 0.0 和 1.0 之间。
您的应用程序代码中可能有逻辑上看起来像这样的代码,用于将用户输入转换为滚动:
if (scrollRight) {
scrollValue += scrollIncrement;
} else if (scrollLeft) {
scrollValue -= scrollIncrement;
}
...
glUniform1f(scrollLoc, scrollValue);
将此更改为:
if (scrollRight) {
scrollValue += scrollIncrement;
if (scrollValue > 1.0f) {
scrollValue -= 1.0f;
}
} else if (scrollLeft) {
scrollValue -= scrollIncrement;
if (scrollValue < 0.0f) {
scrollValue += 1.0f;
}
}
...
glUniform1f(scrollLoc, scrollValue);
这将使 scrollValue
保持在 0.0 和 1.0 之间,这允许您在片段着色器中使用 medium
纹理坐标的完整相对精度。