URP 外边框效果:基于Cull 剔除和法线扩展

| 分类 游戏开发之unity  好好玩游戏  | 标签 游戏  Unity  URP  Shader  SubShader  外边框  风格化渲染 

先看一下效果

猴头描边问题

通过上面的效果展示,可以看到第一个猴头和第二个猴头的描边效果不同,原因如下

如上图,第一个猴头在Unity 中的Transform 的Scale 是(1, 1, 1)

而第二个猴头在Unity 中的Transform 的Scale 是(100, 100, 100)

其中因为第一个猴头从Blender 导出的时候勾选了【应用变换】,而第二个没有勾选

首先Blender 默认是没有单位的,而Unity 的单位是米,这个是主要的原因!

注意后面几篇文章的猴头也是一样的,请关注渲染效果

Cube 和其他的不同

因为是通过沿着法线方向往外扩展,而Cube 在8 个尖处的法线不平滑的,所以向外扩展是有问题的

为了解决这个问题,可以使用将模型放大的方式,也就是下一篇会介绍到的

再看后续的其他实现的时候,也请关注Cube 这种有“尖”的模型和其他“圆润”模型的渲染效果的区别

法线在哪个空间扩展

在下面的代码中,可以看到第二个Pass 中,法线的扩展是在裁剪空间做的

需要注意的是,如果选择在模型空间外扩,就会出现这样的问题:远近描边的粗细是不同的。因为在裁剪之前做的变换,最后长度都会符合世界空间下因为相机透视造成的近大远小的效果

当然也可以改成在模型空间做法线扩展,然后实际在Unity 中看一下效果

v.vertex.xyz += v.normal * _Outline;
o.pos = UnityObjectToClipPos(v.vertex.xyz);

但是好像下面代码中的实现,当模型离相机很远的时候,描边也会变细,当模型离相机很近的时候,描边也会变粗?!

代码演示

Shader "Unlit/Outline_Cull_Normal"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color("Color", Color) = (1, 1, 1, 1)
        _RefValue("Stencil RefValue", Int) = 1
        _Outline("Outline Width", Range(0, 0.2)) = 0.05
        _OutlineColor("Outline Color", Color) = (0, 0, 0, 1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"}

        // 渲染固定颜色(缺少光照模型、贴图处理等)
        Pass
        {
            Cull Back

            Tags { "LightMode" = "SRPDefaultUnlit" }

            CGPROGRAM

            fixed4 _Color;

            #pragma vertex vert
            #pragma fragment frag

            float4 vert (float4 v : POSITION) : SV_POSITION 
            {       
                return UnityObjectToClipPos(v); 
            }

            float4 frag() : SV_Target 
            { 
                return _Color;
            }

            ENDCG
        }

        // 渲染偏大用于描边效果黑色模型
        Pass
        {
            Cull Front

            Tags { "LightMode" = "UniversalForward" }

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 pos : SV_POSITION;
            };

            fixed _Outline;
            fixed4 _OutlineColor;

            v2f vert (a2v v) 
            {
                v2f o;

                float4 pos = mul(UNITY_MATRIX_MV, v.vertex); 
                float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);  
                normal.z = -0.5;
                pos = pos + float4(normalize(normal), 0) * _Outline;
                o.pos = mul(UNITY_MATRIX_P, pos);

                return o;
            }

            float4 frag(v2f i) : SV_Target 
            { 
                return float4(_OutlineColor.rgb, 1);               
            }

            ENDCG
        }
    }

    FallBack "Diffuse"
}



如果本篇文章对您有所帮助,您可以通过微信(左)或支付宝(右)对作者进行打赏!


上一篇     下一篇