3

進行状況については、最後に編集を参照してください。

OpenGL ES 2.0 を学習しようとしています (Android デバイスで開発する予定です)。

Vertex シェーダーと Fragment シェーダーについて少し混乱しています。それらの目的は理解していますが、カスタム ビルド クラス (「ポイント」など) から形状を構築し、そのサイズと色を設定するか、テクスチャを適用し、オブジェクト クラスのコンストラクターで最初に両方のシェーダーが宣言および定義されていると想定している場合、これは、そのクラスの各インスタンスが独自のシェーダーのペアを持つことを意味しますか?

それが私の最初の質問です。2 つ目は、これが当てはまる場合 (各オブジェクトのシェーダー ペア) ....これでいいのでしょうか? 1 つのシェーダー ペアを使用してそのパラメーターを切り替えることは、パフォーマンスのために良い考えではないと聞いたことがありますが、すべて同じサイズと色 (またはテクスチャ) の 100 個のスプライトがある場合、それらすべてにまったく同じパラメーターを持つシェーダーの異なるペア?

正しい質問をしているといいのですが、私は ES 2.0 を長い間勉強していないので、少し混乱しています。現在、OpenGL についての理解は限られています。

編集

リクエストに応じてコードを追加します。

public class Dot {

    int iProgId;
    int iPosition;
    float size = 10;
    FloatBuffer vertexBuf;
    float r = 1f;
    float g = 1f;
    float b = 1f;
    float a = 1f;
    int iBaseMap;
    int texID; 
    Bitmap imgTexture;


    //Constructor
    public Dot() {

        float[] vertices = {
                        0,0,0f              
                        };

    //Create vertex shader
    String strVShader =  
              "attribute vec4 a_position;\n"+
              "void main()\n" +
              "{\n" +
              "gl_PointSize = " +size+ ";\n" +
              "gl_Position = a_position;\n"+                 
              "}";

    //Create fragment shader
    String strFShader = 
              "precision mediump float;" +
              "void main() " +
              "{" +
              "gl_FragColor = vec4(0,0,0,1);" +
              "}";
              iProgId = Utils.LoadProgram(strVShader, strFShader);
              iPosition = GLES20.glGetAttribLocation(iProgId, "a_position");

                  vertexBuf = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();

                  vertexBuf.put(vertices).position(0);


        }

私の setTexture メソッド

public void setTexture(GLSurfaceView view, Bitmap imgTexture){
    this.imgTexture=imgTexture;

    //Create vertex shader
    String strVShader =  
            "attribute vec4 a_position;\n"+
            "void main()\n" +
            "{\n" +
            "gl_PointSize = " +size+ ";\n" +
            "gl_Position = a_position;\n"+                 
            "}";

    //Fragment shader
    String strFShader =
            "precision mediump float;" +
            "uniform sampler2D u_baseMap;" +
            "void main()" +
            "{" +
            "vec4 color;" +
            "color = texture2D(u_baseMap, gl_PointCoord);" +
            "gl_FragColor = color;" +
            "}";

    iProgId = Utils.LoadProgram(strVShader, strFShader);
    iBaseMap = GLES20.glGetUniformLocation(iProgId, "u_baseMap");

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glUniform1i(iBaseMap, 0);

    texID = Utils.LoadTexture(view, imgTexture);  //See code below
}

Utils私のクラスの LoadTexture() メソッド:

public static int LoadTexture(GLSurfaceView view, Bitmap imgTex) {
    int textures[] = new int[1];
    try {
        GLES20.glGenTextures(1, textures, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_LINEAR);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, imgTex, 0);
    } catch
    }
    return textures[0];
}

そして最後に私の描画方法:

public void drawDot(float x, float y){

        float[] vertices = {
                x,y,0f              
                };

         vertexBuf = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
         vertexBuf.put(vertices).position(0);
        GLES20.glUseProgram(iProgId);
        GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 0, vertexBuf);
        GLES20.glEnableVertexAttribArray(iPosition);
        GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);
    }

