Open7

URPで動くシェーダーを作る

sawarasawara

ゲーミングPC的に光るやつ

Shader "Custom/Gaming"
{
    Properties
    {
        _ColorCycle ("ColorCycle", float) = 0.5
        _BrightCycle ("BrightCycle", float) = 3.0
    }

CGINCLUDE
uniform float _ColorCycle;
uniform float _BrightCycle;

float3 color(float level)
{
    // level: 0~6 -> rgb
    float r = float(level <= 2.0) + float(level > 4.0) * 0.5;
    float g = max(1.0 - abs(level - 2.0) * 0.5, 0.0);
    float b = (1.0 - (level - 4.0) * 0.5) * float(level >= 4.0);
    return float3(r, g, b);
}

float3 smoothColor(float x)
{
    float level1 =  floor(x * 6.0);
    float level2 = min(6.0, floor(x*6.0) + 1.0);
    float3 a = color(level1);
    float3 b = color(level2);
    return lerp(a, b, frac(x * 6.0));
}

float4 paint(float2 uv) 
{
    float repeat = abs(fmod(uv.x * _ColorCycle + _Time.y, 1));
    float3 col = smoothColor(repeat);
    float timeBrightness = sin(_Time.y * _BrightCycle) + 1.5;
    return float4(col * timeBrightness, 1);
}

ENDCG
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            struct fin
            {
                float4 vertex : SV_POSITION;
                float2 texcoord : TEXCOORD0;
            };

            fin vert(appdata v)
            {
                fin o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.texcoord = v.texcoord;
                return o;
            }

            float4 frag(fin IN) : SV_TARGET
            {
                return paint(IN.texcoord.xy);
            }
            ENDCG
        }
    }
}
sawarasawara

HLSLシェーダーの魔導書のunity向け改変

2.3.4 頂点シェーダー

Shader "Custom/Hlsl"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 texcoord : TEXCOORD0;
            };

            sampler2D _MainTex;

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = v.vertex;
                o.vertex.x *= 1.5f;
                o.vertex.y *= 0.5f;

                o.texcoord = v.texcoord;
                return o;
            }

            float4 frag(v2f i) : SV_TARGET
            {
                fixed4 col = tex2D(_MainTex, i.texcoord);
                return col;
            }
            ENDCG
        }
    }
}
sawarasawara

2.4 ピクセルシェーダー入門 赤色の表示

Shader "Custom/Hlsl"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 texcoord : TEXCOORD0;
            };

            sampler2D _MainTex;

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = v.vertex;
                o.texcoord = v.texcoord;
                return o;
            }

            float4 frag(v2f i) : SV_TARGET
            {
                fixed4 red = float4(1.0f, 0.0f, 0.0f, 1.0f);
                return red;
            }
            ENDCG
        }
    }
}

sawarasawara

2.4 ピクセルシェーダー入門 step-4 頂点シェーダーから受け取ったカラーを出力する

Shader "Custom/Hlsl"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                float3 color : COLOR;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 texcoord : TEXCOORD0;
                float3 color : COLOR;
            };

            sampler2D _MainTex;

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = v.vertex;
                o.color = float4(round(v.texcoord.x), round(v.texcoord.y), 0.0f, 1.0f);  // 仮に頂点に色指定
                return o;
            }

            float4 frag(v2f i) : SV_TARGET
            {
                float4 color;
                color.x = i.color.x;
                color.y = i.color.y;
                color.z = i.color.z;
                color.w = 1.0f;
                return color;
            }
            ENDCG
        }
    }
}

c++側を書いていないため、頂点の色を仮で置いている

sawarasawara

3.1 ワールド行列と座標を乗算して座標変換を行う

行列はHLSL内で作成

スクリーン座標への変換はUnityObjectToClipPosを使用。

https://blog.applibot.co.jp/2021/08/04/shader/

Shader "Custom/Hlsl"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType" = "Transparent" "Queue"="Transparent" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                float3 color : COLOR;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 texcoord : TEXCOORD0;
                float3 color : COLOR;
            };

            sampler2D _MainTex;

            v2f vert(appdata v)
            {
                v2f o;

                float x = 0.3;
                float y = 0.5;
                float z = 0.2;
                
                half4x4 moveMatrix = half4x4(1, 0, 0, x,
                                         0, 1, 0, y,
                                         0, 0, 1, z,
                                         0, 0, 0, 1);
                v.vertex = mul(moveMatrix, v.vertex);
                
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            float4 frag(v2f i) : SV_TARGET
            {
                fixed4 red = float4(1.0f, 0.0f, 0.0f, 1.0f);
                return red;
            }
            ENDCG
        }
    }
}

sawarasawara

4.3.2 Lambert拡散反射モデルを実装する

書籍だと内積を取ったあとに-1を乗算しているが、
しなくても正しくレンダリングできているように見える。

_WorldSpaceLightPos0.xyz
のベクトルの向きが逆なのかも

Shader "Custom/Hlsl"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType" = "Transparent" "Queue"="Transparent" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                float3 color : COLOR;
                float3 normal: NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 texcoord : TEXCOORD0;
                float3 color : COLOR;
                float3 normal: NORMAL;
            };

            sampler2D _MainTex;
            half4 _LightColor0;

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.normal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            float4 frag(v2f i) : SV_TARGET
            {
                float t = dot(normalize(i.normal), _WorldSpaceLightPos0.xyz);
                t = max(t, 0);
                fixed4 red = float4(1.0f, 0.0f, 0.0f, 1.0f);
                fixed4 ligColor = _LightColor0 * t;
                return red * ligColor;
            }
            ENDCG
        }
    }
}