AndroidでOpenGL ES2.0入門 その２

## 背景を透過させたい。

```java:qiita.java
glSurfaceView = new GLSurfaceView(getActivity().getApplicationContext());
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setZOrderOnTop(true);
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
glSurfaceView.getHolder().setFormat(PixelFormat.RGBA_8888);
mRenderer = new GameRenderer();
glSurfaceView.setRenderer(mRenderer);
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
((FrameLayout)rootView.findViewById(R.id.base)).addView(glSurfaceView);
```

こんな感じにする。弊害としては、GLのViewが一番手前に来てしまう事。


## 画像を表示したい


1,shaderの登録は

```java:qiita.java
private int shaderProgram;

    public Sprite(){
        shaderProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(shaderProgram, ShaderUtil.loadShader(GLES20.GL_VERTEX_SHADER, ShaderUtil.vertexShaderCode));
        GLES20.glAttachShader(shaderProgram, ShaderUtil.loadShader(GLES20.GL_FRAGMENT_SHADER, ShaderUtil.fragmentShaderCode));
        GLES20.glLinkProgram(shaderProgram);
    }

```

でShaderUtilはオリジナルのクラスで

```java:qiita.java
public static int loadShader(int type, String shaderCode){
        int[] compiled = new int[1];
        int iShader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(iShader, shaderCode);
        GLES20.glCompileShader(iShader);
        GLES20.glGetShaderiv(iShader, GLES20.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            Log.e("Load Shader Failed", "Compilation\n" + GLES20.glGetShaderInfoLog(iShader));
            return 0;
        }
        return iShader;
    }
public static final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "uniform mat4 uMVPMatrix;" +
                    "attribute vec2 a_texCoord;" +
                    "varying vec2 v_texCoord;" +
                    "void main() {" +
                    "  gl_Position = uMVPMatrix*vPosition;" +
                    "  v_texCoord = a_texCoord;" +
                    "}";
    public static final String fragmentShaderCode ="precision mediump float;" +
            "precision mediump float;" +
            "varying vec2 v_texCoord;" +
            "uniform sampler2D s_texture;" +
            "uniform float Opacity;" +
            "uniform float Brightness;" +
            "void main() {" +
            "lowp vec4 textureColor = texture2D( s_texture, v_texCoord );" +
            "gl_FragColor = vec4((textureColor.rgb + vec3(Brightness)), textureColor.w*Opacity);\n" +
            "}";
```

ここでは、一応、明度と、RGBと透過度を変更できるような仕様のデータをいれてあります。→　fragmentShaderCode

1、画像の登録


```java:qiita.java
int[] texture;
    public void setupImage(Bitmap bitmap, int _uniq) {
        texture = new int[1];
        GLES20.glGenTextures(1, texture, 0);
        GLES20.glActiveTexture(ShaderUtil.getTextureLocation(_uniq));
        GLES20.glDeleteTextures(1, texture, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);
        ShaderUtil.setBitmapShaderFilter();
        // 画像をテクスチャに登録
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
    }
```

でShaderUtilはオリジナルのクラスで

```java:qiita.java
public static int getTextureLocation(int uniq){
        if(uniq>4){
            Log.e("CAUTION","端末によっては表示がされない可能性があります。");
        }
        if(uniq == 0){
            return GLES20.GL_TEXTURE0;
        }else if(uniq == 1){
            return GLES20.GL_TEXTURE1;
        }else if(uniq == 2){
            return GLES20.GL_TEXTURE2;
        }else if(uniq == 3){
            return GLES20.GL_TEXTURE3;
        }else if(uniq == 4){
            return GLES20.GL_TEXTURE4;
        }else if(uniq == 5){
            return GLES20.GL_TEXTURE5;
        }else if(uniq == 6){
            return GLES20.GL_TEXTURE6;
        }else if(uniq == 7){
            return GLES20.GL_TEXTURE7;
        }else if(uniq == 8){
            return GLES20.GL_TEXTURE8;
        }else if(uniq == 9){
            return GLES20.GL_TEXTURE9;
        }else if(uniq == 10){
            return GLES20.GL_TEXTURE10;
        }
        return GLES20.GL_TEXTURE0;
    }
```

と

```java:qiita.java
 public static void setBitmapShaderFilter(){
        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);
    }
```

を読んでいる。

これテクスチャの登録に関しては、何枚か！を入れる事ができるのだけど、
問題があって、枚数が一定以上の場合には、表示が化ける。みたいな事が発生します。しかも、端末によって限界の枚数が違うというクソ仕様もあるので、
できれば1枚をいわゆるスプライトシート型にして使うのがベストです。

削除に関しては下記みたいなのを用意。

```java:qiita.java
public void dispose(){
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        GLES20.glDeleteTextures(1, texture, 0);
    }
```
で、描画をするときには、


```java:qiita.java
float uvs[] = new float[3200];
float vertices[] = new float[4800];
FloatBuffer vertexBuffer;
FloatBuffer uvBuffer;
ByteBuffer bb1;
ByteBuffer bb2;
```

をあらかじめ用意しておくと都合がよかったりする。


