Android OpenGL 2滚动纹理随着时间的推移而失去质量

时间:2015-03-14 04:23:09

标签: android textures opengl-es-2.0

我试图使用OpenGL 2 ES为Android创建一个简单的游戏,它利用重复的滚动纹理作为背景。我设法绘制纹理,滚动它,然后重复。它在前几秒内工作得非常好,然后图像的质量开始下降 - 变得非常像素化。大约10秒钟后,滚动图像几乎无法识别。

纹理使用传递给u_Scroll的浮点值自动/无限滚动。

Fragment Shader:

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

}

我对此非常陌生,所以我不确定要发布的其他代码。为什么我的背景纹理最初会很好并随着时间的推移而降级?不幸的是,我没有足够高的代表发布截图。

1 个答案:

答案 0 :(得分:1)

看起来你在滚动时只是递增/递减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纹理坐标的完全相对精度。