Unity urp2d ShaderGraph 实现一个黑白转彩色的场景渐变效果 设计思路

Posted Sugarzo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity urp2d ShaderGraph 实现一个黑白转彩色的场景渐变效果 设计思路相关的知识,希望对你有一定的参考价值。

设计背景:

        2022网易MG比赛,策划案里关卡背景是一个信中被损坏的场景,主角要去修复这个场景的故事。然后原本的场景呈现黑白色的效果,但主角旁边画面是彩色的,关卡结局还要有镜头拉远,然后整个画面以主角为中心扩散恢复颜色的视觉效果。

效果展示:

        项目是URP管线,场景为2D SpriteRenderer,使用了shaderGraph,摄像机纹理实现了效果

原场景: 只有一块区域是彩色效果其他黑白:

 游戏实机展示:

设计思路:

         一开始刚拿到这个设计的时候,首先研究如何将画面变灰,很简单啊直接将unity自带的后处理加上color Adjustments,然后saturation拉到最低

        很好效果完美实现,此贴完结(撒花)

       -----------------------------------------------------------------

        咳咳,开个玩笑。后处理只能对整个画面进行处理,而我们的需求是对场景内的一块区域动态处理它的显示效果,所以只能自己去写shader了。

        先想想这个shader是写在屏幕空间呢还是世界空间呢?写在屏幕空间,做一层UI Mask,根据Image贴图和这个像素点的采样决定是否对其做灰色也是一个可行的方法,性能方面也比较优解。但这次我们需要以玩家为中心显示彩色区域,中间也有很多摄像机拉远的游戏逻辑,这时候去做世界空间到屏幕空间的转换也不太方便。因此这里就采用了给场景内的sprite上shader了。

        先实现的变灰色图逻辑吧,本人去网上一顿查找,成功找到了一个shader(这里省去了一些代码,关键看fragment shader的实现)

Tags
         
            "Queue"="Transparent" 
            "IgnoreProjector"="True" 
            "RenderType"="Transparent" 
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        

        Cull Off
        Lighting Off
        ZWrite Off
        Blend One OneMinusSrcAlpha

        Pass
        
            //这里省去了一些代码,关键看fragment shader的实现

            sampler2D _MainTex;
            float _GrayScale;

            fixed4 frag(v2f IN) : SV_Target
            
				if(_Open > 0)
				
					fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
                    //乘以一个灰度系数
				    float cc = (c.r * 0.299 + c.g * 0.518 + c.b * 0.184);  
					cc *= _GrayScale;
					c.r = c.g = c.b = cc;

					c.rgb *= c.a;

					return c;
				
                else
				
				   return tex2D(_MainTex, IN.texcoord) * IN.color;
				
            
        ENDCG
        

        取灰度系数为一,其实里面最核心的一行代码就是:

//c为frag中该点color
c.r = c.g = c.b = (c.r * 0.299 + c.g * 0.518 + c.b * 0.184) * 灰度系数;

        可以看到,变灰度图实际上是在片元着色器中,通过采样后对该点的RGB,对一个系数相乘再相加,做一些转换,最后在统一赋值给rbg实现的效果。

        我们新建一个urp2DLit的ShaderGraph,在里面实现里面同样的逻辑效果,记得主采样贴图的参数的reference要正确设置成_MainTex才可以获取到sprite中的贴图

         接着我们设置如何让画面变彩色。思路很简单先传入一个Vector3参数(世界空间坐标点),判断这个点的距离(float)是否小于一个值,如果是则输出sample Texture原本的color值,如果不是输出灰色转换后的color就好了。

        新建两个参数 ,分别为Vector3和float

        使用Position节点可以在Graph中获取该点位置,在使用Distance节点计算距离后Comparison距离值就好了!

        最后用Branch节点分支    选择该店像素值(当然shader中最好不要用Branch,在GPU中做If的运算开销很大,后面会讲优化)

        写一个脚本再同步一下参数,这里没有用unity的材质属性块MaterialPropertyBlock,因此修改时是直接修改所有材质的参数,如果需要也可以加上。

using UnityEngine;

public class Gray2DController : MonoBehaviour

    public Material material;
    //pos就是场景中需要的彩色点
    public Transform pos;
    //    
    public float distance;

    // Update is called once per frame
    void Update()
    
        if(material != null)
        
            material.SetVector("_Diastance", distance);
            if(pos != null)
                material.SetVector("_Pos", pos.position);
        
    

        去场景里拿一张图测试一下效果

        很好,看起来shader成功运行了起来。很高兴,又写完了一个需求,当天做完后忙其他事情了。

        后几天,美术终于花完了场景最终稿,给我发了场景图层拆分,当我兴奋的搭完场景然后安装上我的材质后,然而:

        我: ???????

        好吧即然出现了问题,就只能继续研究了,随便看看能不能优化下原来的想法。

        即然一张图是没有任何问题的,那就只能是多图情况下的混合模式的问题了。观察最开始CG代码的shader,里面的混合模式是:

