Фрагментные шейдеры Android OPEN GL ES 2 - PullRequest
2 голосов
/ 08 января 2011

У меня проблема с фрагментным шейдером Open GL ES 2, и мне было интересно, может ли кто-нибудь мне помочь.

Я использую шейдер для рисования мета-шариков на экране.Это относительно просто, и код выглядит следующим образом:

private static final String mFragmentShader = "precision mediump float;\n"
                                              + "uniform vec2 balls["
                                              + NUMBER_OF_BALLS
                                              + "];\n"
                                              + "float sqr(highp float x) { return x*x; }\n"
                                              + "void main() {\n"
                                              + "  vec4 pixelColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
                                              + "  vec4 color = vec4(0.0, 0.5, 1.0, 1.0);\n"
                                              + "  for (int i=0; i<"
                                              + NUMBER_OF_BALLS
                                              + "; ++i) {\n"
                                              + "    vec2 dist = balls[i] - gl_FragCoord.xy;\n"
                                              + "    float val = 100.0 / (sqr(dist.x) + sqr(dist.y));\n"
                                              + "    pixelColor += color * val;\n"
                                              + "  }\n"
                                              + "  highp float a = smoothstep(0.9, 1.0, pixelColor.a);\n"
                                              + "  gl_FragColor = vec4(pixelColor.rgb * a, 1.0);\n"
                                              + "}\n";

Шейдер прекрасно компилируется и работает хорошо, когда NUMBER_OF_BALLS меньше 15. К сожалению, когда количество шаров больше 15, он выглядит так, как будтовсе шары находятся в положении (0,0) (см. здесь ).Я проверил входные данные для шейдера, и это определенно правильно, поэтому должна быть проблема с самим шейдером.Кроме того, если я изменю точность с среднего значения на верхнее, тогда я могу увеличить количество шаров до 20, прежде чем рендеринг станет проблемой.

Может кто-нибудь сказать мне, что я делаю неправильно?

Редактировать: Вот полный код на случай, если проблема не в самом фрагментном шейдере.

       private static final String mFragmentShader = "precision mediump float;\n"
                                              + "uniform vec2 balls["
                                              + NUMBER_OF_BALLS
                                              + "];\n"
                                              + "float sqr(highp float x) { return x*x; }\n"
                                              + "void main() {\n"
                                              + "  vec4 pixelColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
                                              + "  vec4 color = vec4(0.0, 0.5, 1.0, 1.0);\n"
                                              + "  for (int i=0; i<"
                                              + NUMBER_OF_BALLS
                                              + "; ++i) {\n"
                                              + "    vec2 dist = balls[i] - gl_FragCoord.xy;\n"
                                              + "    float val = 100.0 / (sqr(dist.x) + sqr(dist.y));\n"
                                              + "    pixelColor += color * val;\n"
                                              + "  }\n"
                                              + "  highp float a = smoothstep(0.9, 1.0, pixelColor.a);\n"
                                              + "  gl_FragColor = vec4(pixelColor.rgb * a, 1.0);\n"
                                              + "}\n";



private static final String mVertexShader = "attribute vec4 vPosition;\n" + "void main() {\n"
                                            + "  gl_Position = vPosition;\n"
                                            + "}\n";

int gProgram;
int gvPositionHandle;

private float[][] balls = new float[NUMBER_OF_BALLS][2];

int[] lBalls = new int[NUMBER_OF_BALLS];

private static final int FLOAT_SIZE_BYTES = 4;

private final float[] mQuadVerticesData = { 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, };

private FloatBuffer mQuadVertices;

public MetaballRenderer() {
    mQuadVertices = ByteBuffer.allocateDirect(mQuadVerticesData.length * FLOAT_SIZE_BYTES)
                              .order(ByteOrder.nativeOrder())
                              .asFloatBuffer();
    mQuadVertices.put(mQuadVerticesData).position(0);
}

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;
}

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 void init_balls() {
    for (int i = 0; i < NUMBER_OF_BALLS; ++i) {
        balls[i][0] = 200 + rand.nextInt(50);
        balls[i][1] = 200 + rand.nextInt(50);
    }
}

private void checkGlError(String op) {
    int error;
    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
        Log.e(TAG, op + ": glError " + error);
        throw new RuntimeException(op + ": glError " + error);
    }
}

@Override
public void onDrawFrame(GL10 arg0) {

    GLES20.glUseProgram(gProgram);
    checkGlError("glUseProgram");

    for (int i = 0; i < NUMBER_OF_BALLS; ++i) {
        GLES20.glUniform2fv(i, 1, balls[i], 0);
        checkGlError("glUniform2fv");
    }

    GLES20.glVertexAttribPointer(gvPositionHandle, 2, GLES20.GL_FLOAT, false, 0, mQuadVertices);
    checkGlError("glVertexAttribPointer");
    GLES20.glEnableVertexAttribArray(gvPositionHandle);
    checkGlError("glEnableVertexAttribArray");

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
    checkGlError("glDrawArrays");

    GLES20.glUseProgram(0);
    checkGlError("glUseProgram");

}

@Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) {

    // Ignore the passed-in GL10 interface, and use the GLES20
    // class's static methods instead.
    gProgram = createProgram(mVertexShader, mFragmentShader);
    if (gProgram == 0) {
        return;
    }

    gvPositionHandle = GLES20.glGetAttribLocation(gProgram, "vPosition");
    checkGlError("glGetAttribLocation");
    init_balls();
    for (int i = 0; i < NUMBER_OF_BALLS; ++i) {
        lBalls[i] = GLES20.glGetUniformLocation(gProgram, "balls[" + i + "]");
        checkGlError("glGetUniformLocation");
    }

    GLES20.glViewport(0, 0, width, height);
    checkGlError("glViewport");

}

@Override
public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) {

}

}

Ответы [ 2 ]

0 голосов
/ 08 января 2011

Аппаратное обеспечение телефонов довольно ограничено, и шейдеры имеют фиксированное количество циклов, которое они могут выполнять. Я знаю, когда я программировал шейдеры в XNA, если бы я пытался зацикливаться слишком много раз, я получал бы ошибку, утверждая, что шейдер исчерпал регистры. Может ли это повлиять и на ваш шейдер?

15 значений кажутся довольно маленькими.

0 голосов
/ 08 января 2011

Этот код:

for (int i = 0; i < NUMBER_OF_BALLS; ++i) {
        GLES20.glUniform2fv(i, 1, balls[i], 0);
        checkGlError("glUniform2fv");
}

Не правильно. Вы передаете i в [0, NUMBER_OF_BALLS-1] как единые местоположения, но одинаковые местоположения ДОЛЖНЫ быть получены из OpenGL с использованием glGetUniformLocation.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...