素人のアンドロイドアプリ開発日記

OpenGL es2のコンテンツ

opengl es2を勉強する。その6 画像のopacityを適用

2015.07.08

qiitaにおいて、一連のOpenGL ES2.0の知見をまとめましたので、もしよかったらそちらもご覧ください

AndroidでOpenGL ES2.0入門

 

openglで消える対象とかって、アルファを下げればよくて、

es1の時にはcolor4f(1f,1f,1f,0.1f);

みたいので、描画前に設定しておけば、アルファになったの楽勝でしょって思ってたら、いない!!

みんなしれっとして、描画方法書いてるのに、フェードインとか書いてる人もいなくて、途方にくれたのですが、

http://stackoverflow.com/questions/15693014/changing-level-of-opacity-in-opengl-es-2-0

を見て、shaderに設定をすれば良いなっていう判断だったのですが、

java→shaderってどうやればいいのかな?って思ったのですが、

uniform float Opacity;

ってした時に、

uniform sampler2D s_texture;

とuniformって一緒だなって思って、

GLES20.glUniform1i(GLES20.glGetUniformLocation (shaderProgram, "s_texture" ),1);

って、テクスチャに1番のテクスチャなって突っ込んでいたなー

と思ったので、

GLES20.glUniform1f(GLES20.glGetUniformLocation(shaderProgram, "Opacity" ), 0.8f);

ってしたら、shader内のOpacityの値も設定できましたので、

public final String fragmentShaderCode =
        "precision mediump float;" +
                "varying vec2 v_texCoord;" +
                "uniform sampler2D s_texture;" +
                "uniform float Opacity;" +
                "void main() {" +
                "gl_FragColor = texture2D( s_texture, v_texCoord );" +
                "gl_FragColor = vec4( gl_FragColor.r,gl_FragColor.g,gl_FragColor.b,gl_FragColor.a*Opacity );" +
                "}";

今まで利用していたshaderを上のように設定をしたら、アルファが聞きました!!

カテゴリー:OpenGL es2

opengl es2を勉強する。その5 画像のアルファチャンネル

2015.07.08

qiitaにおいて、一連のOpenGL ES2.0の知見をまとめましたので、もしよかったらそちらもご覧ください

AndroidでOpenGL ES2.0入門

 

描くときに、

GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

みたいなのを描くとアルファチャンネルが表示される

まぁ、使いたいよね。っていう。

カテゴリー:OpenGL es2

opengl es2を勉強する。その4 shaderを使って、モノクロにする

2015.07.07

qiitaにおいて、一連のOpenGL ES2.0の知見をまとめましたので、もしよかったらそちらもご覧ください

AndroidでOpenGL ES2.0入門

 

 

今回はshaderをちょっと使ってみます。

前回までで、画像の表示ができましたが、shaderを使う事で色の変更が高速で実装できるので、一部では、ビデオ撮影とかに使う事で高速で処理ができたりします。

色を利用していたshaderは

public final String fragmentShaderCode =
        "precision mediump float;" +
                "varying vec2 v_texCoord;" +
                "uniform sampler2D s_texture;" +
                "void main() {" +
                "  gl_FragColor = texture2D( s_texture, v_texCoord );" +
                "}";

って今まで書いていましたが、ここを

public final String fragmentShaderCode =
        "precision mediump float;" +
                "varying vec2 v_texCoord;" +
                "uniform sampler2D s_texture;" +
                "void main() {" +
                "  gl_FragColor = texture2D( s_texture, v_texCoord );" +
                "float avg = 0.2126 * gl_FragColor.r + 0.7152 * gl_FragColor.g + 0.0722 * gl_FragColor.b;"+
                "  gl_FragColor = vec4( avg,avg,avg,1.0 );" +
                "}";

ってすると、モノクロにできます。

