|
点击下面链接,B站上传了实际Game窗口效果,视频有压缩,实际运行效果更好些~
系列一共5篇,这个是第5篇:
【01】Unity URP 卡通渲染 原神角色记录-Diffuse: Ramp + AO + Double Shadow
【02】Unity URP 卡通渲染 原神角色记录-Specular: Metal+Non-Metal
【03】Unity URP 卡通渲染 原神角色记录-Function-Based Light and Shadow: Emission+SDF脸部阴影
【04】Unity URP 卡通渲染 原神角色记录-Depth-Based Effect: 7Spaces + 屏幕空间等距深度边缘光Rim Light
【05 | 当前浏览】Unity URP 卡通渲染 原神角色记录-Double Pass Effect: Render Feature + 平滑法线Outline
1. 前言
这一篇主要写RenderFeature,以及利用RenderFeature,结合LayerMask进行BackFace描边,同时也会提及平滑法线的计算脚本。
2. Unity URP管线的光栅化Rasterization顺序问题
我们知道图形渲染,主要有光栅化Rasterization,光线追踪Ray Tracing两种路径。这两者不矛盾,可以一起用。
那么Unity URP管线是如何进行光栅化渲染的呢?这里我们重点关注渲染的顺序,为了更好的说明,直接来一段源码吧:
我们发现核心有8个阶段
URP管线的渲染顺序,从代码中可以发现是如下的顺序:
阴影 --> PrePass --> G Buffer --> Deferred Lights(延迟光照) --> 不透明物体 --> 天空盒子 --> 透明物体 --> 屏幕空间后处理
G Buffer说明: 就是把渲染表面Surface所需的所有数据,写入Geometry Buffer,包括材质,位置,法线等
Positions, normals, and materials for each surface are rendered into the geometry buffer (G-buffer) 3. 什么是RenderFeature?
Renderer Feature可让我们向URP Renderer添加额外的渲染通道,支持我们进行Asset资产配置来重写从而可以自定义渲染的顺序、渲染的对象、材质等等。
A Renderer Feature is an asset that lets you add extra Render passes to a URP Renderer and configure their behavior. 也就是说,在上面的渲染顺序中,我们可以加塞,弄一个自己的pass插进去。
这有什么用呢?比如像描边这种事情,肯定都是不透明物体渲染完后,我们再额外描个边,这时候就可以插队到Opaque之后,放一个自己的Pass。
4. 如何创建Render Feature?
URP管线中,有2种方式可以做render feature:
第一种,Render Object
URP contains the pre-built Renderer Feature called Render Objects. 这种方式很简单,点点按钮就好了
选第一个
这种方式,可以参考官方的教程,不是今天的重点:
第二种,Scriptable Renderer Feature
官方有个教程,可以看看
这种方式的核心就是写代码来定义一个Render Feature,我是使用这种方式来定义一个描边pass。
Renderer Feature定义的核心思路:放在Opaque物体之后,用LayerMask只选择人物Layer,因为我们不需要对其他物体进行描边。
把宵宫的人物放在6层,Character
宵宫的人物层index是6
创建脚本的方式可以参考官方教程,重点是override Execute方法这里,确保描边pass只用于宵宫所在的人物层:
ShaderTagId outlineTag = new ShaderTagId("Outline");
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
DrawingSettings drawingSettings = CreateDrawingSettings(outlineTag, ref renderingData, SortingCriteria.CommonOpaque);
int myLayerIndexVariable = 6; // 宵宫的Layer Index
int myLayerMaskVariable = 1 << myLayerIndexVariable; //用于Filter传参
RenderQueueRange myRenderQueueRange = RenderQueueRange.opaque; //只包含不透明物体
FilteringSettings filteringSettings = new FilteringSettings(myRenderQueueRange, myLayerMaskVariable);
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filteringSettings);
}LayerMask成功的之后,我们会发现,只有人物才描边,这里放一个对比图,左边的宵宫在6层,右边的球default:
同样的Shader,只描边人物,描边效果暂时忽略,这会代码是不对的
之后记得在管线设置中,添加这个Render Feature
这里的ShaderTagId 是Outline
5. 法线平滑
有了Render Feature之后,我们就继续下一步,看看如何计算平滑法线。
物体的硬边问题:处于硬边的顶点,会有多条法线存在,如图所示
我们的目标是求多个法线的平均值
所以,平滑法线的核心,就是发现有多个normal的vertex顶点,然后求平均法线,最后把平均法线存进mesh的tangent空间。
如果对于图形学7大空间,有疑惑,请看第4篇,有讲解
核心代码如下,C#脚本,挂在人物身上就行:
for (int i = 0; i < mesh.vertexCount; i++)
{
Vector3 avgNormal = normalDictionary[mesh.vertices].normalized;
tangents = new Vector4(avgNormal.x, avgNormal.y, avgNormal.z, 0f);
}
mesh.tangents = tangents;6. BackFace描边
这个相关的文章挺多了,说一下核心思路:
在正常的UniversalForward Pass渲染完成后,我再加一个额外的Pass,进行顶点沿法线方向偏移,之后输出颜色。
UniversalForward Pass: Cull Back
Outline Pass: Cull Front
这里有一个选择问题,我们在什么空间内,进行顶点偏移,我的选择是Object Space模型空间,效果最好。
然后来看一下相关代码,很简单:
Pass
{
Name &#34;Outline&#34;
Tags {
&#34;LightMode&#34; = &#34;Outline&#34; //与ShaderTagId一致
}
Cull Front
//.....其他参数根据工程需要配置
HLSLPROGRAM
#pragma vertex OutlinePassVert
#pragma fragment OutlinePassFrag
struct Attributes
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
float4 vertColor : COLOR;
float4 tangent : TANGENT;
};
struct Varyings
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 vertColor : COLOR;
};
Varyings OutlinePassVert (Attributes v)
{
Varyings o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
//从tangent space取出平滑法线,进行外扩,处理硬边断裂
v.vertex.xyz += v.tangent.xyz * 0.01 * _OutlineWidth * v.vertColor.a;//顶点色a通道控制粗细
o.pos = TransformObjectToHClip(v.vertex.xyz);
o.uv = v.uv;
o.vertColor = v.vertColor.rgb;
return o;
}
float4 OutlinePassFrag(Varyings i) : SV_TARGET
{
return float4(i.vertColor, 1) * _OutlineColor;//顶点色rgb混合描边颜色
}
ENDHLSL
}接下来,我们看几个效果图的对比,首先是没有平滑法线的样子,只有正常的法线normal
身体的部分,差点意思
然后是从tangent空间,取出平滑法线后再描边,我们可以发现硬边区域的描边,有了很大改善
硬边区域,差别明显,还是平滑好使
最后额外提一句,脖子上的金属项链,不要描边,我是通过宏+Mask,扣掉了蝴蝶项链的大部分神之眼的描边,以下是反例,如果直接输出颜色大概长下面的样子:
项链和神之眼,不要描边,会很怪
7. 后处理ToneMapping,物理模拟和动画
后处理的部分,我通过Render Feature + Blit方式,添加了GranTurismo的ToneMapping,Unity URP默认只有Neural和ACES两种,不太给力。
动作可以去Mixamo上面白嫖,物理模拟用的Magica Cloth,骨骼和弹簧模拟2种类型的结合。
8. 来看看最终成品效果
看着还行吧,有待进一步提升
https://www.zhihu.com/video/1542407530570989568
本篇是这个系列的最后一篇,感谢阅读,后面有空再写写其他的,完结撒花ヽ(°▽°)ノ
9. 参考链接
Unity官方:URP系列教程 | 手把手教你如何用Renderer Feature
Unity官方:URP系列教程 | 如何使用Scriptable Renderer Feature来自定义后处理效果
2173:【01】从零开始的卡通渲染-描边篇 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|