最近AndroidのOpenGL ESを触っているので、少しだけ記事にしてみます。
多分タイトルは正確ではないんだろうなあ……。
OpenGL ESやGLSLに関しては全く詳しくないというか、自分のやりたいことはフラグメントシェーダを書くだけで実現できてしまったので、とりあえずその部分だけを記事にしています。
元にしたプロジェクト
今回のプロジェクトは、以下のプロジェクトをコピペして、OpenGL ESのバージョンを3.1に変え、フルスクリーン表示にしたものです。
qiita.com
カメラからの入力を受け取るための部分はこのプロジェクトのまんまです。
サンプルプロジェクト
全体は以下のGitHubリポジトリを参照して下さい。
ランタイムパーミッション関連を書いていないので、必要であればカメラパーミッションの設定をお願いします。
github.com
フラグメントシェーダ
OpenGL ESでは、GLSLで記述されたフラグメントシェーダが、各頂点の色に関する処理を行います。(今回は各頂点=各画素位のノリで書いていますが多分厳密には違う……)
今回はテストコードとして、画面の左半分であれば赤にノイズを掛け、青と緑を強める、という処理を実装してみました。
この内容はRenderer.java内に書いてあります。
今回は書いていませんが、行列演算も可能です。
#extension GL_OES_EGL_image_external : require precision mediump float; //texcoordVaryingには、テクスチャの0.0から1.0までの位置情報が格納されている varying vec2 texcoordVarying; uniform samplerExternalOES texture; //https://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl //0.0から1.0の一様乱数を返す関数、 //入力はその都度変わる何か、例えば色情報を用いる float rand(vec2 co){ return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\n" + } //フラグメントシェーダのメイン関数 void main() { //色情報を取得, ここで取得されるのは0.0 〜 1.0の範囲の値を持つrgbaのベクトル vec4 v = texture2D(texture, texcoordVarying); //画面の左半分の場合処理する if(texcoordVarying.x < 0.5){ //rに-0.5 〜 0.5の範囲の乱数を載せている //配列と同じようにアクセスできる v[0] += (rand(vec2(v[0] * v[1],v[0] * v[2])) - 0.5); //g, bを入力と1.0の平均で置き換える //このように、ベクトルはxyzw表記でアクセスしたり、ベクトルの一部を低次元のベクトルとして演算することが可能 v.yz = vec2((v.y + 1.0)/2.0, (v.z + 1.0)/2.0); } gl_FragColor = v; }
スクリーンショット
実行するとこんな感じになります。
java上での取り扱い
上記のGLSLコードは、java内では、以下のようにStringで記述します。
private static final String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + //texcoordVaryingには、テクスチャの0.0から1.0までの位置情報が格納されている "varying vec2 texcoordVarying;\n" + "uniform samplerExternalOES texture;\n" + //https://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl //0.0から1.0の一様乱数を返す関数、 //入力はその都度変わる何か、例えば色情報を用いる "float rand(vec2 co){\n" + " return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\n" + "}\n"+ //フラグメントシェーダのメイン関数 "void main() {\n" + //色情報を取得, ここで取得されるのは0.0 〜 1.0の範囲の値を持つrgbaのベクトル " vec4 v = texture2D(texture, texcoordVarying);\n" + //画面の左半分の場合処理する " if(texcoordVarying.x < 0.5){\n" + //rに-0.5 〜 0.5の範囲の乱数を載せている //配列と同じようにアクセスできる " v[0] += (rand(vec2(v[0] * v[1],v[0] * v[2])) - 0.5);\n" + //g, bを入力と1.0の平均で置き換える //このように、ベクトルはxyzw表記でアクセスしたり、ベクトルの一部を低次元のベクトルとして演算することが可能 " v.yz = vec2((v.y + 1.0)/2.0, (v.z + 1.0)/2.0);\n"+ " }\n"+ " gl_FragColor = v;\n" + "}\n";