Skip to content

Instantly share code, notes, and snippets.

@koturn
Last active January 13, 2021 23:31
Show Gist options
  • Save koturn/51558f584b99330c36e5bdc93361ae4b to your computer and use it in GitHub Desktop.
Save koturn/51558f584b99330c36e5bdc93361ae4b to your computer and use it in GitHub Desktop.
ゲーミングライフゲーム
Shader "koturn/GameOfLife"
{
// セルの生存をアルファ値で管理する
// 座標(0, 0)は更新間隔管理に用いており,描画セルかどうかの座標値の判定は省いているので,
// (0, 0)に影響を及ぼさない安定したパターンを初期値として与える必要がある.
Properties
{
_Color ("Cell Color", Color) = (0.0, 1.0, 0.0, 1.0)
_TimeScale ("Time multiplier for HSV rotation", Float) = 0.1
_TimeOffset ("Time offset for HSV rotation", Range(0.0, 1.0)) = 0.0
_DivCycle ("Divide Cycle", Float) = 6.0
}
SubShader
{
Cull Off
ZWrite Off
ZTest Always
Pass
{
Name "Update"
CGPROGRAM
#pragma target 3.0
#include "UnityCustomRenderTexture.cginc"
#pragma vertex CustomRenderTextureVertexShader
#pragma fragment frag
static const float eps = 1.0e-3;
inline float3 rgb2hsv(float3 rgb);
inline float3 hsv2rgb(float3 hsv);
inline float addHue(float h, float dHue);
inline float3 addHue(float3 hsv, float dHue);
float4 _Color;
float _TimeScale;
float _TimeOffset;
float _DivCycle;
//! @brief フラグメントシェーダ
//!
//! @param [in] i カスタムレンダーテクスチャの入力値
//!
//! @return 1つのテクセルに対するRGBA値
float4 frag(v2f_customrendertexture i) : COLOR
{
float2 d = float2(1.0 / _CustomRenderTextureWidth, 1.0 / _CustomRenderTextureHeight);
float2 uv = i.globalTexcoord;
float dt = (1.0 / _DivCycle);
float t = tex2D(_SelfTexture2D, float2(0.0, 0.0)).r + dt;
float4 texel = tex2D(_SelfTexture2D, uv);
if (uv.x < d.x && uv.y < d.y) {
if (t >= 1.0) {
texel.r = 0.0;
} else {
texel.r += dt;
}
texel.a = 0.0;
} else if (t >= 1.0) {
float4 color = float4(hsv2rgb(addHue(rgb2hsv(_Color.rgb), _Time.y * _TimeScale + _TimeOffset)), _Color.a);
float3x3 neighbor3x3 = step(color.a, float3x3(
tex2D(_SelfTexture2D, uv - d).a, tex2D(_SelfTexture2D, float2(uv.x, uv.y - d.y)).a, tex2D(_SelfTexture2D, float2(uv.x + d.x, uv.y - d.y)).a,
tex2D(_SelfTexture2D, float2(uv.x - d.x, uv.y)).a, 0.0, tex2D(_SelfTexture2D, float2(uv.x + d.x, uv.y)).a,
tex2D(_SelfTexture2D, float2(uv.x - d.x, uv.y + d.y)).a, tex2D(_SelfTexture2D, float2(uv.x, uv.y + d.y)).a, tex2D(_SelfTexture2D, uv + d).a));
float sum = neighbor3x3[0][0] + neighbor3x3[0][1] + neighbor3x3[0][2]
+ neighbor3x3[1][0] + neighbor3x3[1][2]
+ neighbor3x3[2][0] + neighbor3x3[2][1] + neighbor3x3[2][2];
if (abs(sum - 3.0) < eps) {
texel = color;
} else if (abs(sum - 2.0) > eps) {
texel = float4(color.rgb, 0.0);
} else {
// 状態変化無しだが,初期化画像の上書きのため,colorの値で上書きする
texel = float4(color.rgb, step(color.a, texel.a) * _Color.a);
}
}
return texel;
}
//! @brief RGB色空間からHSV色空間へ写像を行なう
//!
//! 入力のRGBの各要素,および出力のHSVの各要素は閉区間: [0.0, 1.0] で正規化されているものとする
//!
//! @param [in] rgb RGB値
//!
//! @return HSV値
inline float3 rgb2hsv(float3 rgb)
{
float4 k = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = rgb.g < rgb.b ? float4(rgb.bg, k.wz) : float4(rgb.gb, k.xy);
float4 q = rgb.r < p.x ? float4(p.xyw, rgb.r) : float4(rgb.r, p.yzx);
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
//! @brief HSV色空間からRGB色空間へ写像を行なう
//!
//! 入力のHSVの各要素,および出力のRGBの各要素は閉区間: [0.0, 1.0] で正規化されているものとする
//!
//! @param [in] hsv HSV値
//!
//! @return RGB値
inline float3 hsv2rgb(float3 hsv)
{
float4 k = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 p = abs(frac(hsv.xxx + k.xyz) * 6.0 - k.www);
return hsv.z * lerp(k.xxx, saturate(p - k.xxx), hsv.y);
}
inline float addHue(float h, float dHue)
{
return fmod(h + dHue, 1.0);
}
inline float3 addHue(float3 hsv, float dHue)
{
return float3(addHue(hsv.x, dHue), hsv.yz);
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment