【Unity URP】探讨描边方案 自定义后处理Volume

这篇具有很好参考价值的文章主要介绍了【Unity URP】探讨描边方案 自定义后处理Volume。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

本篇内容实现了在URP下获取深度、法线实现描边的后处理描边之前做的工作,包括讨论描边方案,以及写shader之前的自定义renderFeature和Volume组件的过程。

由于是想复刻《SCHiM》游戏里的画面风格,所以本篇文章的需求很明确,会夹杂一些自己的分析思考,并不是严格意义上的分享某一种描边技术的文章,更多的是个人的记录。

由于URP各个版本更新换代太快了,贴一下项目环境,给后面看到这篇文章的小伙伴提个醒,我的项目环境:

URP12.1.7

Unity2021.3.8f1


 1 明确描边需求

1.1 分析

 之前学习《入门精要》的时候就实现过基于Sobel算子的边缘检测描边效果:【Unity Shader】屏幕后处理2.0:实现Sobel边缘检测,这是一种基于颜色信息进行描边的方法,再来回顾一下效果:

【Unity URP】探讨描边方案 自定义后处理Volume

【Unity URP】探讨描边方案 自定义后处理Volume

简单总结一下这个实现的效果:

  • 除了边缘,物体的纹理有明显过渡的地方也会描边
  •  阴影也会被描边

在实现任何效果之前,我们需要明确需求,再提出合理的渲染方案,才是一个正确的思路。

这里再明确一下需求,由于我是有针对性地复刻游戏画面,我希望:

  • 最基础的,给物体边缘描边
  • 阴影虽然也有描边,但是阴影描边颜色是可控的,粗细也是额外控制的,因此阴影不能被后处理描上边
  • 最后,其实也是最特别的,游戏中出现了很多如下的平面的、简单的描边效果:

【Unity URP】探讨描边方案 自定义后处理Volume

进行场景分析的时候也总结过:

【Unity URP】探讨描边方案 自定义后处理Volume

所以上述需求,单纯的Sobel算子边缘检测无法满足需求。

1.2 提出实现方案

场景中阴影描边自己来,通过shadow值step就行,不赘述。

主要是场景中的那些装饰性的框框怎么实现。想了很久,最后定了一种可行的方案——基于Mask图进行Sobel算子边缘检测描边,然后场景中的物体描边采用深度+法线纹理后处理描边法解决。

2 基于Mask图的描边

原理大概是:场景中色彩不是很复杂,是单色Shading,按理来说纹理是不需要的。这里我们就不传递sRGB的颜色纹理,选择传递储存Mask信息的单通道纹理。

纹理需要在建模阶段,给场景中对应的物件进行特别的绘制,例如地面的斑马线、花坛的小砖块等等,纹理类似这样:

【Unity URP】探讨描边方案 自定义后处理Volume

由于我还没开始准备场景中的模型贴图等资产,只能先随便简单画几个框框,看看铺在地面上的效果。

接下来我们进行正常的Sobel算子边缘检测,完全跟之前的实现过程一样,最后也是获得一个edge参数:

【Unity URP】探讨描边方案 自定义后处理Volume

接下来

【Unity URP】探讨描边方案 自定义后处理Volume

中间还需要把阴影考虑进去,再得到最后的值:

【Unity URP】探讨描边方案 自定义后处理Volume

最后的效果(观察地板上的描边):

【Unity URP】探讨描边方案 自定义后处理Volume

这样,场景中装饰性的平面上的描边效果,就实现了,并且还不是后处理,而是包含在了基本着色的Pass里。

接下来就是基于深度和法线的描边了,这里就开始了后处理描边的实现。我希望给他写成一个可以在Volume面板看到的一个后处理效果,所以可能步骤相对繁琐,需要脚本和shader之间的参数传递。先来回顾一下Volume组件:

3 URP下的后处理

URP下后处理都塞在了一个叫做Global Volume的组件中,我们右键可以创建出来:

【Unity URP】探讨描边方案 自定义后处理Volume

