ふと「光源位置やら、大域照明やら、そんな事どうでも良いから、指定した色を線形にグラデーションしてくれるようなSkyboxが欲しい!」と思ったので作ってみました。
シェーダ
という事でシェーダコードです。
GradationSkybox.shader
Shader "ScreenPocket/Skybox/Gradation"
{
Properties
{
_TopColor ("Top", Color) = (1, 0, 0, 1)
_MiddleColor ("Middle", Color) = (0, 1, 0, 1)
_BottomColor ("Bottom", Color) = (0, 0, 1, 1)
_Length ("Length", Float) = 1
}
SubShader
{
Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
Cull Off ZWrite Off
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform half3 _TopColor;
uniform half3 _MiddleColor;
uniform half3 _BottomColor;
uniform half _Length;
struct appdata_t
{
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 pos : SV_POSITION;
float3 color : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
v2f vert (appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.pos = UnityObjectToClipPos(v.vertex);
OUT.color = lerp(lerp(_MiddleColor,_TopColor,saturate(v.vertex.y/_Length)),_BottomColor, saturate((-v.vertex.y)/_Length));
return OUT;
}
half4 frag (v2f IN) : SV_Target
{
return half4(IN.color,1);
}
ENDCG
}
}
Fallback Off
}
ポイントは下記
- MVP変換前のv.vertex.yは-1~0~1の球になっているので、その座標位置をそのまま使って線形補間(lerp())しました。
- Topが天球の一番上、Middleが水平線、Bottomが天球の一番下の色となります。
- 色の補間はFragmentシェーダでやろうかと思いましたが、頂点シェーダで行っても十分滑らかだったので、負荷を抑えるために頂点シェーダ側で行いました。
- グラデーションの具合をある程度調整したいので、Lengthの値でグラデ幅を調整できるようにしています
使い方
- 適当にシェーダを作る
- 上記のコードをコピペ
- 適当なマテリアルを作って、ScreenPocket/Skybox/Gradation シェーダを設定
- Top、Middle、Bottomの色を確定し、Lengthでグラデーション幅を決める
- Window/Rendering/LightingでLightingパネルを開き、Environmentタブを選択し、Skybox Materialに作ったマテリアルを設定する
- カメラのInspectorからEnvironment/Background TypeをSkyboxにする
で確認できるかと思います。
終わりに
厳密なSkyboxは必要ないけど、単色で塗りつぶすのは面白くないなぁ…という時や、水中の表現に使えるかと思います。
カーブを線形以外に対応したり、Gradientで自由な色テーブルに対応出来たりすると汎用性が上がりそうですね。