2011-01-08 112 views
2

我有Open GL ES 2片段着色器的問題,並想知道是否有人可以幫助我。Android 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)(見here)。我檢查了着色器的輸入,它絕對是正確的,因此着色器本身必定存在問題。此外,如果我將中間精度從中性改爲highp,那麼在渲染成爲問題之前,我可以將球的數量調整爲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) { 

} 

}

+1

看來片段着色器不會影響對象的輸出位置,我無法看到片段着色器中可能存在的問題......當然,它必須是故障所在的頂點着色器? – Goz 2011-01-08 13:54:35

+0

你可能是對的,但頂點着色器更簡單!我已經將整段代碼添加到了原始問題中 - 您將從android GL2三角形渲染器示例中識別出大部分代碼! – 2011-01-08 14:55:46

+0

在使用glVertexAttribPointer之前不應該調用glEnableVertexAttribArray?如果你知道了,請通知你。我真的很好奇。 – Utyi 2011-01-31 18:14:46

回答

0

此代碼:

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

是不對的。您將[0,NUMBER_OF_BALLS-1]中的i作爲統一的位置傳遞,但必須使用glGetUniformLocation從OpenGL獲取統一的位置。

0

手機上的硬件相當有限,着色器有一個固定數量的週期可以執行。我知道當我在XNA中編程着色器時,如果我試圖循環太多次,我會得到一個錯誤,指出着色器用完了寄存器。這可能會影響你的着色器嗎?

雖然15個值看起來確實很小。