挂到场景中后,可以在Volume下Add Override添加一些URP内置的后处理效果:

【Unity URP】探讨描边方案 自定义后处理Volume

这些内置的后处理效果,Volume控制脚本都放在了这儿:

【Unity URP】探讨描边方案 自定义后处理Volume

打开个Bloom后处理面板跟脚本对着看看:

【Unity URP】探讨描边方案 自定义后处理Volume

会发现仅仅是可视化了面板,这个cs脚本再跟相应的RenderFeature想匹配,我们就可以实现Volume组件里控制后处理效果了!

4 自定义Volume

我们可以仿照这自定义一个Outline Volume组件,当然,这个Outline组件具体需要什么参数,只有写完shader之后才能明确知道,文章其实也是写完pass之后再回来补充的,所以直接给出Volume的脚本:

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

namespace UnityEngine.Rendering.Universal
{
    [Serializable,VolumeComponentMenu("My-post-processing/Outline")]
    public class OutlineVolume : VolumeComponent, IPostProcessComponent
{
    [Tooltip("边缘颜色")]
    public ColorParameter  OutlineColor = new ColorParameter(Color.white);
    [Tooltip("边缘检测大小")]
    public ClampedFloatParameter Scale = new ClampedFloatParameter(1f, 0f, 10f);
    [Tooltip("深度")]
    public ClampedFloatParameter DepthThreshold = new ClampedFloatParameter(0.2f, 0f, 10f);

    [Tooltip("法线深度")]
    public ClampedFloatParameter NormalThreshold = new ClampedFloatParameter(0.4f, 0f, 1f);
    public ClampedFloatParameter DepthNormalThreshold = new ClampedFloatParameter(0.5f, 0f, 1f);
    public ClampedFloatParameter DepthNormalThresholdScale = new ClampedFloatParameter(7f, 0f, 10f);


    public bool IsActive() => Scale.value > 0;

    public bool IsTileCompatible() => false;

}
}

这样就能在自定义路径下添加组件了。

当然这仅仅是写参数,还需要自定义一个实现方法。我们用RenderFeature来实现,完全把URP内置的实现路径和我们自定义的后处理过程剥离开,下一步就是自定义RenderFeature了。

5 自定义RenderFeature

刚接触URP的时候,一直不想去用RenderFeature,,觉得很麻烦,这次静下心来扒了一下整个过程,感觉还是足以理解的!

学习,我主要参考unityURP管线学习+后处理这篇文章最后的Volume相关的内容,最后的定义过程,参考了URP | 后处理-描边和Unity Outline Shader Tutorial,学习并实现了RenderFeature和Volume面板,完成的话接下来就能安心写主要的shader内容了:

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;


public class OutlineRenderFeature : ScriptableRendererFeature
{
    [System.Serializable]
    // 定义3个共有变量
    public class Settings
    {
        //public Shader shader; // 设置后处理shader
        public Material material; //后处理Material
        public RenderPassEvent renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing; // 定义事件位置,放在了官方的后处理之前
    }

    // 初始化一个刚刚定义的Settings类
    public Settings settings = new Settings(); 
    // 初始化Pass
    OutlinePass outlinePass;

    // 给pass传递变量,并加入渲染管线中
    public override void Create()
    {
        this.name = "OutlinePass"; // 外部显示的名字
        this.
        outlinePass = new OutlinePass(settings.renderPassEvent, settings.material);
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        renderer.EnqueuePass(outlinePass);
    }

    
}

public class OutlinePass : ScriptableRenderPass
{
    static readonly string renderTag = "Post Effects"; // 定义渲染Tag
    Material tmaterial;
    OutlineVolume outlineVolume;  // 传递到volume,OutlineVolume是Volume那个类定义的类名
    public OutlinePass(RenderPassEvent evt, Material tmaterial)
    {
        renderPassEvent = evt; // 设置渲染事件位置
        //var shader = tshader;  // 输入shader信息
        var material = tmaterial;
        if (material == null)
        {
            Debug.LogError("没有指定Material");
            return;
        }
    }

