2011-01-08 139 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个值看起来确实很小。