背景を透過させたい。
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の登録は
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はオリジナルのクラスで
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、画像の登録
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はオリジナルのクラスで
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;
}
と
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枚をいわゆるスプライトシート型にして使うのがベストです。
削除に関しては下記みたいなのを用意。
public void dispose(){
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glDeleteTextures(1, texture, 0);
}
で、描画をするときには、
float uvs[] = new float[3200];
float vertices[] = new float[4800];
FloatBuffer vertexBuffer;
FloatBuffer uvBuffer;
ByteBuffer bb1;
ByteBuffer bb2;
をあらかじめ用意しておくと都合がよかったりする。
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();
}
}
こんな感じにバッファー化を行い。
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);
}
ってするのですが、
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//カメラの頭
);
//上記2つを合算。
Matrix.multiplyMM(mtrxProjectionAndView, 0, mtrxProjection, 0, mtrxView, 0);
mtrxProjectionAndView = mtrxProjectionAndView.clone();
こんな風に座標のデータを用意しておくと便利
で、
Data.GetUvs();
とかについては、UVSを用意してねって事
Data.GetVertices();
はVERTICESを用意してねって部分でデータは各々が用意する必要がありますが
UVSは画像の座標の事
VERTICESはステージに座標の事。
たとえば
public static float[] getUvs(){
return new float[]{
0, 0,
0, 1,
1, 0,
0, 1,
1, 0,
1, 1
};
}
これは読み込んだ画像まるまる。
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で設定した自分の座標系を考える必要があるのだけど、
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で使う人がいないかと思いますが、悩んでる方などには、ある程度道しるべになるかと思います。