209 字
1 分钟
卡通渲染中的描边
法线外扩
基本原理
原理是渲染两次,第一个 Pass 正常渲染正面,将背面剔除,第二个 Pass 将正面剔除后先将背面顶点沿着法线的方向移动,外扩后再渲染背面,
最后两个 Pass 叠加在一起。
Unity 实现
渲染正面
Shader "nekoside/default"{ Properties { _BaseColor("BaseColor", Color) = (0, 0, 0, 1) }
SubShader { Tags { "RenderType" = "Opaque" "Queue" = "Geometry" }
// 渲染正面 Pass { Cull Back HLSLPROGRAM #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #pragma vertex vert #pragma fragment frag
CBUFFER_START(UnityPerMaterial) half4 _BaseColor; CBUFFER_END
struct Attributes { float3 positionOS : POSITION; };
struct Varyings { float4 positionHCS : SV_POSITION; };
Varyings vert(Attributes IN) { Varyings OUT; OUT.positionHCS = TransformObjectToHClip(IN.positionOS); return OUT; }
half4 frag(Varyings IN) : SV_Target { half4 OUT; OUT = half4(_BaseColor.rgba); return OUT; } ENDHLSL } }}渲染背面(描边)
Shader "nekoside/outline"{ Properties { _OutlineColor ("Outline Color", Color) = (1, 1, 1, 1) _OutlineWidth ("Outline Width", Range(0, 0.5)) = 0.25 }
SubShader { Tags { "RenderType" = "Opaque" "Queue" = "Geometry" }
// 渲染背面(描边) Pass { Cull Front HLSLPROGRAM #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #pragma vertex vert #pragma fragment frag
CBUFFER_START(UnityPerMaterial) half4 _OutlineColor; float _OutlineWidth; CBUFFER_END
struct Attributes { float3 positionOS : POSITION; float3 normalOS : NORMAL; };
struct Varyings { float4 positionHCS : SV_POSITION; };
Varyings vert(Attributes IN) { Varyings OUT; IN.positionOS += _OutlineWidth * IN.normalOS; OUT.positionHCS = TransformObjectToHClip(IN.positionOS); return OUT; }
half4 frag(Varyings IN) : SV_Target { return _OutlineColor; } ENDHLSL } }}因为 Unity 默认不会渲染所有 Pass(因为会对性能造成影响),所以我这里把两个 Pass 拆分为两个 Shader,一共使用两个 Material.

描边断开
直接使用刚刚的 Shader 会变成这样

因为法线外扩得到的描边,会导致模型的硬边(比如这个立方体)连接处断开
解决方法是生成平滑法线

修改 Smoothing Angle
效果如下

相关文章 智能推荐
