qiitaにおいて、一連のOpenGL ES2.0の知見をまとめましたので、もしよかったらそちらをご覧ください
参考にしてるのは、下記の記事
http://androidblog.reindustries.com/a-real-open-gl-es-2-0-2d-tutorial-part-1/
自分の使いやすい用なutilクラスを作るのが目的
manifestファイルは下記
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ve_lo.net.opengltest" > <!-- Tell the system this app requires OpenGL ES 2.0. --> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
use-featureを用意するだけ。これは、端末の特徴を明記する事で、opengl es2が存在してない端末だとインストールできなくするという規則的な記述なので、なくても問題なく動作をする。
今回の構成
MainActivity
rGraphicTools
GLRenderer
のjavaを作る。
まず、MainActivityに関しては、
public class MainActivity extends Activity { private GLSurfaceView glSurfaceView; private GLRenderer mRenderer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setForGL(); setLayout(); } private void setLayout(){ RelativeLayout layout = (RelativeLayout)findViewById(R.id.gamelayout); RelativeLayout.LayoutParams glParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT); layout.addView(glSurfaceView, glParams); } private void setForGL(){ glSurfaceView = new GLSurfaceView(this); glSurfaceView.setEGLContextClientVersion(2); mRenderer = new GLRenderer(); glSurfaceView.setRenderer(mRenderer); glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); } @Override protected void onPause() { super.onPause(); mRenderer.onPause(); glSurfaceView.onPause(); } @Override protected void onResume() { super.onResume(); mRenderer.onResume(); glSurfaceView.onResume(); } }
とシンプルな作りにしてる。
レンダリングは2バージョンを使うのと、絶え間なくレンダリングをし続ける設定だけをする。
でレンダリングのスタートとして、どういう座標系で配置をするのか?っていうのを細々と記載をするサンプルを見ていたのだけど、カメラの位置、座標の位置という形で分けて記載をする事は最初はわからなくなるのでやらない方がいいと思います。
https://www.youtube.com/watch?v=yP1hPFMy-jgを参照して作りました。
いろいろな資料を見ていた結果、行うとよい方法は、
public class GLRenderer implements GLSurfaceView.Renderer { public GLRenderer(){ } Triangle triangle; @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { GLES20.glClearColor(0.0f, 0.0f, 0.7f, 1); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); triangle = new Triangle(); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { } @Override public void onDrawFrame(GL10 unused) { GLES20.glClearColor(0.0f, 0.0f, 0.7f, 1); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); triangle.draw(); } public void onPause(){ } public void onResume(){ } }
こんな感じでTriangleという、クラスを自分で用意して、三角形の記述と、
glClearColorで背景色を指定しています。
で、三角形の記述は細かくなるのですが、ソースコード内に説明を記載しました。
シェーダーに関しては、今回はシンプルなものにしてます。あまり詳しくはないのですが、2D用になっていると思うので3Dで使いたいときとかは、ここから別の対応が必要かもですが、とりあえずは、動くものにしています。
public class Triangle { //三角形の頂点座標をx,y,zで記述 private float vertices[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f }; //色データを赤、緑、青、アルファで記述 float[] color = new float[]{0.0f,0.6f,1.0f,1f}; //最もシンプルなシェーダー public final String vertexShaderCode = "attribute vec4 vPosition;" + "void main() {" + " gl_Position = vPosition;" + "}"; public final String fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() {" + " gl_FragColor = vColor;" + "}"; public static int loadShader(int type, String shaderCode){ int shader = GLES20.glCreateShader(type); GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } private int shaderProgram; FloatBuffer vertexBuffer; public Triangle(){ //頂点座標をバッファーに変換 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); } public void draw(){ //利用するシェーダーの選択 GLES20.glUseProgram(shaderProgram); // シェーダーの準備 int positionAttrib = GLES20.glGetAttribLocation(shaderProgram, "vPosition"); // シェーダー:ON GLES20.glEnableVertexAttribArray(positionAttrib); // vertexBufferをデータ列から頂点データという解釈に変換 //GLES20.glVertexAttribPointer(mPositionHandle, 頂点の数, GLES20.GL_FLOAT, 正規化をする, オフセット, vertexBuffer); GLES20.glVertexAttribPointer(positionAttrib,vertices.length, GLES20.GL_FLOAT, false, 0, vertexBuffer); //ユニフォーム変数にアクセスの準備 int coloruniform = GLES20.glGetUniformLocation(shaderProgram, "vColor"); //色情報をユニフォーム変数に変換 GLES20.glUniform4fv(coloruniform, 1, color, 0); //第二引数はオフセット、第三引数は、頂点の数 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertices.length/3); // シェーダー:OFF GLES20.glDisableVertexAttribArray(positionAttrib); } }
これで、三角形が記載できたので、とりあえず、GLES2.0で三角形を書くのが出来ました!
説明に関しては、下記を参考にしました。(感想は下記に書きました。)
androidって書いてあるけど、iPhoneのソースコードしか乗ってなくて、サンプルだけ申し訳程度にandroidのソースがついてる。っていう、買った後に破り捨てそうになりました。正直。この本見て、androidでopengl入門しようとしたら、泣きますのでご注意した方がよいです。実装がわからないって人には向かないです。