使用OpenGL ES2.0降低纹理渲染质量

时间:2014-12-23 07:49:57

标签: android graphics opengl-es opengl-es-2.0 graphics2d

我正在使用OpenGL ES2.0 [ANdroid]在正方形上绘制纹理。纹理在垂直方向上无限滚动。

几帧后渲染质量下降非常快,纹理质量下降。

截图#1 Initial Image

屏幕截图#2 After a few frames

如何解决此问题?

代码:

package gamedev.soursugar.infinitescroll;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

/**
 * Created by soursugar on 19/12/14.
 */
public class Background {

    private final String vertexShaderCode =
            "uniform mat4 uMVPMatrix;"      +
                    "attribute vec4 vPosition;"     +
                    "attribute vec2 TexCoordIn;"    +
                    "varying vec2 TexCoordOut;"     +
                    "void main() {"                 +
                    "   gl_Position = uMVPMatrix * vPosition;"  +
                    "   TexCoordOut = TexCoordIn;"  +
                    "}";

    private final String fragmentShaderCode =
            "precision mediump float;"  +
                    "uniform vec4 vColor;"      +
                    "uniform sampler2D TexCoordIn;" +
                    "uniform float scroll;" +
                    "varying vec2 TexCoordOut;" +
                    "void main() {" +
                    "   gl_FragColor = texture2D(TexCoordIn, vec2(TexCoordOut.x, TexCoordOut.y + scroll));" +
                    "}";


    private int[] textures = new int[1];

    private byte[] indices = {
            0, 1, 2,
            0, 2, 3
    };

    private float[] texture = {
            0.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f,
            1.0f, 1.0f
    };

    private float[] vertices = {
            -1f, -1f, 0f,
            -1f, 1f, 0f,
            1f, 1f, 0f,
            1f, -1f, 0f
    };

    private final FloatBuffer vertexBuffer;
    private final ByteBuffer indexBuffer;
    private final FloatBuffer textureBuffer;

    private final int mProgram;
    private int mPositionHandle;
    private int mMVPMatrixHandle;

    static final int COORDS_PER_VERTEX = 3;
    static final int COORDS_PER_TEXTURE = 2;
    private final int vertexStride = COORDS_PER_VERTEX * 4;
    private final int textureStride = COORDS_PER_TEXTURE * 4;

    private float scroll = 0.00f;

    public Background() {
        ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        vertexBuffer = byteBuf.asFloatBuffer();

        byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        textureBuffer = byteBuf.asFloatBuffer();
        textureBuffer.put(texture);
        textureBuffer.position(0);

        indexBuffer = ByteBuffer.allocateDirect(indices.length);
        indexBuffer.order(ByteOrder.nativeOrder());
        indexBuffer.put(indices);
        indexBuffer.position(0);

        int vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
        GLES20.glShaderSource(vertexShader, vertexShaderCode);
        GLES20.glCompileShader(vertexShader);

        int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
        GLES20.glShaderSource(fragmentShader, fragmentShaderCode);
        GLES20.glCompileShader(fragmentShader);

        mProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(mProgram, vertexShader);
        GLES20.glAttachShader(mProgram, fragmentShader);

        GLES20.glLinkProgram(mProgram);

    }

    private void reloadVertexBuffer() {
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);
    }

    public void loadTexture(int texture, Context context, int width, int height) {
        Bitmap bitmap = null;
        float w = 0.75f;

        try{
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inScaled=false;
            bitmap = BitmapFactory.decodeStream(context.getAssets().open("background.png"));
            w = (1.0f/height)*width;
            Log.d("Width", String.valueOf(w));

        } catch (Exception e) {
            Log.d("Exception from SourSugar", "Error in decoding stream");
        }

        vertices[0] = -w;
        vertices[3] = -w;
        vertices[6] = w;
        vertices[9] = w;
        reloadVertexBuffer();

        GLES20.glGenTextures(1, textures, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);

        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();
    }

    public void draw(float[] mvpMatrix, int frameCount) {
        //if(frameCount==25 || frameCount==50)
            //scroll = 0f;

        scroll -= 0.005f;
        GLES20.glUseProgram(mProgram);

        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        GLES20.glEnableVertexAttribArray(mPositionHandle);


        int vsTextureCoord = GLES20.glGetAttribLocation(mProgram, "TexCoordIn");


        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
        GLES20.glVertexAttribPointer(vsTextureCoord, COORDS_PER_TEXTURE, GLES20.GL_FLOAT, false, textureStride, textureBuffer);
        GLES20.glEnableVertexAttribArray(vsTextureCoord);


        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
        int fsTexture = GLES20.glGetUniformLocation(mProgram, "TexCoordOut");
        int fsScroll = GLES20.glGetUniformLocation(mProgram, "scroll");

        GLES20.glUniform1i(fsTexture, 0);
        GLES20.glUniform1f(fsScroll, scroll);

        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_BYTE, indexBuffer);
        GLES20.glDisableVertexAttribArray(mPositionHandle);

    }

}

1 个答案:

答案 0 :(得分:4)

问题与片段着色器中的这一行有关:

"gl_FragColor = texture2D(TexCoordIn, vec2(TexCoordOut.x, TexCoordOut.y + scroll));"

粗略地说,浮点数可以准确地表示小数字,也可以不准确地表示大数字。当您将两个浮点数加在一起时,结果通常会具有两者中较大幅度(不太准确)的精度。因此,当 scroll 的值过大时,纹理坐标(TexCoordOut.y + scroll)的精度会降低。

您可以通过更改Java代码来修复此问题,使您的滚动值环绕在0.0 - 1.0

的范围内
scroll -= 0.005f;
if(scroll < 0.0f)
    scroll += 1.0f;

由于你在T中进行纹理环绕,你可以丢弃整数部分,它不会有任何区别。