啊咧咧,从大学毕业开始,有一段时间没有更新过博客了,很怀念当初边学习边写博客的时光。今天打开博客网站看着各位大神通过文字来分享自己的技术心得,也手痒了,决定也来一篇!
说完上面的话,感觉自己像是大佬一样。嘿嘿,然而本篇文章还是一个小白文,就是Shader Graph
的入门知识,一个简单的物体溶解效果,意在帮助新手了解Shader Graph
这个工具。效果如下图,如果你感兴趣,可以看看后面的实现方式,然后来试试吧!
注:本项目Unity
版本为2021.1.12f1c1
为了使用Shader Graph
这个工具,我们首先需要配置一下开发环境,由于目前的Shader Graph
一般应用在Urp
或Hdrp
的可编程渲染管线模板下,所以我们要在项目中使用Urp
或者Hdrp
插件,具体的配置方法有下面两种
第一种:
在我们创建项目时,通过Unity Hub
直接创建一个由Unity官方提供的Urp
或者Hdrp
的模板。
创建方式为打开Unity Hub
,然后点击创建,选择Urp
模板创建即可:
第二种:
点击Unity
编辑器导航栏的Window
菜单,并在其中找到Package Manager
点击,即可打开资源包管理器面板,我们可以在这里面管理项目中的插件,或者安装一些Unity
官方提供给我们的插件。
在本案例中,我们需要安装一个名为Universal RP
的插件
如图所示,通过搜索Universal RP
,可以找到Urp
的插件,通过左下角的安装按钮可以将其导入到项目中,然后需要对项目的渲染管线进行一系列的配置,具体的配置可以查看之前的文章:
文章链接:
- Unity 升级项目到Urp(通用渲染管线)以及画面后处理
完成上面的环境配置后,就可以在project面板右键选择创建,然后选择Shader,并在其中找到Blank Shader Graph
(注意,我使用的是2021.1.12f1c1
版本的Unity
,更早版本可能没有这个选项,可以选择PBR Shader
)并点击创建一个Shader Graph
:
命名为Dissolve
,创建完成后,我们可以在编辑器中找到一个与刚刚创建的Shader Graph
命名相同的窗口,接下来就可以在这里面实现一些连连看的操作了。
在创建完之后,可以在窗口中看到下面图片中的一些内容,大概可以分为四个内容区域,我自己也对其进行了一些命名方便大家理解:
四个具体区域:
public int i
一样创建一个变量i
,然后就可以在Inspecter
面板对该变量进行调整Inspecter
面板,可以对变量添加区域的一些变量进行数量或者进行调整了解完整个Shader Graph
面板的基本结构,就可以开始通过该功能来实现一些效果了,终于来到了正题。
在属性调整区域(Graph Inspector
)里面选择Graph Setting
中找到Active Empty
,初始时我们可以看到上面显示List is Empty
,很明显,我们需要新建一个,点击加号添加一个Universal
,就可以在下面的内容中调整我们需要的Shader
类型属性:
如果你经常为模型调整材质,相信你对这些参数一定不会陌生,如果你不了解也没有关系,下面列出一些关键的参数来帮助你去调整自己的Shader:
Material
:有四个选项Lit
(受光:接受光照影响)、UnLit
(不受光照影响,UI元素常常是UnLit
)、Sprite lit
与Sprite UnLit
则多应用于2D场景Workflow
:有镜面(Specular
)与金属度(Metallic
)Surface
:Transparent
(透明)、Opaque
(不透明)Alpha Clip
:透明通道裁切(小于该值的透明通道归零)在创建完Universal
后,可以发现在节点编辑区出现了最终的输出面板
实现物体的溶解效果,在本项目中是通过修改物体材质的透明度实现的,既物体材质的Alpha
通道,但是如何修改才能确保物体准确的溶解呢。
要实现这样的效果,需要通过一个关键的节点来实现该功能:
Simple Noise
(噪波节点):根据UV
生成简单的噪波,可以利用其随机的确定物体不同位置的透明度,而且如果仔细观察噪波图,会发现透明度高与透明度低的地方是渐变的,而不是截断的(要理解这一含义,可以从水波的效果来思考,任意相邻的两点之间是连续的,而不可能存在横截面)为什么噪波的分布是渐变的,可以通过官方文档看出:
- 在两个决定的UV坐标点之间的的噪波强度的计算为插值计算,而不是随机产生:
到这里,你可能不太理解,这样一张噪波图为什么能做到溶解的效果,如果仅仅通过其来改变物体的透明度,怎么形成变化的溶解呢
其实很简单,首先我们定义一个从零到一变化的值,然后利用这个值对噪波图进行处理,高于这个值的区域设置其Alpha
为一,而低于这个值的区域则为零,这样,随着这个值的不断增大,直到大于一的时候,物体透明的区域逐渐增大至全部。这一过程就是实现溶解的方式
可以举这样的一个例子,白蛇传中水漫金山,你从一张等高图中看到的场景是什么样子的呢,水慢慢的占满了整个地图,如何占据的呢,就是根据一条条等高线逐渐的蔓延:
类似如图,噪波图里面的透明度也会形成一条条这样的线,在溶解时,透明度小的线先消失,直到最大为1的线消失。
如果你看了上面的介绍,有可能会觉得很麻烦。我要如何修改Alpha呀,这怎么可能去使用一个值来分割出来不同的透明度区域,而且还要归一或者归零。
如果你有这些问题哈哈哈,那说明你真的是新手,Shader Graph
作为一个专门编辑Shader
的工具,为我们封装了许多许多的方法来帮助我们开发,在本案例中,会有几个节点很方便的帮助我们来实现这样的效果:
Time
:可以帮助我们生成一个变化的数值Step
:本质上是一个bool类型判断节点,但是返回的是0或1,而且判断条件也是比较两个数值的大小Remap
:用来重新映射一个区间范围,比如说将从0到10的数字映射到从0到1add
:加法Multiply
:乘法不多废话了,简简单单的一个溶解效果,结果让我说了这么多废话
如果你对原理不感兴趣,上面全是废话,下面直接开始效果实现的教程
1,更改Universal选项
前面我们添加了一个Active Targets,但是你会在Fragment(片元着色器)中发现没有Alpha通道,而我们要对透明通道进行裁切,所以我们需要在Universal中将Alpha Clip中勾选上:
如上图,我们在右边设置完毕后,左边的Fragment
会多出两个输入项,一个是Alpha
用来控制透明度,而另外一个Alpha Clip Threshold(1)
则是我们上文说到的实现截断功能的输入。当Alpha
小于Alpha Clip Threshold(1)
时,则物体会直接透明,若大于该值时,不处理
注意:
- 如果是不透明物体,不要尝试将Surface选项更改为Transparent(透明),如果设置为透明,物体会未溶解部分会出现半透明的情况
2,为物体添加材质
首先说明一下如何添加一个输入:在变量添加区域点击加号,即可添加一个变量,变量的类型有Float
、Color
、Texture
等等
创建一个Texture
输入变量,拖入到节点编辑区,点击后可以在属性调整区添加一张贴图。并连接一个材质节点Sample Texture 2D
节点,连接好后,将该节点的输出连至Base Color(3)
,如图:
3,溶解效果的实现
之前说过,溶解效果需要一张噪波图与一个0到1的变化的数值(通过Time
节点的Sine Time
产生,同时使用),具体的连线如图:
注:
Sine
节点本质是一个Sin
函数,我们知道sin
函数是一个y值为-1到1的一个循环的曲线,x是由Unity
的Time
来决定的,所以会随着时间变化持续的输出-1到1
如果你观察了预览区,你就可以发现,预览小球已经有了溶解的效果,What?这么简单?仅仅三四个节点,就可以实现一个高级的溶解效果。
这就是Shader Graph
的优势,对于一些比较成熟的效果有着比较高的封装性,只需要简单的拖拽就可以完美的实现,但是不够灵活,对于一些创造性的活动就需要大量的工作
4,为溶解边缘加高光
完成上一步后,似乎和卖家秀不太一样呀,好像缺了点什么?
好像是边缘没有光呢,没错,由于溶解边缘没有光,质感下降了许多,通过下面的操作,可以为其添加一些边缘光:
在上面的图示中,添加了一个Color
类型的输入变量,用来控制边缘的颜色,而添加的三个节点,在前面有介绍,第一个就是Add
按钮,在溶解的边缘的透明度的数值加一即为未溶解的边缘,类似于等高图,目前溶解到五千米,我加一米,即五千零一米,刚好是溶解的边缘,接下来通过一个Step
节点 判断需要亮度的范围(即小于五千零一米的所有区域输出为1),这样透明区间到五千零一米之间就会有一圈亮的区域
5,通过脚本调用该效果
实现这样的溶解效果后,可以作为一个角色死亡时的特效,但是该怎么去实现这杨的功能呢,本案例就提供一个简单的脚本来应用这样的效果。
由于角色的死亡是一次事件的触发,我们使用Sin函数来循环溶解该物体毫无意义,因此我们定义一个float变量输入作为从显示到完全溶解的控制变量。
通过改变这一变量来控制物体的溶解过程,具体的脚本实现方式为:
public Material material;
public void Start()
{
//获取修改材质溶解度的变量并设置初始值
id = Shader.PropertyToID("TestNum");
material.SetFloat(id, 0);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
StartCoroutine(DestroyCube());
}
}
IEnumerator DestroyCube()
{
int n = 2000;
float num = 0;
Mathf.Sin(Time.time);
while (n>0)
{
num = Mathf.Lerp(num, 1,0.001f);
material.SetFloat(id, num);
n--;
yield return null;
}
}
编写上面的脚本,挂载到任一物体上面,并将刚刚创建好的材质拖入即可,这样就可以实现一个由事件驱动的溶解效果,如图点击空格键后效果:
Shader Graph
对于不会编程写Shader
的人很友好,通过简单的学习就可以实现一些很酷炫的效果,但是相比来说,还是没有编程实现那样的灵活。并且效果的性能完全是自己不可控的,取决与Unity
官方的性能优化,这样来讲,适配性就低很多。
不过Shaer Graph
很明显的优势就是可以对于效果原理的理解很形象,能够更好帮助初级开发者的学习渲染的知识。如果你和我一样也是一个小白,也尝试去学习一下吧!