2011-01-08 15 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参照)。私はシェイダーへの入力をチェックしました。それは間違いなく正しいのでシェーダー自体に問題があるはずです。さらに、mediumpから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

+0

あなたは正しいかもしれませんが、頂点シェーダはもっと簡単です!私はオリジナルの質問にコード全体を加えました - あなたはアンドロイドGL2三角レンダラの例からそのほとんどを認識します! –

+0

glVertexAttribPointerを使用する前にglEnableVertexAttribArrayを呼び出さないでください。あなたがそれを理解した場合は通知してください。私は本当にそれについて興味がある。 – Utyi

答えて

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

はい、申し訳ありませんが、GLES20.glUniform2fv(lBalls [i]、1、balls [i]、0)である必要があります。私はlBalls [i]を、レンダラーの起動時に呼び出されるonSurfaceChanged()メソッドのunifromの場所に設定しました。これを修正すると残念なことに同じプロンプトレンダリングが行われます( –

0

携帯電話のハードウェアはかなり制限されており、シェーダは実行可能な一定量のサイクルを持っています。私はXNAでシェーダをプログラミングしていた時期を知っていますが、何度もループしてみると、シェーダがレジスタを使い果たしたというエラーが表示されます。これはあなたのシェーダーにも影響を与えますか?

15値はかなり小さいようです。

+0

これは不可能ではありませんが、15値がすべて対応できれば非常に苛立つでしょう)。私は見て、それが問題を引き起こしているかどうかを確認しますこの場合、checkGLErrorを介してエラーが発生していると予期していましたか? –

+0

まだGLSLを行っていないので100%確信していません。 – SpencerElliott

関連する問題