もともとは、texture2Dっていうので、色データとかを格納していた部分を、rgbの値を平均化して、再設定しています。gl_FragColorで色を扱っていたんだな。なんて、自分で作ってた部分でありながら実感しますね。

カテゴリー:OpenGL es2

opengl es2を勉強する。その3 画像を複数描く

2015.07.07

qiitaにおいて、一連のOpenGL ES2.0の知見をまとめましたので、もしよかったらそちらもご覧ください

AndroidでOpenGL ES2.0入門

 

 

前回、画像を使ってみて、多分同じ書き方で増やしていけば画像の方をいくつも用意はできるのですが、一部よりCPUの効率がよい方法がありましたので、それで対応してみます。

OpenGL1.0でも行って描画の直前に該当の画像のテクスチャをバインドしていました

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);

で、これが、実は重い動作のようでした。画像へのアクセスを作るというよりも、画像を作業場に持ち出すみたいな感じ。

GLES20.glGenTextures(1, texture, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);

こうやって設定をしていたtextureの中のidを使っていたのですが。

ここで、参照用に

GLES20.glGenTextures(1,texture,0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);

みたいにします。glActiveTextureでGLES20.GL_TEXTUREっていうのが、存在していて、これが該当の番号でGLES20.GL_TEXTURE0からGLES20.GL_TEXTURE31まで用意されていて、それぞれに該当するテクスチャを登録する事ができます。

もっとたくさんテクスチャを用意したい場合には、よくわからないですが、メモリ圧迫をしてしまうので、シーンで分けるとかしたりスプライトシートにしてひとつの画像にいくつかの画像をまとめるのがよいかと思います

でDrawをする前に

// 描画に利用をする画像のデータをする
int textureuniform = GLES20.glGetUniformLocation (shaderProgram, "s_texture" );
GLES20.glUniform1i(textureuniform,2);

みたいにする事で、2番目のテクスチャ持ってくるよ!ってしてくれます。で、このUniformLocationっていうのが、簡単にいうと、shaderの中に記載していた、s_textureの値を変更しますよーっていう関数です。

これは、参照だけなので、Bindよりも高速なようですが、速度は計測してないので、どうかはわかりませんが、おそらくこちらの方がスタンダードな方法のようです。

前回のSpriteを複製したクラスを作って、表示位置を変更するクラスを作って重ねたところ問題なく動作しました

public class Sprite2 {
    //画面の方の座標 zも含む
    private float vertices[] = {
            0.0f, 0.0f,0.0f,
            0.0f, -1.0f,0.0f,
            -1.0f, 0.0f,0.0f,
            -1.0f, -1.0f,0.0f
    };
    //画像の方の座標
    public static float uvs[] = new float[] {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            1.0f, 1.0f
    };

    public FloatBuffer vertexBuffer;
    public ShortBuffer drawListBuffer;
    public FloatBuffer uvBuffer;

    //最もシンプルなシェーダー
    public final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "attribute vec2 a_texCoord;" +
                    "varying vec2 v_texCoord;" +
                    "void main() {" +
                    "  gl_Position = vPosition;" +
                    "  v_texCoord = a_texCoord;" +
                    "}";

    public final String fragmentShaderCode =
            "precision mediump float;" +
                    "varying vec2 v_texCoord;" +
                    "uniform sampler2D s_texture;" +
                    "void main() {" +
                    "  gl_FragColor = texture2D( s_texture, v_texCoord );" +
                    "}";

    public static int loadShader(int type, String shaderCode){
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }


    int shaderProgram;


    Context ctx;

    public Sprite2(Context _ctx){
        ctx = _ctx;
        setupImage();

        //頂点座標をバッファーに変換
        ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);