    // 后处理逻辑和渲染核心函数,相当于build-in 的OnRenderImage()
    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        // 判断是否开启后处理
        if (!renderingData.cameraData.postProcessEnabled)
        {
            return;
        }

        // 渲染设置
        var stack = VolumeManager.instance.stack;             // 传入volume
        outlineVolume = stack.GetComponent<OutlineVolume>();  // 拿到我们的volume
        if (outlineVolume == null)
        {
            Debug.LogError("Volume组件获取失败");
            return;
        }

        var cmd = CommandBufferPool.Get(renderTag);     // 设置渲染标签
        Render(cmd, ref renderingData);                 // 设置渲染函数
        context.ExecuteCommandBuffer(cmd);              // 执行函数
        CommandBufferPool.Release(cmd);                 // 释放
	}
	void Render(CommandBuffer cmd, ref RenderingData renderingData)
    {
        RenderTargetIdentifier source = renderingData.cameraData.renderer.cameraColorTarget;                 // 定义RT
        RenderTextureDescriptor inRTDesc = renderingData.cameraData.cameraTargetDescriptor;
        inRTDesc.depthBufferBits = 0;                                                                          // 清除深度

        var camera = renderingData.cameraData.camera;                         // 传入摄像机
        Matrix4x4 clipToView = GL.GetGPUProjectionMatrix(camera.projectionMatrix, true).inverse;

        tmaterial.SetColor("_Color", outlineVolume.OutlineColor.value);   // 获取value 组件的颜色

        tmaterial.SetMatrix("_ClipToView", clipToView);   // 反向输出到Shader

        tmaterial.SetFloat("_Scale", outlineVolume.Scale.value);
        tmaterial.SetFloat("_DepthThreshold", outlineVolume.DepthThreshold.value);
        tmaterial.SetFloat("_NormalThreshold", outlineVolume.NormalThreshold.value);

        tmaterial.SetFloat("_DepthNormalThreshold", outlineVolume.DepthNormalThreshold.value);
        tmaterial.SetFloat("_DepthNormalThresholdScale", outlineVolume.DepthNormalThresholdScale.value);

        int destination = Shader.PropertyToID("Temp1");

        // 获取一张临时RT
        cmd.GetTemporaryRT(destination, inRTDesc.width, inRTDesc.height, 0, FilterMode.Bilinear, RenderTextureFormat.DefaultHDR); //申请一个临时图像,并设置相机rt的参数进去

        cmd.Blit(source, destination);                            // 设置后处理


        cmd.Blit(destination, source, tmaterial, 0);
    }
}

体现在面板上就是:

【Unity URP】探讨描边方案 自定义后处理Volume

关于展示到面板部分的内容,需要给定义的结构体前加上[System.Serializable]

我发现,如果只是创建一个RenderFeature脚本,跟URP下创建shader一样,函数啥的都缺胳膊少腿的,为什么不像创建URP Shader模板那样,也创建一个带有Pass的RenderFeature脚本模板呢!

然后我就写了个模板:

【Unity URP】探讨描边方案 自定义后处理Volume

用的话Asset->Rendering->MyRenderFeature,就能创建自定义的模板啦! 

那么下一步,就是写shader了!明天继续!

参考

如何扩展Unity URP的后处理Volume组件 (zhihu.com)

Unity Outline Shader Tutorial - Roystan文章来源地址https://www.toymoban.com/news/detail-413278.html

