本日は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
}
}
}