        //ここからシェーダーを使うっていう、定形
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
        shaderProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(shaderProgram, vertexShader);
        GLES20.glAttachShader(shaderProgram, fragmentShader);
        GLES20.glLinkProgram(shaderProgram);


    }
    int[] texture;
    private void setupImage(){

        //画像側の頂点座標をバッファーに変換
        ByteBuffer bb = ByteBuffer.allocateDirect(uvs.length * 4);
        bb.order(ByteOrder.nativeOrder());
        uvBuffer = bb.asFloatBuffer();
        uvBuffer.put(uvs);
        uvBuffer.position(0);

        texture = new int[1];
        Bitmap bitmap = Util.loadBitmapFromAsset(ctx,"256_2.png");

        // Bind texture to texturename

        GLES20.glGenTextures(1,texture,0);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);

        // 拡大縮小の時のフィルターの設定
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);

        // ちょっとわからないけど何かの設定
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);

        // 画像をテクスチャに登録
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();

        Log.e("CHECLK", "ID:" + texture[0]);
        Log.e("CHECLK", "GLES20.GL_TEXTURE2:" + GLES20.GL_TEXTURE2);
    }

    public void draw(){

        GLES20.glUseProgram(shaderProgram);
        // シェーダーの準備(図形側)
        int mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
        // シェーダー:ON
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //シェーダーの準備(テクスチャ側)
        int mTexCoordLoc = GLES20.glGetAttribLocation(shaderProgram,"a_texCoord" );
        // シェーダー:ON
        GLES20.glEnableVertexAttribArray(mTexCoordLoc );

        //////////////////////////////////START
        //vertexBufferをデータ列から頂点データという解釈に変換
        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
        //uvBufferをデータ列から頂点データという解釈に変換
        GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, uvBuffer);

        // 描画に利用をする画像のデータをする
        int textureuniform = GLES20.glGetUniformLocation (shaderProgram, "s_texture" );
        GLES20.glUniform1i(textureuniform,2);

        // 描画に利用をする画像のデータをする
        //GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);

        // 描画する。何で描くのかは、「関数内で登録してある」という暗黙の了解的な。
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        //////////////////////////////////END
        // シェーダー:OFF
        GLES20.glDisableVertexAttribArray(mPositionHandle);
        GLES20.glDisableVertexAttribArray(mTexCoordLoc);
    }
}

 

カテゴリー:OpenGL es2

opengl es2を勉強する。その2 画像を描く

2015.07.07

qiitaにおいて、一連のOpenGL ES2.0の知見をまとめましたので、もしよかったらそちらもご覧ください

AndroidでOpenGL ES2.0入門

 

前回から、紹介してる内容は、opengl使ってるっていう人には、違和感があるかもしれないのですが、自分としては、

・シンプルに書いて、必要に応じて調べる

という事を目的に書いてます。

初心者丸出しだけど下記みたいになります。

 

device-2015-07-07-170612

OpenGLを使ってみましょうって書いてあって、説明不足で不明点大量の記事や本に辟易してしまったので、なるべくシンプルに書いてます。

前回の

opengl es2を勉強する。その1 三角形を書いて動かす。

をそのまま使います。追加して書いていきますね。

Spriteというクラスで画像を描くとすると

public class GLRenderer implements GLSurfaceView.Renderer {

    Context ctx;
    public GLRenderer(Context _ctx){
        ctx = _ctx;
    }
    Sprite sprite;
    Triangle triangle;
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        triangle = new Triangle();
        sprite = new Sprite(ctx,gl);
    }

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

    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClearColor(0.0f, 0.0f, 0.7f, 1);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        triangle.draw();
        sprite.draw();

    }

    private void callLog(String str){
        Log.e("LOG",str);
    }

    public void onPause(){

    }

    public void onResume(){

    }
}

という形でレンダラーの方をまとめます。で描画用のクラスの方は

public class Sprite {

    //画面の方の座標 zも含む
    private float vertices[] = {
            0.0f, 0.0f,0.0f,
            0.0f, 1.0f,0.0f,
            1.0f, 0.0f,0.0f,
            1.0f, 1.0f,0.0f
    };
    //画像の方の座標
    public static float uvs[] = new float[] {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            1.0f, 1.0f
    };