Blend One OneMinusSrcAlpha

        ShaderGraph中也可以设置混合模式,然而一顿研究和查找资料后发现:

 

       (这张图的介绍来源Intro to Shader Graph | Cyanilux

        shaderGraph默认的四种混合居然不支持Blend One OneMinusSrcAlpha。那只能走走别的方向了,仔细想想,原来的shader也确实不太完美,因为我们要的是整个画面的黑白,而上面的shader则需要给每个场景物品都安装这个shader跑计算的话,无疑是降低了性能和扩展性的。(因为对于每个物品都要计算一遍距离Distance是很低效的)

        这时候突然想到,如果这个shader混合模式达不到我们想要的效果,而且最好只做一张图片的处理的话,那我们完全可以在场景空间中在贴一张贴图,然后在场景里再放一个摄像机专门渲染这张帖图就行啦,然后玩家的主摄像机只需要渲染这张贴图的图层就好了!(其实这种方法应该早点想到的我是笨比)这样子也解决了性能的问题。

        开始行动!首先我们新建一个Layer

 在项目资源中右键,选择创建一个渲染器纹理

 

         在场景中新建一个相机,这个相机是用来渲染场景物品的并输出到贴图上的,因此在剔除中取消勾选刚刚新建的RendererTexture层,然后将刚刚创建好的Texture加载输出上。

         调整摄像机在场景的位置,选择创建的RenderTexture资源,调整大小,就可以在预览窗口中看到场景样子了(这里我用了场景大小,实际上直接用屏幕分辨率1920*1080,然后将刚刚的摄像机放到主摄像机子物品下做位置同步也是可以的) 

        然后我们修改shader参数,实际上就是把采样的SampleTexture从MainTex改成刚刚的摄像机贴图就好了

         然后我们在场景中新建一个sprite,设置它的layer和大小,然后拖入这个shader材质,我们这个摄像机贴图就做好了。 

        我们回到场景中的主摄像机,可以让它只渲染这个贴图,当然将这个贴图放在场景最前面挡住后面的正常物品也是可以,但是这样运行时渲染管线还要额外做深度剔除的计算所以就可以直接在设置中直接剔除其他的物品。

        这样我们这个效果就成功实现了。最后在来一个优化,还记得我们前面用了if节点,通过距离大小判断选择,这样一是if性能开销大,二是两个色域过渡时也比较尖锐(因为if是简单的二值判断然后选择)

         我们可以放弃if节点,改用lerp在两个色域中做插值,就可以优化渐变效果,插值需要一个0-1的参数,我们选择使用“Saturate”节点,这个节点可以将一个浮点值映射到[0,1]的范围内,即输入大于1时=1,输入小于0时等于0,然后将结果连接到Lerp节点就可以了。

        这样交界就有了一个柔和的过渡了。

最终ShaderGraph连接图:

Unity 之 ShaderGraph入门使用详解

一,ShaderGraph 简介

简介:
Unity2018版本之后推出了一个可编程渲染管线工具ShaderGraph,让我们可以通过可视化界面拖拽来实现着色器的创建和编辑。

官方话术:

Shader Graph 使您能够直观地构建着色器。您无需编写代码,而是在图形框架中创建和连接节点。Shader Graph 提供反映您的更改的即时反馈,并且对于不熟悉着色器创建的用户来说非常简单。

Shader Graph 仅与可编写脚本的渲染管线 (SRP) 兼容,即高清晰度渲染管线 (HDRP) 和通用渲染管线 (URP)。这两个 SRP 在 Unity 2018.1 及更高版本中可用。传统的内置渲染管线不支持 Shader Graph。

Shader Graph是基于可编程流水线, 一种通过节点图的方式,来实现可视化的Shader的编程。
有了它之后我们就不用再编写大量的代码了,不用考虑语法和错误调试了。

使用版本:推荐使用Unity2019.1以上的版本。


二,ShaderGraph 导入

2.1 现有工程导入

点击”Windows“ --> ”Package Manager“ --> “Shader Graph” --> ”Install“ ,点击后等待导入完成即可:

同理在点击Package Manager面板找到 --> “Lightweight RP” 然后点击”Install“导入等待导入完成即可:

2.2 导入指定版本

使用2.1的方式添加,只能导入最新版本的插件,使用下面这个方式可导入一个指定版本:
打开工程目录,找到“Package Manager” 文件夹下的“manifest.json”文件,打开后添加:(注意要指定正确版本)

"com.unity.render-pipelines.lightweight": "7.5.3",
"com.unity.shadergraph": "7.5.3",

2.3 新工程导入

选择LWRP或者HDRP的话,会自动附带相关插件,并且Unity已经帮我们进行了工程基础配置,下面我们要说的工程基础配置:


三,ShaderGraph 配置

若你是以上面2.3新工程的形式创建的工程,则不需要进行下述配置

3.1 基本设置

通过菜单"Asset" --> “Create” --> “Rendering” --> “Universal Render Popeline” --> “Pipeline Asset(Forward Renderer)” 创建URP渲染管线配置

在2019.3版本之后,Unity将轻量渲染管线LWRP重命名为通用渲染管线URP。 所以虽然我们上面导入的是“Lightweight RP”包,但是这边创建的时候显示的是“Universal Render Pipeline”:

设置URP渲染管线配置到“Edit” --> “Project Setting” --> “Graphics” --> “Scriptable Render Pipeline Settings” 如下图所示:

3.2 创建ShaderGraph示例

在“Project”面板右键 --> “Create” --> “Shader” --> “Unlit Graph”; 这时我们可以看到Shader面板上多了几个后缀为Graph的选项:

选择我们创建一个“Unlit Graph”看下效果:

“双击” 就可打开我们创建“Unlit Shader Graph”的可编辑面板:


四,ShaderGraph 面板

4.1 可编辑面板介绍

为了方便操作,此编辑面板支持多开,支持直接从其他面板上复制节点

  • 主节点:决定着色器输出的最终连接:(所有节点经过计算后都必须连接到主节点上,才会得到应用)

  • 预览界面:在这里“右键”,可随意旋转,缩放,以及替换网格:

  • 黑板:在单个收集视图中包含所有着色器属性的区域。使用Blackboard 添加,删除,重命名和排序:(创建属性,然后拖拽到主编辑空白处,形成在材质球上可编辑公开属性)

  • 创建节点:空白处“右键” --> “Create Node” --> 选择要创建的节点:(可选择,可搜索找到要用的节点,子节点非常多,使用过程中慢慢累积)

  • 编辑节点:创建了一个“Color” 节点,在节点上右键,可以看到复制,删除等操作信息

  • 连接节点:单击节点右侧“Out”输出,拖拽到对应的输入上:


五,ShaderGraph 使用

5.1 创建UnlitGraph并创建贴图节点

在“Project”面板右键 --> “Create” --> “Shader” --> “Unlit Graph”; 详细图解创建步骤见上文3.2。

双击创建好的"Unlit Graph",打开编辑界面,空白处“右键” 选择 --> “Create Node” —-> 搜索框搜索“Texture” 点击创建“Sample Texture 2D”:

5.2 给贴图节点赋值并连接到主节点

将Texture节点的输出,拖拽到主节点的输入:

给Texture进行赋值:(和其他组件使用形式一样,点击“原点”选择Texture)

5.3 保存并使用ShaderGraph

点击面板左上角的“Save Asset”,进行保存

然后创建材质球,将其Shader 指定为刚刚保存的“UnlitShaderGraph”:(可直接拖拽赋值)

最后在场景中创建一个Cube,并将其材质球指定为刚创建的:(也可直接拖拽赋值)

这样就完成了一个Shader的从创建到应用整个流程啦~

5.4 公开属性使其在材质球上编辑

细心的你可能已经发现了,在上图材质球使用的贴图位置是不能进行修改的:

下面我们就将贴图属性公开为外部可修改的。

在“Blackboard”面板点击“+”号,添加"Texture 2D"属性,然后将其拖拽到空白编辑区域,最后将其输出节点连接到贴图输入节点上:

然后点击下右上角的“Save Asset”保存一下,再次点击到材质球上,就可以看到贴图位置是空的,并且是可修改的了:

六,ShaderGraph 总结

本文对ShaderGraph进行了简单介绍,使用时需要的工程配置,以及ShaderGraph的编辑面板操作,最后通过一个简单示例进行整体流程的梳理。

使用ShaderGraph前提条件:

  1. 导入ShaderGraph插件
  2. 导入URP(通用渲染管线)或者HDRP(高清渲染管线)
  3. 创建Pipeline Assets并配置到Graphics面板

完成上述准备工作,就可以愉快的使用ShaderGraph了。

以上是关于Unity urp2d ShaderGraph 实现一个黑白转彩色的场景渐变效果 设计思路的主要内容,如果未能解决你的问题,请参考以下文章

unity shader可视化工具——Shader Graph

Unity 之 ShaderGraph 实现全息效果入门级教程

Unity 之 ShaderGraph 实现火焰效果入门级教程

Unity 之 ShaderGraph 实现旋涡(传送门)效果入门级教程

游戏开发创新上班通勤时间太长,做一个任意门,告别地铁与塞车(Unity | 建模 | ShaderGraph | 摇杆 | 角色控制)

游戏开发创新上班通勤时间太长,做一个任意门,告别地铁与塞车(Unity | 建模 | ShaderGraph | 摇杆 | 角色控制)