Не работает OpenGL ES шейдер, вызывать glLinkProgram каждый кадр? - PullRequest
0 голосов
/ 22 мая 2011

Я пытаюсь сделать прозрачный объект в 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 для альфа-тестирования, который отлично работает на моем устройстве 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 ]

2 голосов
/ 05 декабря 2012

Вам не нужно связывать вашу программу каждый кадр, связывать ее один раз и хранить где-нибудь ее идентификатор. Затем позвоните GLES20.glUseProgram(_programId);, прежде чем отправлять вызовы для рисования, соответствующие этой программе.

Проверьте это для уже реализованного подхода: https://github.com/TraxNet/ShadingZen/blob/master/library/src/main/java/org/traxnet/shadingzen/core/ShadersProgram.java (Метод bindProgram - это то, что вам нужно).

0 голосов
/ 28 ноября 2012

Причина такого неправильного поведения не была связана с glLinkProgram().Я изменил некоторые другие параметры инициализации GL (не могу вспомнить, какие в данный момент), и теперь он работает просто отлично.

...