    public FloatBuffer vertexBuffer;
    public ShortBuffer drawListBuffer;
    public FloatBuffer uvBuffer;

    //最もシンプルなシェーダー
    public final String vertexShaderCode =
            "attribute vec4 vPosition;" +
            "attribute vec2 a_texCoord;" +
            "varying vec2 v_texCoord;" +
            "void main() {" +
            "  gl_Position = vPosition;" +
            "  v_texCoord = a_texCoord;" +
            "}";

    public final String fragmentShaderCode =
            "precision mediump float;" +
                    "varying vec2 v_texCoord;" +
                    "uniform sampler2D s_texture;" +
                    "void main() {" +
                    "  gl_FragColor = texture2D( s_texture, v_texCoord );" +
                    "}";

    public static int loadShader(int type, String shaderCode){
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

    int shaderProgram;
    int[] texture;
    Context ctx;

    public Sprite(Context _ctx){
        ctx = _ctx;
        setupImage();

        //頂点座標をバッファーに変換
        ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);

        //ここからシェーダーを使うっていう、定形
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
        shaderProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(shaderProgram, vertexShader);
        GLES20.glAttachShader(shaderProgram, fragmentShader);
        GLES20.glLinkProgram(shaderProgram);
    }

    private void setupImage(){

        //画像側の頂点座標をバッファーに変換
        ByteBuffer bb = ByteBuffer.allocateDirect(uvs.length * 4);
        bb.order(ByteOrder.nativeOrder());
        uvBuffer = bb.asFloatBuffer();
        uvBuffer.put(uvs);
        uvBuffer.position(0);

        texture = new int[1];
//Bitmapは自分で作ったクラスで持ってきていますが、自分の方法で用意してください。
//Openglなのでサイズは128*128-1024*1024とか2の累乗の正方形にしましょう。
//詳しく調べてませんがes1の時に累乗の正方形でないと出ない端末と出る端末がありました。
        Bitmap bitmap = Util.loadBitmapFromAsset(ctx,"256_2.png");
        GLES20.glGenTextures(1,texture,0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);

        // 拡大縮小の時のフィルターの設定
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);

        // ちょっとわからないけど何かの設定
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);

        // 画像をテクスチャに登録
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();

        Log.e("CHECLK", "ID:" + texture[0]);
    }

    public void draw(){

        GLES20.glUseProgram(shaderProgram);
        // シェーダーの準備(図形側)
        int mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
        // シェーダー:ON
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //シェーダーの準備(テクスチャ側)
        int mTexCoordLoc = GLES20.glGetAttribLocation(shaderProgram,"a_texCoord" );
        // シェーダー:ON
        GLES20.glEnableVertexAttribArray(mTexCoordLoc );

        //////////////////////////////////START
        //vertexBufferをデータ列から頂点データという解釈に変換
        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
        //uvBufferをデータ列から頂点データという解釈に変換
        GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, uvBuffer);

        // 描画に利用をする画像のデータをする
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);

        // 描画する。何で描くのかは、「関数内で登録してある」という暗黙の了解的な。
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        //////////////////////////////////END
        // シェーダー:OFF
        GLES20.glDisableVertexAttribArray(mPositionHandle);
        GLES20.glDisableVertexAttribArray(mTexCoordLoc);
    }
}

で説明は、関数内部に書いてあります。画像のデータはテクスチャっていうのでbindする事で使えるのですが、es1の頃はメモリの為に捨てる必要もあったかと思うので、そのあたりも含めて整理が必要そうです。

 

カテゴリー:OpenGL es2

公開中のアプリ、是非ダウンロードしてみてください

2chまとめのたね

RSSを利用してさまざまなブログの情報をキュレーションしてくれるアプリ

インストールする

ひらがな戦記

OPENGL ES2 を利用したカルタのソーシャルゲーム

インストールする