1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

初心者がToonShaderを作ってみた

Posted at

初めに

キャラクターをアニメ調で表現するToonshaderを書いてみたので勉強用に記録します。
解説はコードのコメントに書きました。
ユニバーサルレンダーパイプラインを使用していますので、インストールされてない方Window > My Asset > Unity Registry > Universal RPより、インストールしてください。

Shaderの使い方でお世話になった記事🙇‍♂️

実装コード

Shader "Custom/Toon"
{
   Properties
    {
        _Color ("Color", Color) = (0.3, 0.3, 0.3, 1)//GameObjectの色
        _Width ("width",float) = 0.1//枠の大きさ
        _FrameColor("FrameColor",Color) = (0,0,0,1)//枠の色
    }
   SubShader
    {
        Tags {
            "RenderPipeline"="UniversalPipeline"//UniversalPipelineを使用
        }
 
        LOD 100//閾値

        Pass//枠
        {
            Tags{ "LightMode" = "UniversalForward"}//URPにおける描画順番の指定に必要
            Cull Front//描画順番 後
            HLSLPROGRAM//HLSLを使用
            #pragma vertex vert//頂点の操作
            #pragma fragment frag//画素の色塗
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"//Core.hlslをimport
            #include  "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"//Lighting.hlslをimport
            
            struct appdata
            {
                float4 vertex : POSITION;// セマンティクス(頂点の位置)
                float3 normal : NORMAL;//セマンティクス(頂点の法線)
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;//他のレンダリング対象に対する色
                float3 normalWS : TEXCOORD1;//セマンティクス(2番目のUV座標)
            };
            float _Width;
            v2f vert (appdata v)
            {
                v2f o;
                half4x4 scaleMatrix = half4x4(1 +_Width, 0, 0, 0,
                                             0, 1 + _Width, 0, 0,
                                             0, 0, 1 + _Width, 0,
                                             0, 0, 0, 1);
                v.vertex = mul(scaleMatrix, v.vertex);//行列計算してGameObjectの拡大
                o.vertex = TransformObjectToHClip(v.vertex);
                VertexNormalInputs normal = GetVertexNormalInputs(v.normal);
                o.normalWS = normal.normalWS;
                return o;
            }
            float4 _FrameColor;
            float4 frag (v2f i) : SV_Target
            {                
                return _FrameColor;//枠の色
            }
            ENDHLSL
        }

        Pass
        {
            Cull Back//描画順番 先

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"//Core.hlslをimport
            #include  "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"//Lighting.hlslをimport
            
            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 normalWS : TEXCOORD1;//セマンティクス(2番目のUV座標)
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex);
                VertexNormalInputs normal = GetVertexNormalInputs(v.normal);
                o.normalWS = normal.normalWS;
                return o;
            }
            float4 _Color;
            float4 frag (v2f i) : SV_Target
            {                
                Light lt = GetMainLight();//光を取得
                float4 col = _Color;
                float strength = dot(lt.direction, i.normalWS);//光の強さを計算
                if(strength <= 0.2)//強さによって場合分け
                {
                    strength = 0.1;
                }
                else if(strength <= 0.66)
                {
                    strength = 0.5;
                }
                else
                {
                    strength = 1;
                }
                float4 lightColor = float4(lt.color, 1);//光の色
                return col* lightColor*strength;//最終的な色の計算
            }
            ENDHLSL
        }
}
}

完成

スクリーンショット 2025-02-11 215010.png

補足

HLSLPROGRAMとCGPROGRAMは大体似たようなもの(初心者の意見)
それと、if 文を使うと処理が重くなるという記事を見たので、ifを使わないやり方も載せておきます

Shader "Custom/Toon"
{
   Properties
    {
        _Color ("Color", Color) = (0.3, 0.3, 0.3, 1)//GameObjectの色
        _Width ("width",float) = 0.1//枠の大きさ
        _FrameColor("FrameColor",Color) = (0,0,0,1)//枠の色
        _RampTex ("Ramp", 2D) = "white"{}
    }
   SubShader
    {
        Tags {
            "RenderPipeline"="UniversalPipeline"//UniversalPipelineを使用
        }
 
        LOD 100//閾値

        Pass//枠
        {
            Tags{ "LightMode" = "UniversalForward"}//URPにおける描画順番の指定に必要
            Cull Front//描画順番 後
            HLSLPROGRAM//HLSLを使用
            #pragma vertex vert//頂点の操作
            #pragma fragment frag//画素の色塗
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"//Core.hlslをimport
            #include  "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"//Lighting.hlslをimport
            
            struct appdata
            {
                float4 vertex : POSITION;// セマンティクス(頂点の位置)
                float3 normal : NORMAL;//セマンティクス(頂点の法線)
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;//他のレンダリング対象に対する色
                float3 normalWS : TEXCOORD1;//セマンティクス(2番目のUV座標)
            };
            float _Width;
            v2f vert (appdata v)
            {
                v2f o;
                half4x4 scaleMatrix = half4x4(1 +_Width, 0, 0, 0,
                                             0, 1 + _Width, 0, 0,
                                             0, 0, 1 + _Width, 0,
                                             0, 0, 0, 1);
                v.vertex = mul(scaleMatrix, v.vertex);//行列計算してGameObjectの拡大
                o.vertex = TransformObjectToHClip(v.vertex);//変換
                VertexNormalInputs normal = GetVertexNormalInputs(v.normal);
                o.normalWS = normal.normalWS;
                return o;
            }
            float4 _FrameColor;
            float4 frag (v2f i) : SV_Target
            {                
                return _FrameColor;//枠の色
            }
            ENDHLSL
        }

        Pass
        {
            Cull Back//描画順番 先

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"//Core.hlslをimport
            #include  "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"//Lighting.hlslをimport
            
            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 normalWS : TEXCOORD1;//セマンティクス(2番目のUV座標)
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex);//変換
                VertexNormalInputs normal = GetVertexNormalInputs(v.normal);
                o.normalWS = normal.normalWS;
                return o;
            }
            float4 _Color;
            sampler2D _RampTex;
            float4 frag (v2f i) : SV_Target
            {                
                Light lt = GetMainLight();//光を取得
                float4 col = _Color;
                float strength = (dot(lt.direction, i.normalWS)+1)*0.5;//光の強さを計算
                float3 ramp = tex2D(_RampTex, float2(strength, 0.5)).rgb;//テキスチャの色の取得
                float r = dot(ramp, float3(0.333, 0.333, 0.333));//内積による色の強度の取得
                float4 lightColor = float4(lt.color, 1);//光の色
                return col* lightColor*r;//最終的な色の計算
            }
            ENDHLSL
        }
}
}

使用方法

以下の写真をtoon.shaderのマテリアルのRampにアタッチします

Image.png

参考にしたサイトの紹介

枠の作成

陰の作成

shaderのセマンティクスの解説

ifを使わずに実行する方法の参考

最後に

今回が初めて書いた記事なので、うまくかけてないかもしれません。だから、疑問とかあれば、コメントとか書いていただければ、拙い知識ではありますが、できるだけ答えようと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?