不工作的OpenGL ES着色器,每帧调用glLinkProgram?

时间:2011-05-22 07:05:00

标签: android opengl-es opengl-es-2.0 glsl

我正在尝试在OpenGL ES 2.0中制作透明对象。这是一个动态壁纸,我使用GLWallpaperService作为基类。我正在以这种方式设置OpenGL:

GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthFunc(GLES20.GL_GEQUAL);
GLES20.glClearDepthf(0.0f);
GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

我使用的着色器取自PowerVR样本OGLES2AlphaTest进行alpha测试,这在我的HTC Desire设备上运行良好。 以下是着色器的代码:

private final String mVertexShader = "uniform highp mat4 uMVPMatrix;\n" +
        "attribute highp vec4 aPosition;\n" +
        "attribute highp vec2 aTextureCoord;\n" +
        "varying mediump vec2 vTextureCoord;\n" +
        "void main() {\n" +
        "  gl_Position = uMVPMatrix * aPosition;\n" +
        "  vTextureCoord = aTextureCoord;\n" +
        "}\n";

private final String mFragmentShader = "precision mediump float;\n" +
        "varying mediump vec2 vTextureCoord;\n" +
        "uniform sampler2D sTexture;\n" +
        "void main() {\n" +
        "  vec4 base = texture2D(sTexture, vTextureCoord);\n" +
        "  if(base.a < 0.5){ discard; }\n" +
        "  gl_FragColor = base;\n" +
        "}\n";

private int createProgram(String vertexSource, String fragmentSource) {
    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
    if (vertexShader == 0) {
        return 0;
    }

    int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
    if (pixelShader == 0) {
        return 0;
    }

    int program = GLES20.glCreateProgram();
    if (program != 0) {
        GLES20.glAttachShader(program, vertexShader);
        checkGlError("glAttachShader");
        GLES20.glAttachShader(program, pixelShader);
        checkGlError("glAttachShader");
        GLES20.glLinkProgram(program);
        int[] linkStatus = new int[1];
        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
        if (linkStatus[0] != GLES20.GL_TRUE) {
            Log.e(TAG, "Could not link program: ");
            Log.e(TAG, GLES20.glGetProgramInfoLog(program));
            GLES20.glDeleteProgram(program);
            program = 0;
        }
    }
    return program;
}

private int loadShader(int shaderType, String source) {
    int shader = GLES20.glCreateShader(shaderType);
    if (shader != 0) {
        GLES20.glShaderSource(shader, source);
        GLES20.glCompileShader(shader);
        int[] compiled = new int[1];
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            Log.e(TAG, "Could not compile shader " + shaderType + ":");
            Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
            GLES20.glDeleteShader(shader);
            shader = 0;
        }
    }
    return shader;
}

渲染帧的代码:

public void onDrawFrame(GL10 glUnused) {
    //GLES20.glLinkProgram(mProgram);

    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    GLES20.glUseProgram(mProgram);
    checkGlError("glUseProgram");

    GLES20.glDisable(GLES20.GL_BLEND);

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);

    mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
    GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
    checkGlError("glVertexAttribPointer maPosition");
    mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
    GLES20.glEnableVertexAttribArray(maPositionHandle);
    checkGlError("glEnableVertexAttribArray maPositionHandle");
    GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
    checkGlError("glVertexAttribPointer maTextureHandle");
    GLES20.glEnableVertexAttribArray(maTextureHandle);
    checkGlError("glEnableVertexAttribArray maTextureHandle");

    long time = SystemClock.uptimeMillis() % 4000L;
    float angle = 0.090f * ((int) time);
    time = SystemClock.uptimeMillis();// % 4000L;
    angle = 0.030f * ((int) time);
    // Matrix.setRotateM(mMMatrix, 0, angle, 0, 0, 1.0f);
    Matrix.setRotateM(mMMatrix, 0, angle, 0, 1.0f, 0);
    Matrix.scaleM(mMMatrix, 0, 0.075f, 0.075f, 0.075f);
    Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);

    GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, numPolys);
    checkGlError("glDrawArrays");
}

GLES20.glLinkProgram(mProgram);开头没有onDrawFrame()我的结果不正确(透明度不正确):http://imgur.com/kESeO

当我在GLES20.glLinkProgram(mProgram);的开头添加onDrawFrame()时,它正确呈现,但性能不佳,glLinkProgram()是一项耗时的功能。以下是正确呈现的屏幕截图:http://imgur.com/sw83z

请解释我做错了什么,显然我不必在重绘每一帧时调用glLinkProgram()

2 个答案:

答案 0 :(得分:2)

您不需要每帧链接您的程序,将其链接一次并将其ID存储在某处。然后在发出与该程序对应的绘图调用之前调用GLES20.glUseProgram(_programId);

检查一下已经实现的方法:https://github.com/TraxNet/ShadingZen/blob/master/library/src/main/java/org/traxnet/shadingzen/core/ShadersProgram.java(bindProgram方法就是你所追求的)。

答案 1 :(得分:0)

这种不当行为的原因与glLinkProgram()无关。我已经修改了一些其他的GL初始化参数(目前无法回想起这些参数),现在它的工作正常。