2022
04-13

URP的RenderMaskLayer

今天看源码无意间发现了renderingLayerMask属性,真是解决了一个大问题啊。 比如我有多个角色,希望其中某几个拥有描边效果,此时又不希望写多个Layer层。就可以添加一个RenderMaskLayer。如下图所示。 可以自己扩展一个RenderObjects类。

URP的RenderMaskLayer - 雨松MOMO程序研究院 - 1

RenderObjectsPass.cs

public RenderObjectsPass(string profilerTag, RenderPassEvent renderPassEvent, string[] shaderTags, RenderQueueType renderQueueType, int layerMask, uint renderMask,RenderObjects.CustomCameraSettings cameraSettings)
{
    //..略
    m_FilteringSettings = new FilteringSettings(renderQueueRange, layerMask);

    m_FilteringSettings.renderingLayerMask = renderMask; //在这里设置renderMask
}

RenderObjects.cs

[System.Flags]
public enum RenderLayer
{
    Outline = (1 << 0),
    A2 =  (1 << 1),
    A3 =  (1 << 2),
    A4 =  (1 << 3),
}

[System.Serializable]
public class FilterSettings
{
    public RenderQueueType RenderQueueType;
    public LayerMask LayerMask;
    public string[] PassNames;
    public RenderLayer RenderMask; //添加RenderMask
    public FilterSettings()
    {
        RenderQueueType = RenderQueueType.Opaque;
        LayerMask = 0;
    }
}

public override void Create()
{
    FilterSettings filter = settings.filterSettings;

    //...略
    //传入RenderMask
    renderObjectsPass = new RenderObjectsPass(settings.passTag, settings.Event, filter.PassNames,
        filter.RenderQueueType, filter.LayerMask, (uint)filter.RenderMask, settings.cameraSettings);
}

RenderObjectsPassFeatureEditor.cs 修改面板

void DoFilters(ref Rect rect)
{
    m_FiltersFoldout.value = EditorGUI.Foldout(rect, m_FiltersFoldout.value, Styles.filtersHeader, true);
    SaveHeaderBool(m_FiltersFoldout);
    rect.y += Styles.defaultLineSpace;
    if (m_FiltersFoldout.value)
    {
        EditorGUI.indentLevel++;
        //Render queue filter
        EditorGUI.PropertyField(rect, m_RenderQueue, Styles.renderQueueFilter);
        rect.y += Styles.defaultLineSpace;
        //Layer mask
        EditorGUI.PropertyField(rect, m_LayerMask, Styles.layerMask);
        rect.y += Styles.defaultLineSpace;

        EditorGUI.PropertyField(rect, m_RenderMask, Styles.renderMask);//在这里添加面板
        rect.y += Styles.defaultLineSpace;


        //Shader pass list
        EditorGUI.PropertyField(rect, m_ShaderPasses, Styles.shaderPassFilter, true);
        rect.y += EditorGUI.GetPropertyHeight(m_ShaderPasses);
        EditorGUI.indentLevel--;
    }
}

然后在需要描边的Render上挂脚本,设置它的RenderMask层级

URP的RenderMaskLayer - 雨松MOMO程序研究院 - 2

       GetComponent<Renderer>().renderingLayerMask = (uint)renderLayer;

 

大功告成,两个Cube在同一个层, 但是设置了不同的RenderMask,所以效果不同。

URP的RenderMaskLayer - 雨松MOMO程序研究院 - 3

今天美术又给我来了个灵魂拷问,他们的材质使用的是多维子材质。如下图所示,一个Render上有多个材质,美术同学系统其中某一个才需要描边这种特殊效果,而其他的不需要。开始我想使用CommandBuffer.DrawRender,但是这样就无法使用SrpBatcher里, 由于每个人的Mesh也都不相同,这样就没办法用GPU Instancing了,效率恐怕不会更好,随后想到了这个办法。

URP的RenderMaskLayer - 雨松MOMO程序研究院 - 4

它需要占用一个RenderQueue了,如上图中将需要特殊效果的材质的RenderQueue设置成2001,如果透明就设置成3001,具体数值设置成其他也行就是做一个区分,让管线知道它和其他的不同。(2001和3001也可以根据情况改成其他数值)

public RenderObjectsPass(string profilerTag, RenderPassEvent renderPassEvent, string[] shaderTags, RenderQueueType renderQueueType, int layerMask, RenderObjects.CustomCameraSettings cameraSettings)
{
    //..略
    RenderQueueRange renderQueueRange = (renderQueueType == RenderQueueType.Transparent)
        ? RenderQueueRange.transparent
        : RenderQueueRange.opaque;
    m_FilteringSettings = new FilteringSettings(renderQueueRange, layerMask);

   	//设置需要特殊效果的RenderQueue
    if(renderQueueRange == RenderQueueRange.opaque)
        m_FilteringSettings.renderQueueRange = new RenderQueueRange(2001, 2001);
    else if (renderQueueRange == RenderQueueRange.transparent)
        m_FilteringSettings.renderQueueRange = new RenderQueueRange(3001, 3001);
}

通过这段代码可以强制设置不透明只有2001才会有描边特效效果, 透明只有3001层级才有描边特殊效果。这种方法暂时可以解决问题,但是毕竟还需要修改RenderQueue实际应用中还需要美术同学配合,如下图所示,都是多维子材质,可以选择性开启或关闭覆盖的特殊效果了。

URP的RenderMaskLayer - 雨松MOMO程序研究院 - 5

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

URP的RenderMaskLayer》有 2 条评论

  1. zhhasd说:

    感觉还是不好用,如果我想按照确切的几个物体而不是layer就很麻烦,所以我自己写了个基于list列表来渲染对象的renderfeature,但是深度贴图又有问题,崩溃了。

  2. zhutaorun说:

    能分享下完整的代码吗,最近刚在接触在新项目尝试使用的

留下一个回复

你的email不会被公开。 必填项已用 * 标注。