こんにちは、Unityエンジニアのオオバです。

GLSL Sandboxとは、
言わずと知れた有名なWebサービスです。
GLSLで書かれたシェーダーを即時実行して全世界にブラウザベースで共有できます。

ソースも公開されているためシェーダー教材としても非常に重宝します。

実際にUnityで試してみたい表現が見つかったりするので移植することもありますが、
そもそもUnityはShaderLabという独自のシェーダー言語なので単純にコピペという訳にはいきません。

本記事では移植方法について説明していきます。

👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!

シェーダー言語が違う

先ほど説明したとおり、Unityのシェーダーは全てShaderLab
記述されていて、記述文法としてはCg/HLSLです。

ということで、GLSL SandboxのGLSLコードをCg/HLSLに変換します。

GLSL Sandbox初期ソースをCg/HLSLに変換

GLSL Sandboxで新規作成したときのGLSLコード
newglslsandbox.glsl · GitHub

こちらのGLSLをUnityに以下の手順で移植してみます。

  1. 不要ソース削除
  2. フラグメントシェーダー処理をコピペする
  3. Cg/HLSLの文法に書き換える

GLSL SandboxをUnityに移植する方法その1_0

1.不要ソース削除

こちらのソースは使用しないので削除します。

#ifdef GL_ES
precision mediump float;  
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;  
uniform vec2 mouse;  
uniform vec2 resolution;  

uniform と付くものは外部(ここではJavaScript)から渡される変数で、
timemouseresolutionはそのまま、
時間マウス座標解像度が渡ってきます。

マウス座標以外はShaderLab内で取得可能なので、ここでは削除します。

2. フラグメントシェーダー処理をコピペする

void main( void ) {  
// fragment shader content  
}

11行目のmain関数がフラグメントシェーダー処理です。
この中身をUnityのフラグメントシェーダーにコピペします。

それ以外の変数や関数、構造体などのコードを
フラグメントシェーダーより手前にコピペします。

このサンプルにはmain関数しか無いので、
該当する変数・関数はありませんが、大抵この作業は発生します。

※使用する関数・変数・定数・構造体は、
C言語のように使用するコードより先に書いてないとコンパイルエラー

3.Cg/HLSLの文法に書き換える

ただコピペするだけだとコンパイルエラーになるので、ここからCg/HLSL文法に変換していきます。

フラグメントシェーダーおさらい

フラグメントシェーダーはピクセル毎に処理していくユニットです。
最終的にそのピクセルのカラー値を算出することで処理を終えます。
GLSLとCg/HLSLでは少し文法が違うのでおさらいです。

■GLSLの場合

GLSLのフラグメントシェーダーはgl_FragColor変数にカラー(vec4型)を代入します。

gl_FragColor = vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );  

■Cg/HLSLの場合

一方Cg/HLSLのフラグメントシェーダーでは、
returnステートメントでカラー(fixed4型、float4型、half4)を返却します。

return fixed4( fixed3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );  

また適宜以下のようにキーワードを置き換えてコンパイルが通るように修正していきます。

GLSLCg/HLSL備考
vechalf, fixed, float
_time_Time
mixlerp線形補間
fractfrac引数の小数部分を返す
mat2half2x2, fixed2x2, float2x22☓2行列
mat3half3x3, fixed3x3, float3x33☓3行列
mat4half4x4, fixed4x4, float4x44☓4行列
resolution_ScreenParams解像度
fragCoordi.uv*_ScreenParams頂点シェーダー定義済み関数vert_imgを定義した場合
mouse-C#からシェーダーに値を引き渡して実装する

更に詳しくはコチラのサイトをどうぞ

opengl:glsl_hlsl [HYPERでんち]

頂点シェーダー関数をvert_imgに設定する

これはやってもやらなくても良いのですが、UnityCG.cgincに頂点を変換するだけのミニマムな定義済み頂点シェーダー関数が定義されています。

#pragma vertex vert_img

vert_imgを使用することで、頂点シェーダー関数の記述を省くことが出来ます。

fixed4 frag (v2f_img i) : SV_Target  

以下のようにvert_img関数がv2f_imgを返却しているため、上記のようにフラグメントシェーダーの引数はv2f_img構造体にする必要があります。

UnityCG.cginc内vert_img関数のソースコード

v2f_img vert_img( appdata_img v )  
{
    v2f_img o;  
    o.pos = UnityObjectToClipPos (v.vertex);  
    o.uv = v.texcoord;  
    return o;  
}

変換終了

最終的にこのようなソースコードになります。

glsl.shader · GitHub

書いたシェーダーの反映方法の例

GLSL SandboxをUnityに移植する方法その1_1

Quad(板ポリ)を1枚3D上に配置します。

GLSL SandboxをUnityに移植する方法その1_2

先程のシェーダーをMaterialにアタッチして、このQuadにアタッチします。

GLSL SandboxをUnityに移植する方法その1_3

すると、このようにシェーダーを反映できます。

次回は初期コードではない、もう少しコード量の多いシェーダーを移植してみます。

余談:float4, half4, fixed4とは何か?

さっきからよく出てきてますが、どれも同じ4つの要素を持った値ですが、違いは精度です。

精度備考
float高精度の32bit浮動小数点通常プログラミングのfloatと同じような32bit
half中精度16bit浮動小数点–60000 から +60000 の範囲で、小数点以下約 3 桁
fixed低精度11bit固定小数点–2.0 から +2.0 の範囲で、1/256の精度

int型も使えるようですが、プラットフォームによってはサポートされていないGPUがあるようで注意です。

オススメ記事
検証環境
参考サイト