2015/11/25

GLSLで書いたシェーダーをUnityのマテリアルにセット、WebGL出力してみます

blog-post-05-content

Unityでシェーダーを書く機会は中々ありませんでしたが、今後のためにもGLSLでシェーダーを書いてみます。

GLSLの特徴はOpenGLに使えるという点です。ということは、スマートフォンゲームやWebGL(ブラウザ)に応用することもできます。 また、言語的には、ほぼCに近い、ポインタのないC言語といった印象があります。(今回、細かな言語仕様の説明は割愛させていただきます。)


まずはGLSL on ブラウザで書く

まずは純粋にGLSLのフラグメントシェーダーだけを書いて試してみたいと思います。 これにはGLSL Sandboxというサイトを使います。このサイトでは、WebGL経由でシェーダーのGLSLコードをリアルタイムプレビュー、さらにjsdoitのようにギャラリーやフォークなどもできます。先にここで書く理由は、ちょっと寄り道してみたかったからです。w WebでもUnityでもどっちでも動くと良いですし。

ちなみに、GLSL Sandboxの開発にはthree.jsの@mrdoob氏など、著名開発者が名を連ねています。

凝ると際限がないと思いますが、そこそこ見栄えしてきたら次のステップへいきます。

GIF Description

デモはこちら : 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

マテリアルを作って・・・

blog-post-05-content3

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

blog-post-05-content4

シェーダーを書いていきます。


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を足しました)

blog-post-05-content


いよいよ再生・・・

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

GIF Description


動いたので、UnityからWebGL出力

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

書き出してしばし待機・・・

圧縮されてはいますが、動きました!

blog-post-05-content5


モバイルブラウザでも動くの?

ちなみに、iOS9.1で動くのかも試してみましたが・・・
動きませんでした。まだ動かないかー。Android5.1でも動きませんでした。
しかも、こんなアラートも出ています。

blog-post-05-content6

「まだUnityはWebGL出力をサポートしていないけどいいの?それでもいいならOKを押してくれたって構わないが・・」という相変わらずの内容です。当然OKを押しましたが、動きません。

モバイル対応の道はまだまだのようです。詳しい情報をご存知の方はお教えいただければと思います。


結果

GLSLで書いたシェーダーを、UnityのWebGL出力で、PCブラウザでは動かすことができました!(モバイルブラウザでは不可)
シェーダーを書くと、画面の表現力が一段増す感じがしますね。