到了这里,关于【Unity URP】探讨描边方案 自定义后处理Volume的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity 后处理(Post-Processing) -- (3)挑战:创建局部后处理Volume 为何使用局部Volume

            在前面两节中,我们使用了一个Global Volume来应用后处理,其作用范围是整个场景。有些时候,我们需要实现当角色靠近某个地点后,进行一些特殊的后处理。这时我们就需要使用Local Volume来实现这个功能。         举个例子,在某些游戏中,当角色不小心进入了

    2024年02月10日
    浏览(33)
  • 8、URP自定义屏幕后处理

    回到目录 大家好,我是阿赵。这次来说一下URP渲染管线里面怎样使用后处理效果,还有怎样去自定义后处理效果。 要使用URP自带的后处理效果,方法很简单,和Unity内置渲染管线的PostProcessing后处理很类似的,在一个物体上面添加一个Volume脚本。 这个脚本的整体用法和PostP

    2024年02月06日
    浏览(22)
  • [Unity]给场景中的3D字体TextMesh增加描边方案一

    取你的文本对象,简单地添加以下脚本:

    2024年02月05日
    浏览(29)
  • 【Unity】URP屏幕后处理UI模糊效果实现

     这里Canvas(1)设置为Overlay能渲染出指定UI高清,其他UI模糊,然而这做法非常不好,如果此时再打开UI 以及 关闭模糊效果 要将这些置顶UI 恢复到原本Canvas里,也就是要管理2套Canvas Shader代码实现模糊  1个Canvas和2个摄像机 主要以上内容,实际上就是因为Render Pass Event是只能Af

    2024年02月10日
    浏览(30)
  • unity 建立urp项目并使用后处理技术的方法

    Unity URP是Unity官方提供的轻量级渲染管线,它旨在为移动平台和低端PC提供高效的渲染解决方案。相较于传统的渲染管线,URP使用了一些新的技术和算法来提高渲染效率和质量。URP还支持可编程渲染管线(Shader Graph)和更加直观的后处理效果。在使用URP时,可以通过调整一些参

    2024年02月16日
    浏览(36)
  • 【Unity URP】Rendering Debugger和可视化MipMap方案

    写在前面 最近开始学习Unity性能优化,是结合了《Unity游戏优化》这本书和教程《Unity性能优化》第叁节——静态资源优化(3)——纹理的基础概念一起学习。在学习纹理优化部分时候遇到了问题,固定管线下Unity的Scene窗口有一个可视化Mipmap的渲染模式: 而这批Miscellaneous模式的

    2024年02月04日
    浏览(41)
  • 《Unity的URP项目中使用自定义shader导致材质消失的解决办法》

            在Unity中使用URP时,会有需求使用自定义的一些shader来实现特殊效果,这时如果我们直接使用新建材质与无光照着色器(Unlit shader),可能会发生一个对于新手而言意料之外的问题—— 物体!消失了!         打开你正在使用的的 通用渲染器(Universal Rendere

    2024年02月06日
    浏览(46)
  • 【Unity Shader Graph URP渲染管线下的自定义半透明效果_半透明案例分享】

    URP的渲染管线下 在项目设置里找到“Graphic” 找到URP Asset文件 索引到Renderer List文件——“ForwardRenderer” 在这个“ForwardRenderer”文件里找到“Add Renderer Feature” 添加一个渲染对象,类似下图:Render Object (Experimental) 如图设置,将“Event”设置成 AfterRenderingSkybox ,然后“Layer M

    2024年02月09日
    浏览(46)
  • Unity Shader 学习笔记(4)URP渲染管线带阴影PBR-Shader模板 -- 新增可自定义阴影颜色

    材质面板截图 功能实现(URP渲染管线下): 1、进一步优化Shader结构和算法; 2、包含PBR材质; 3、投射和接收阴影,并升级 支持自定义阴影颜色 ; 4、支持点光源照射(但不支持点光源阴影)。 通用渲染截图 自定义阴影颜色截图 完整代码: 写在最后: 1、在我的上一篇文

    2024年02月12日
    浏览(29)
  • unity shader 实现通用描边shader -文字描边-字体描边

    在制作游戏时,可以遇到要对字体添加描边的需求,unity 的UGUI自带的OutLine组件,描边效果不好,宽度过大会出现穿帮,顶点数量也会增加,性能不好,如果对于有几百字,顶点数量会很多,而且无法扩展功能 可以看出Outline创建了4个方向的文字 Unity5.2以前的版本要求,每一个Canvas下至多

    2024年02月03日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包