like coffeeの進捗ダメです

Unity, Processingとか

MENU

HSVでグリッドな床シェーダーを作ってみた

かなり久しぶりの投稿です...!

今回は, 先月の学内プロコン用に作ったシェーダーを作った際の工夫を書いてきます!



イメージとしてはplaneオブジェクトにグリッド線の描画し, さらにBloomエフェクトを設定して色相を動的に変更していく感じです

※本シェーダーではPost Processing Stack を必要とします


Surfaceシェーダ作成

実際に書いたシェーダーが下記になります↓

Shader "Custom/HsvGrid"
{
	Properties{
		_GridThickness("Grid Thickness", Float) = 0.1
		_GridSpacing("Grid Spacing", Float) = 9.0
		_Freq("frequency", Range(1,3)) = 1
		_Bloom("Bloom", float) = 7
	}
	SubShader{
		Tags{ "Render" = "Opaque" }
		LOD 200

		CGPROGRAM
		#pragma surface surf Standard fullforwardshadows
		#pragma target 3.0

		struct Input {
			float3 worldPos;
		};

		//HSB→RGB
		fixed3 hsv2rgb(fixed3 c)
		{
			fixed4 K = fixed4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
			fixed3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
			return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
		}

		float _GridThickness; //グリッド線の太さ
		float _GridSpacing; //グリッドの間隔
		float _Freq; //色相が変化する早さ
		float _Bloom; //Bloomエフェクト用の係数

		void surf(Input IN, inout SurfaceOutputStandard o) {
			float _Hue = _Time * _Freq; //色相

			//グリッド線
			o.Albedo = (frac(IN.worldPos.x / _GridSpacing) < _GridThickness
				|| frac(IN.worldPos.z / _GridSpacing) < _GridThickness) ? hsv2rgb(fixed3(_Hue % 1, 1, 1))*_Bloom : fixed3(0, 0, 0);
		}
		ENDCG
		}
	FallBack "Diffuse"
}


これをPlaneオブジェクトに適用します↓

f:id:Eddie_Le_Garden:20191207140216p:plain


グリッド線のジャギー対策

この時点だと上記のキャプチャから遠くのグリッド線にジャギーが生じてしまうことが確認できます

今回はこれを, むろ小径さん(@murosyoukei)のツイートを参考に改善していきます





このツイートを基に改善したシェーダーがこちらです↓

Shader "Custom/HsvGrid"
{
	Properties{
		_GridThickness("Grid Thickness", Float) = 0.1
		_GridSpacing("Grid Spacing", Float) = 9.0
		_Freq("frequency", Range(1,3)) = 1
		_Bloom("Bloom", float) = 7

		_Center("Center", Vector) = (0,0,0,0) //変更点1
		_Range("Renge", Float) = 0.05 //変更点2
	}
		SubShader{
		Tags{ "Render" = "Opaque" }
		LOD 200

		CGPROGRAM
#pragma surface surf Standard fullforwardshadows
#pragma target 3.0

		struct Input {
		float3 worldPos;
	};

	//HSB→RGB
	fixed3 hsv2rgb(fixed3 c)
	{
		fixed4 K = fixed4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
		fixed3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
		return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
	}

	float _GridThickness;
	float _GridSpacing;
	float _Freq;
	float _Bloom;

	float4 _Center; //変更点1
	float _Range; //変更点2

	void surf(Input IN, inout SurfaceOutputStandard o) {
		float _Hue = _Time * _Freq; //色相
		float _DepthThick = (distance(fixed3(_Center.x, 0, _Center.z), IN.worldPos)*_Range); //変更点3

		//グリッド線
		o.Albedo = (frac(IN.worldPos.x / _GridSpacing) < _GridThickness + _DepthThick //変更点4
			|| frac(IN.worldPos.z / _GridSpacing) < _GridThickness + _DepthThick) ? hsv2rgb(fixed3(_Hue % 1, 1, 1))*_Bloom : fixed3(0, 0, 0);
	}
	ENDCG
	}
		FallBack "Diffuse"
}


変更点1, 2ではそれぞれ, MainCameraの位置とその距離に応じてグリッド線を太くするための係数を示します
surf関数では実際にMainCameraとの距離を求め, _DepthThick (変更点3) に加算する太さを代入しています



各プロパティの値は大体こんな感じに設定しました↓

f:id:Eddie_Le_Garden:20191207001751p:plain


次に, 上記のシェーダーにMainCameraの座標を渡すスクリプトを作成します

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PosShader : MonoBehaviour
{
    [SerializeField] Renderer mat;

    void Update()
    {
        mat.material.SetVector("_Center", transform.position);
    }
}


このスクリプトをMainCameraにアタッチし, インスペクターから"mat"にPlaneオブジェクトを指定します.


これで実行すると大体こんな感じになるかと思います↓



右のGame画面からも視点が線に近づくにつれ細くなっていることが確認できると思います.


まとめ

完全にジャギーを消すにはさらに色々と改善しなければならない点はあると思いますが, とりあえず簡単な動きだけ実装しました

今後何かいい方法が思いついたらまた投稿したいと思います!


今回, むろ小径さんにはジャギーの改善以外にも色々お世話になりました
本当にありがとうございます...!



下記参考

hsva-unity/HSVRangeShader.shader at master · greggman/hsva-unity · GitHub

Unity grid floor shader · GitHub

むろ小径 on Twitter: "RGB各要素の数値を1.0以上に設定すれば大丈夫なはずです…!
単純に値に100掛けたりするだけでいい感じになります(その場合0.0になる要素が無いようにすると白い部分が出来て光ってる感が出やすくなります)(既に知っていたらすみません)… "