したがって、次のようなものを作成できます。

Dot dot1 = new Dot();
dot1.setSize(40);
setTexture(myBitmap); //(created earlier with BitmapFactory)
drawDot(0,0);

ありがとうございました!

編集 1: これまでの回答に感謝します。さらに調査すると、他にも数人がまったく同じ問題を抱えているようです。問題は、レンダリング ルーチンで glBindTexture を呼び出していないことです。そのため、OpenGL はロードした最後のテクスチャを使用しているだけです。これは理にかなっていると思います。

レンダリング ルーチンに次のコードを追加すると、次のようになります。

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 1);

最初のビットマップを適用して表示します

私が置く場合:

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 2);

2番目のビットマップを適用して表示します

だから、どこかに行きます!しかし、私の質問は、どのオブジェクトがそれを呼び出しているか (レンダリング ルーチン) に基づいて、使用するビットマップをレンダリング メソッドに自動的に認識させるにはどうすればよいかということです。

再度、感謝します

4

2 に答える 2

3

仕組み(簡単に)

シェーダーは、グラフィックス カードで実行される単なるプログラムです。それらをコンパイルしてリンクすると、それらにいくつかの変数を渡して、頂点とフラグメントのプロパティを変更できます。これは、glDrawElements や glDrawArrays などの特定の描画関数を呼び出すと、頂点データ (送信する内容に応じて、位置、テクスチャ座標、法線、色などを意味します) がパイプラインに送信されることを意味します。これは、現在ロードされている頂点シェーダーが頂点を 1 つずつ取得し、コードを実行して必要な変換を適用することを意味します。その後、OpenGL はラスタライズを適用して、現在のフレームのフラグメントを生成します。次に、フラグメント シェーダーはすべてのフラグメントを取得し、それに応じて変更します。

シェーダーをいつでもアンロードして、別のシェーダーをロードできます。オブジェクトごとに異なるシェーダーが必要な場合は、シェーダーに従ってオブジェクトをグループ化し、グループごとに対応するシェーダーをリロードしながら、それらを個別にレンダリングできます。

ただし、一部のパラメーターをシェーダーに渡してオブジェクトごとに変更する方が簡単な場合もあります。たとえば、3D モデルをレンダリングする場合、サブメッシュに分割し、すべてのサブメッシュが異なるテクスチャを持つようにすることができます。次に、メッシュの頂点データを渡すときに、テクスチャをロードしてシェーダーに渡します。次のメッシュには、別のテクスチャを渡します。

現実の世界ではすべてがもっと複​​雑ですが、それがどのように機能するかを理解するのに役立つことを願っています.

あなたの例

コンストラクターにシェーダーのペアを (テクスチャなしで) ロードし、テクスチャを設定するたびに新しいシェーダーを作成します。これがより良いアプローチであるかどうかはわかりません。

Utils.LoadShader が何をするかを知らずに知ることは困難ですが、呼び出すたびに結果をログに記録できます。シェーダーを 2 回目にリンクすると、機能しない場合があります。

私があなただったら、ドット オブジェクトの外側で一対のシェーダーを使用します。ドット サイズ、テクスチャなどを示すパラメーターを (glUniform... を使用して) シェーダーに渡すことができます。setTexture 関数は、シェーダーをロードせずに新しいテクスチャをバインドするだけです。最初に (GL コンテキストなどを設定した後) コンパイルします。

これが機能する場合は、本当に必要な場合にのみ、シェーダーを毎回変更することを検討してください。

于 2013-03-05T15:58:19.080 に答える
2

問題が何であるかを知ったので、私は自分自身に答えます。

これを私のdrawDotメソッドに追加しました:

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texID);

texIDは、drawDot()メソッドを呼び出すオブジェクトに対応するテクスチャIDです。

完璧に動作します

これが将来同様の問題を抱えている可能性のある人に役立つことを願っています。

于 2013-03-08T18:07:32.573 に答える