```java:qiita.java
private int shaderProgram;

    public Sprite(){
        shaderProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(shaderProgram, ShaderUtil.loadShader(GLES20.GL_VERTEX_SHADER, ShaderUtil.vertexShaderCode));
        GLES20.glAttachShader(shaderProgram, ShaderUtil.loadShader(GLES20.GL_FRAGMENT_SHADER, ShaderUtil.fragmentShaderCode));
        GLES20.glLinkProgram(shaderProgram);

        //頂点座標をバッファーに変換
        if(bb1 == null) {
            bb1 = ByteBuffer.allocateDirect(vertices.length * 4);
            bb1.order(ByteOrder.nativeOrder());
            vertexBuffer = bb1.asFloatBuffer();
        }
        //画像側の頂点座標をバッファーに変換
        if(bb2 == null) {
            bb2 = ByteBuffer.allocateDirect(uvs.length * 4);
            bb2.order(ByteOrder.nativeOrder());
            uvBuffer = bb2.asFloatBuffer();
        }
    }
```

こんな感じにバッファー化を行い。


```java:qiita.java
public void draw(float alpha,float bright,Data _Data,int _uniq){
        float uvs_s[] = _Data.GetUvs();
        float vertices_s[] = _Data.GetVertices();
        for(int k = 0 ; k < 12;k++) {
            uvs[k] = uvs_s[k];
        }
        for(int k = 0 ; k < 18;k++) {
            vertices[k] = vertices_s[k];
        }
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
        GLES20.glUseProgram(shaderProgram);
        int mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        int mTexCoordLoc = GLES20.glGetAttribLocation(shaderProgram, "a_texCoord");
        GLES20.glEnableVertexAttribArray(mTexCoordLoc);
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);
        uvBuffer.put(uvs);
        uvBuffer.position(0);
        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
        GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, uvBuffer);
        GLES20.glUniform1i(GLES20.glGetUniformLocation(shaderProgram, "s_texture"), _uniq);
        GLES20.glUniform1f(GLES20.glGetUniformLocation(shaderProgram, "Opacity"), alpha);
        GLES20.glUniform1f(GLES20.glGetUniformLocation(shaderProgram, "Brightness"), bright);
        GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix"), 1, false, mtrxProjectionAndView, 0);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, uvs_s.length/2);
        GLES20.glDisableVertexAttribArray(mPositionHandle);
        GLES20.glDisableVertexAttribArray(mTexCoordLoc);
        GLES20.glDisable(GLES20.GL_BLEND);
    }
```
ってするのですが、

```java:qiita.java
mtrxProjectionAndViewに関しては、まだ定義していなかったのですが、


// Our matrices
    public final float[] mtrxProjection = new float[16];
    public final float[] mtrxView = new float[16];
    public final float[] mtrxProjectionAndView = new float[16];


for(int i=0;i<16;i++) {
            mtrxProjection[i] = 0.0f;
            mtrxView[i] = 0.0f;
            mtrxProjectionAndView[i] = 0.0f;
        }

        // 画面の座標系を作成
        Matrix.orthoM(mtrxProjection, 0,
                0f, width,//左端→右端
                height, 0.0f, //下端→上端
                -1, 1//手前→奥
        );

        //カメラの向きを作成
        Matrix.setLookAtM(mtrxView, 0,
                0f, 0f, 1f,//カメラ位置
                0f, 0f, 0f,//カメラの向き
                0f, 1.0f, 0.0f//カメラの頭
        );

        //上記２つを合算。
        Matrix.multiplyMM(mtrxProjectionAndView, 0, mtrxProjection, 0, mtrxView, 0);
        mtrxProjectionAndView = mtrxProjectionAndView.clone();
```

こんな風に座標のデータを用意しておくと便利

で、

```java:qiita.java
Data.GetUvs();
```

とかについては、UVSを用意してねって事

```java:qiita.java
Data.GetVertices();
```

はVERTICESを用意してねって部分でデータは各々が用意する必要がありますが

UVSは画像の座標の事
VERTICESはステージに座標の事。

たとえば

```java:qiita.java
public static float[] getUvs(){
        return new float[]{
                0,    0,
                0,    1,
                1,    0,
                0,    1,
                1,    0,
                1,    1
        };
    }
```

これは読み込んだ画像まるまる。

```java:qiita.java
public static float[] getUvs(){
        return new float[]{
                0,    0,
                0,    1/4,
                1/4,    0,
                0,    1/4,
                1/4,    0,
                1/4,    1/4
        };
    }
```
これは読み込んだ画像の左上1/4


みたいに、いろいろverticesについては、上記のmtrxProjectionAndViewで設定した自分の座標系を考える必要があるのだけど、

```java:qiita.java
public static float[] getVertices(){

        return new float[]{
                0, 0, 0.0f,
                0, height, 0.0f,
                width, 0, 0.0f,
                0, height, 0.0f,
                width, 0, 0.0f,
                width, height, 0.0f
        };
    }
```

これで全画面に貼りつける事が出来る。


でわりと自分は2Dで使うのだけど、これだけあれば、あとは上手く使うだけで、
これ以上余計な事を考える事もないので、一回画像を表示させて、好きな位置とスプライトシートをうまく使えば、カンタンにできるかと思います。

上記、結構大掛かりな案件でも使った内容ですが、OPENGL自体あまり、Androidで使う人がいないかと思いますが、悩んでる方などには、ある程度道しるべになるかと思います。