本日はShader枠です。
今回は[Kode life]で作成したShaderをUnityでも再現していきます。
○Kode lifeとは?
[Kode life]はリアルタイムGPUシェーダーエディタです。
リアルタイムとある通り、Kode lifeのエディタ上で編集したコードがすぐに見たに反映されるエディタです。
Unityなどの場合Shaderを編集してエディタ上で保存して初めてコンパイルが行われ、リアルタイムにシェーダーを確認することはできません。
その点Kode lifeはShaderの勉強や簡単なプロトタイプの作成などにおいて非常に強力なツールです。
○UnityのShaderとの違い
UnityのShaderは独自言語の[Shaderlab]で書かれています。
Shaderlabの内部は[cg/HLSL]言語という別の言語で書かれています。
〇Kode lifeのShaderをUnityで再現
[Kode life]を起動するとデフォルトで以下のようにコードが記述されています。
#ifdef GL_ES precision highp float; #endif uniform float time; uniform vec2 resolution; uniform vec2 mouse; uniform vec3 spectrum; uniform sampler2D texture0; uniform sampler2D texture1; uniform sampler2D texture2; uniform sampler2D texture3; uniform sampler2D prevFrame; uniform sampler2D prevPass; varying vec3 v_normal; varying vec2 v_texcoord; void main(void) { vec2 uv = -1. + 2. * v_texcoord; gl_FragColor = vec4( abs(sin(cos(time+3.*uv.y)*2.*uv.x+time)), abs(cos(sin(time+2.*uv.x)*3.*uv.y+time)), abs(tan(time+2)),//ここだけデフォルトから値を変えています。 1.0); }
これはGLSL(OpenGL Shading Language)言語で書かれておりUnityで扱うには変換が必要です。
デフォルトのコードではmain関数のgl_FragColorにvec4型でRGBAが与えられています。
デフォルトのコードではuvを使用しているほか、別の処理を行っていないシンプルなコードなのでこれをUnityのShaderに移植します。
①Unityで基とする基本的なShaderを用意します
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Custom/Rainbow" { Properties { [Header(Rainbow)] _Power("Power",Range(0.1,10))=1 _MainTex("Emissive Map", 2D) = "white" {} } SubShader { Tags { "LightMode" = "ForwardBase" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } fixed4 frag(v2f i) : SV_Target{ return fixed4(1,1,1, 1); } ENDCG } } }
このShaderではuvを使用してRGBA=(1,1,1,1)の白色が表示されるようなShaderです。
②Kode lifeのGLSLのmain関数内をUnityのShaderのフラグメントシェーダー内にコピーします。
fixed4 frag(v2f i) : SV_Target{ //ここからKode lifeからコピーしたGLSL vec2 uv = -1. + 2. * v_texcoord; gl_FragColor = vec4( abs(sin(cos(time + 3. * uv.y) * 2. * uv.x + time)), abs(cos(sin(time + 2. * uv.x) * 3. * uv.y + time)), abs(tan(time + 2)), 1.0); //ここまで return fixed4(1,1,1, 1); }
もちろんこのままでは構文が違うのでエラーを出してしまいます。
GLSLをcg/HLSLに変換していきます。
〇GLSLからcg/HLSLへ変換
GLSLの関数をcg/HLSLへ書き換えていきます。
この対応は以下の記事が参考になりました。
①vec2型をfloat2型に変換する
vec2 uv = -1. + 2. * v_texcoord; → float2 uv = -1. + 2. * i.uv;
② gl_FragColorをfixed4に変換する
gl_FragColor(,,,1);=> return fixed4(,,,1);
③gl_FragColorの引数(R,G,B,1)を移植する
return fixed4(abs(sin(cos(time + 3. * uv.y) * 2. * uv.x + time)),abs(cos(sin(time + 2. * uv.x) * 3. * uv.y + time)), abs(tan(time + 2)),1):
この際にtimeでエラーが出ます。 これはcg/HLSLでは時間を扱うtimeは_Timeと表記する必要があるからです。
④timeを_Timeに変換する
float time = _Time ; return fixed4(abs(sin(cos(time + 3. * uv.y) * 2. * uv.x + time)),abs(cos(sin(time + 2. * uv.x) * 3. * uv.y + time)), abs(tan(time + 2)),1):
以上で移植が完了しました。 Unityで確認するとkode life同様の見た目になることが確認できます。
〇完成したRainbowシェーダー
最後にPowerという変数を加えてUnityのマテリアル側でスピードを調整できるようにしたものが次になります。
Shader "Custom/Rainbow" { Properties { [Header(Rainbow)] _Power("Power",Range(0.1,10))=1 _MainTex("Emissive Map", 2D) = "white" {} } SubShader { Tags { "LightMode" = "ForwardBase" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } float _Power; fixed4 frag(v2f i) : SV_Target{ float2 uv = -1. + 2. * i.uv; float time = _Time * _Power; return fixed4(abs(sin(cos(time + 3. * uv.y) * 2. * uv.x + time)), abs(cos(sin(time + 2. * uv.x) * 3. * uv.y + time)), abs(tan(time + 2)), 1); } ENDCG } } }