Technology Blog
技術ブログ
2015.11.25
GLSLで書いたシェーダーをUnityのマテリアルにセット、WebGL出力してみます

Unityでシェーダーを書く機会は中々ありませんでしたが、今後のためにもGLSLでシェーダーを書いてみます。
GLSLの特徴はOpenGLに使えるという点です。ということは、スマートフォンゲームやWebGL(ブラウザ)に応用することもできます。また、言語的には、ほぼCに近い、ポインタのないC言語といった印象があります。(今回、細かな言語仕様の説明は割愛させていただきます。)
まずはGLSL on ブラウザで書く
まずは純粋にGLSLのフラグメントシェーダーだけを書いて試してみたいと思います。
これにはGLSL Sandboxというサイトを使います。このサイトでは、WebGL経由でシェーダーのGLSLコードをリアルタイムプレビュー、さらにjsdoitのようにギャラリーやフォークなどもできます。先にここで書く理由は、ちょっと寄り道してみたかったからです。w
WebでもUnityでもどっちでも動くと良いですし。
ちなみに、GLSL Sandboxの開発にはthree.jsの@mrdoob氏など、著名開発者が名を連ねています。
凝ると際限がないと思いますが、そこそこ見栄えしてきたら次のステップへいきます。

デモはこちら : http://glslsandbox.com/e#29054.0
ソースは以下の通りです。
ポイントは(というほどではありませんが・・)時間経過を元にして三角関数を動かしているところです。
#ifdef GL_ES precision mediump float; #endif uniform float time; uniform vec2 resolution; void main( void ) { vec2 position = ( gl_FragCoord.xy / resolution.xy ) - 0.5 ; vec3 col = vec3(0.0,0.0,0.0); //15個円を描く for(int i = 0; i < 15; i++){ float red = 0.01 / abs(length(position + float(i) * 0.1) - 1.0 * abs(sin(time))) ; col.r += red; } //時間変化に合わせて色を変える col.g = abs(cos(time)); col.b = abs(sin(time)); gl_FragColor = vec4( col , 1.0 ); }
シェーダーのコードをUnityのマテリアルに持っていく
さて、フラグメントシェーダーのアルゴリズムができたので、Unityのマテリアルを作ってシェーダーをセットしていきます。
ここらへんは以下のページが非常に参考になりました。
「Unity で GLSL によるカスタムシェーダを利用する方法」
http://tips.hecomi.com/entry/20130324/1364136769
マテリアルを作って・・・

シェーダーを作って・・・

シェーダーを書いていきます。
GLSL SandboxのコードをUnity用にする。
先の参考ページをもとにシェーダーのコードを書いていきます。
というか、書いていて気づいたんですがUnityはシェーダーの変更があった場合、リアルタイムに反映してくれるんですね。こりゃ知らなかった。。良いですね。
出来上がったシェーダーはこちら
Shader "Custom/GLSL Shader" { SubShader { Pass { GLSLPROGRAM #ifdef VERTEX void main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } #endif #ifdef FRAGMENT uniform vec4 _Time; uniform vec4 _ScreenParams; void main() { vec2 position = ( gl_FragCoord.xy / _ScreenParams.xy ) - 0.5 ; vec3 col = vec3(0.0,0.0,0.0); float time = _Time.x * 15.0; for(int i = 0; i < 15; i++){ float red = 0.01 / abs(length(position + float(i) * 0.1) - 1.0 * abs(sin(time))) ; col.r += red; } col.g = abs(cos(time)); col.b = abs(sin(time)); gl_FragColor = vec4( col , 1.0 ); } #endif ENDGLSL } } }
ここまでで、こんな感じです。(それっぽいcubeを足しました)

いよいよ再生・・・
こうなりました・・・!!
先ほどのシェーダーが壁一面に広がっています。

動いたので、UnityからWebGL出力
さて、エディター上では一通り、それなりの動きを見ることができました。
次はUnityからWebGL出力をします。これでブラウザ上で上手くシェーダーが動けばいいんですが・・・
書き出してしばし待機・・・
圧縮されてはいますが、動きました!

デモはこちらになります。
モバイルブラウザでも動くの?
ちなみに、iOS9.1で動くのかも試してみましたが・・・
動きませんでした。まだ動かないかー。Android5.1でも動きませんでした。
しかも、こんなアラートも出ています。

「まだUnityはWebGL出力をサポートしていないけどいいの?それでもいいならOKを押してくれたって構わないが・・」という相変わらずの内容です。当然OKを押しましたが、動きません。
モバイル対応の道はまだまだのようです。詳しい情報をご存知の方はお教えいただければと思います。
結果
GLSLで書いたシェーダーを、UnityのWebGL出力で、PCブラウザでは動かすことができました!(モバイルブラウザでは不可)
シェーダーを書くと、画面の表現力が一段増す感じがしますね。