Shader Graph 期望主节点中顶点输入的对象空间,在幕后将其转换为剪辑空间。所以如果你想用 ClipSpace 做一个效果,必须手动转换成 ClipSpace,转换回 Object Space ,然后 Shader Graph 再转换成 ClipSpace 。

你会在剪辑空间中创建网格的副本,然后使用法线扩展 x 和 y 使其更大。然后将 z 从相机推开,使其始终呈现在后面。
如果打开 噪波 选项,它将添加投影到顶点数据上的纹理结果,以获得更卡通的轮廓效果。
带注释的着色器代码:
Shader "Toon/Ice Effect" {
Properties{
_TColor("Top Color", Color) = (0.64,0.94,0.64,1)// top gradient, light green
_Ramp("Toon Ramp (RGB)", 2D) = "gray" {}
_BottomColor("Bottom Color", Color) = (0.23,0,0.95,1)// bottom gradient, blue
_RimBrightness("Rim Brightness", Range(3,4)) = 3.2 // ice rim brightness
}
SubShader{
Tags{ "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf ToonRamp
sampler2D _Ramp;
// custom lighting function that uses a texture ramp based
// on angle between light direction and normal
#pragma lighting ToonRamp
inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
{
#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif
half d = dot(s.Normal, lightDir)*0.5 + 0.5;
half3 ramp = tex2D(_Ramp, float2(d,d)).rgb;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
c.a = 0;
return c;
}
float4 _TColor;
float4 _BottomColor;// bottom gradient color
float _RimBrightness;// ice rim brightness
struct Input {
float3 viewDir; // view direction
float3 worldPos; // world position
};
void surf(Input IN, inout SurfaceOutput o) {
float3 localPos = saturate(IN.worldPos - mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz) + 0.4;// local position of the object, with an offset, clamped to make sure it doesn't go into negative
float softRim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));// calculate a soft fresnel based on the view direction and the normals of the object
float hardRim = round(softRim); // round it up for a harder edge
o.Emission = _TColor * lerp(hardRim, softRim, (localPos.x + localPos.y)) * (_RimBrightness*localPos.y); // lerp the emission from the hard rim to the softer one, based on the position
float innerRim = 1.5 + saturate(dot(normalize(IN.viewDir), o.Normal)); // softer inner rim
o.Albedo = _TColor *pow(innerRim, 0.7)*lerp(_BottomColor, _TColor, localPos.y); // multiply the main color by the inner rim, multiply that by the gradient color lerp
}
ENDCG
}
Fallback "Diffuse"
}
硬法线问题

所以这个着色器使用法线来膨胀网格,这对于平滑法线模型非常有效,但对于硬法线模型则不太适用。

你还可以将轮廓基于顶点位置,这在某些情况下效果更好。
在这两种方法之间添加了一个滑块,这不是一个很好的解决方案。
设置
URP 不支持多通道着色器,因此无法使用该选项,但我们还有其他 2 个选项:
方法 1 使用渲染器功能

找到 通用渲染管线资源,可以在 Edit > Project Settings > Graphics 中快速找到它

从 Universal Render Pipeline Asset 转到 Forward Renderer Data 资产

在底部,转到 添加渲染器功能 并选择 渲染对象

给它一个名字,将它设置为 Event – AfterRenderingOpaques
为将使用轮廓效果的任何对象创建一个新图层,并在此处将其设置为图层蒙版。(不要忘记将对象设置到这一层)
将从链接着色器代码制作的材质分配给 Material Override。
这是一个非常快速的设置,但对于每个对象都是相同的,没有针对每个对象的设置。
方法2:使用第二种材质
在 Mesh Renderer 中,转到 Materials 数组,并从链接的着色器代码中添加Unity材质。

对于实际上无法做到的多通道非常有趣,但是对于这种效果应该没问题。
这更难处理,因为必须为每个想要有轮廓的对象设置额外的效果,但可以为每个对象设置不同的设置。
对于这个 Inky Effect Outline,只需使用渲染器功能就可以了。其他轮廓很快就会出现,只是将它们分开以便于搜索!