unity 3d物体描边效果_萌新学习Shader(七)描边效果

2860ce2a7969da998b73b98ed45496a1.png

0.前言

通过之前的努力,我们达到了如下效果

f28a0d4b6f4b6c9081013f4125318db2.png

现在我们想在这个基础上添加描边效果,也就外轮廓线。

1f1b5bb4fe708575de6c2bd59178f22f.png

1.核心思想

这里要用到的知识点就是我们之前提到的,一个SubShader可以有多个Pass

想实现描边效果,我们需要用到两个Pass渲染,在一个Pass中渲染一个球,然后在另一个Pass中渲染一个大一圈的黑色球,然后再对大一圈的黑球进行正面剔除

2.核心代码

1.剔除正面

Cull Front

2.让球扩大一圈

v2f vert (appdata v)
{    
    v2f o;

    // 获取法线
    float3 normal = v.normal;

    // 顶点加 0.0.2 倍的法线
    v.vertex.xyz += normal * 0.02;

    // 转换坐标到裁剪坐标
    o.pos = UnityObjectToClipPos(v.vertex);

    return o;
}

3.返回一个黑色球

float4 frag (v2f i) : SV_Target
{    
    // 全部设置呈黑色
    return fixed4(0,0,0,1);
}

4.用两个Pass渲染

Shader "MyShader/Cartoon"
{
    Properties
    {
        ...
    }
    SubShader
    {
        Pass
        {
            Tags { "LightMode" = "ForwardBase"}

            // 剔除掉球的正面
            Cull Front

            CGPROGRAM
            ...

            v2f vert (appdata v)
            {    
                ...
            }

            float4 frag (v2f i) : SV_Target
            {
                ...
            }
            ENDCG
        }

        Pass
        {
            CGPROGRAM
            ...
            v2f vert (appdata v)
            {    
                ...
            }

            float4 frag (v2f i) : SV_Target
            {
                ...
            }
            ENDCG
        }
    }
}

3.完整的代码实现

Shader "MyShader/Cartoon"
{
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            Tags { "LightMode" = "ForwardBase"}
            Cull Front
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal:NORMAL;
            };

            struct v2f
            {
                float3 worldNormal:TEXCOORD0;
                float4 pos: SV_POSITION; 
            };

            float4 _Diffuse; 

            v2f vert (appdata v)
            {    
                v2f o;

                // 获取法线
                float3 normal = v.normal;

                // 顶点加 0.0.2 倍的法线
                v.vertex.xyz += normal * 0.02;

                // 转换坐标到
                o.pos = UnityObjectToClipPos(v.vertex);

                return o;
            }

            float4 frag (v2f i) : SV_Target
            {    
                return fixed4(0,0,0,1);
            }
            ENDCG
        }

        Pass
        {
            Tags { "LightMode" = "ForwardBase"}
            Cull Back

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal:NORMAL;
            };

            struct v2f
            {
                float3 worldNormal:TEXCOORD0;
                float4 pos: SV_POSITION; 
            };

            float4 _Diffuse; 

            v2f vert (appdata v)
            {    
                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);

                // 表面法线                
                o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));

                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                // 环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                // 顶点到光源方向                
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                float NdotL = 0.5 + 0.5 * dot(i.worldNormal, worldLight);

                if (NdotL > 0.9)
                {
                    NdotL = 1;
                } 
                else if (NdotL > 0.5)
                {
                    NdotL = 0.6;
                } 
                else if (NdotL > 0.2)
                {
                    NdotL = 0.3;
                } 
                else 
                {
                    NdotL = 0.1;
                }

                // Cdiffuse = (Clight * Mdiffuse)max(0,N^*L^)
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * NdotL;

                return fixed4(ambient + diffuse,1.0);
            }
            ENDCG
        }
    }
}

4.总结

虽然我们完成了一个看起效果还不错的卡通渲染球,但是还是存在很多问题,比如外轮廓不平滑,没有高光效果,只能渲染一些表面平滑并且没有棱角的物体,当然之后通过更深入的研究我们也会继续完善这个卡通渲染效果。

ee3dd6de4a002a9188b6113221a3ad51.png
棱角是没有进行描边的

所有文章的目录

StarryFun:独立游戏爱好者的成长记录​zhuanlan.zhihu.com
844e1bca93a8098ba94431b0b5a6e746.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值