原文:Unreal Engine 4 Materials Tutorial
作者:Tommy Tran
译者:Shuchang Liu
通过这篇教程,你将学会如何在材质编辑器里修改贴图,创建材质实例,以及在游戏中修改更新材质实例。
一如现实世界,游戏世界也有各种各样的物体,各自拥有独特的外观。在Unreal引擎里,材质决定了物体的外观。物体的颜色?它的光泽度?是否透明?一切都定义在材质里。
在Unreal引擎中,材质被应用在基本所有可视元素里。你可以对网格、粒子、UI元素应用材质。
在本篇教程里,你将学会:
- 操作材质修改亮度和颜色
- 使用材质实例来快速生成变体
- 使用动态材质实例来在游戏收集道具过程中修改模型的颜色
在本篇教程里,你会接触到材质和蓝图编辑器。如果你还不是很熟悉,请阅读入门教程和蓝图教程教程。
注意:本篇教程只是Unreal Engine 4系列教程的其中一篇:
- Part 1:入门
- Part 2:蓝图
- Part 3:材质
- Part 4:UI
- Part 5:制作简单游戏
- Part 6:动画
- Part 7:音频
- Part 8:粒子系统
- Part 9:AI
- Part 10:制作简单FPS游戏
起步入门
下载示例项目并解压。进入项目文件夹,双击BananaCollector.uproject打开项目。
注意:如果你看到了项目是由较早的引擎版本创建的提示,这很正常(因为引擎经常更新版本)。你可以选择以拷贝副本的形式打开,也可以直接转换项目版本打开。
我们可以看到有块铺满香蕉的区域。按下Play,使用W,A,S和D键控制红色方块。你可以通过移动方块方块香蕉。
首先,我们需要修改香蕉材质来改变其亮度。Content Browser进入Materials文件夹双击M_Banana,打开材质编辑器。
为了调整香蕉的亮度,我们需要修改贴图。
修改贴图
贴图本质就是一张图片,而图片是像素点的集合。一张彩色图片,它的像素点颜色是由红(R),绿(G)和蓝(B)三个通道值所确定的。
下面是一张2x2像素的图片,每个像素点的RGB值如文本所示。
注意:在Unreal引擎中,RGB各通道值的范围为0.0~1.0。然而,在很多其他应用中,RGB各通道值为0~255。这仅仅是两种不同的表示方式,并不代表Unreal引擎的颜色范围更小。
我们可以通过对贴图的每个像素值做数值操作从而修改贴图。这种操作可以是简单的增加每个像素点通道值。
下面的例子是将各通道值的范围调整成0.4~1.0。这样各通道的最小值不小于0.4,就使得图片看起来更亮了。
我们可以如下图一样在材质编辑器完成上述操作:
接着,我们会使用Multiply(乘法)节点来调整贴图的亮度。
Multiply节点
顾名思义,Multiply节点对两个数值输入做乘法操作。
使用乘法,我们可以在不影响色相和饱和度情况下,改变像素亮度。下面的例子里,通过对每个像素点通道值乘以0.5,将图片的亮度减半。
通过给每个像素做上述操作,就可以改变整个贴图的亮度。
虽然下面所说并非教程重点,但我们也可以通过使用Multiply节点连接一张遮罩贴图。使用了遮罩贴图,原贴图的某些区域看起来就会更暗了。下面是使用瓷砖纹理来遮罩石头纹理的例子:
其遮罩原理是像素点的灰度范围在0(黑色)到1(白色)之间。
白色像素区域的原图亮度最高,因为其像素点通道值乘以了1,灰色区域的亮度暗淡些,因为通道值乘以了小于1的数值,黑色区域完全无亮度,因为通道值乘以了0。
现在,让我们试试Multiply节点吧。
调整贴图亮度
首先我们需要去掉Texture Sample和Base Color引脚之间的连线。我们可以通过右键点击引脚或者连线去掉连接。同样的,按住Alt键,鼠标左键点击连线也可去掉连接。
接着创建Multiply和Constant节点。你可以通过长按M键(Multiply节点)或者1键(Constant节点)并左键点击空白区域,快捷创建对应节点。随后如下图一样连线:
这样贴图的每个像素值都会与Constant节点值相乘。最后,将修改后的贴图作为Base Color输出。
现在,贴图看起来应该是黑色的,因为乘数为0(Multiply节点默认值为0)。为了修改乘数,选中Constant节点,在Details面板将Value改为5。
点击Apply并返回主编辑器。可以看到香蕉颜色变得更亮了。
我们还可以通过添加一些不同颜色的香蕉来丰富画面效果。虽然我们可以新增不同颜色的材质,创建材质实例是一种更为简便的方法。
关于材质实例
材质实例是材质的一种副本。对于原材质的任何修改都会在连带影响材质实例。
材质实例的好处在于不用重新编译而使得修改生效。你可能注意到了,每次我们修改了材质并点击Apply按钮,面板都会提示shader编译信息。
通常来说这个过程只会持续数秒时间。然而,随着材质变得复杂,编译时间会急剧增加。
下面两种场景很适合使用材质实例:
- 材质非常复杂,而且你希望可以快速进行修改
- 希望根据原材质创建材质变体,比如希望修改颜色,亮度甚至贴图。
以下场景所有物体都使用了材质实例来修改显示颜色,其实这些实例都共用了同一个材质。
在使用材质实例前,你需要为原材质创建参数。这样材质实例才会显示同样的参数,使得我们可以调整材质的参数。
创建材质参数
回到主编辑器,并确保仍然处于编辑M_Banana材质的状态。
首先,我们需要一个节点来修改贴图的色相。HueShift节点就可以胜任。添加节点,并如下图进行连线:
- 按住Alt键并左键点击连线断开Multiply节点与M_Banana节点的连接。
- 右键点击 Blueprint面板,搜索HueShift节点并选中。
- 如上图所示进行连线。
接着,我们需要创建Scalar Parameter节点。这个节点有一个可编辑的字段值。我们可以通过按住S键并左键点击空白区域快速创建,然后连接HueShift节点的Hue Shift Percentage(S)引脚。
这里我们最好重新命名这个参数。选择Scalar Parameter节点,并在Details面板将变量名改为HueShiftPercentage。
我们也可以将Constant节点转换为Scalar Parameters节点。右键点击刚才创建的Constant节点,选择Convert to Parameter选项,然后将变量名改为Brightness。
现在材质参数就算设置好了。点击Apply并关闭材质编辑器。
接着,我们要创建一个材质实例。
创建材质实例
将Content Browser切换到Materials文件夹。右键点击M_Banana,并在弹出菜单中选择Create Material Instance。将新资源重命名为MI_Banana_Green。
双击MI_Banana_Green打开材质实例编辑器。
编辑器由三个主要面板组成:
- Details:展示设置参数及其他通用参数。
- Instance Parents:展示当前实例的父类材质列表。在这个例子里,父类只有M_Banana。
- Viewport:展示当前材质实例的预览球形网格。通过长按左键移动鼠标旋转预览网格,滑动滚轮缩放界面。
为了改成预览香蕉网格,可以在Details面板的Previewing部分,左键点击Preview Mesh下拉框,选择SM_Banana。现在就可以看到预览网格变成了香蕉。
接着,我们需要编辑参数将香蕉颜色改成绿色。为了编辑参数,要先勾选每个参数的勾选框。
将Brightness改为0.5,HueShiftPercentage改为0.2。你会看到如下图的效果:
现在你已经创建好了材质实例,是时候应用在游戏的香蕉上了。关闭材质实例编辑器,回到主编辑器。
应用材质实例
我们可以单独编辑放入场景的每个角色。意思是我们可以修改一个香蕉的材质而不影响其他香蕉。我们可以通过这点将某些香蕉改成绿色的。
选择任意香蕉并在Details面板的组件列表中选中StaticMesh组件。
Details面板会显示出StaticMesh组件的参数,将材质参数改成MI_Banana_Green。
重复如上操作,让场景不同颜色的香蕉分布得更加随机。看你能不能自己创建一个材质实例来制作一些紫色的香蕉吧!
动态变化材质
材质的作用也不仅限于美化画面;我们也可以利用材质来做一些游戏设计。接着,你会学习如何利用材质,伴随方块收集了越来越多的香蕉,动态地将方块颜色由白改成红色。
在我们创建材质实例前,我们需要先设置好方块的材质。
在Materials文件夹双击M_Cube打开材质编辑器。
首先需要创建颜色。你能看到Constant3Vector节点连接了Base Color引脚。这个节点非常适合用于设置颜色,因为它有RGB通道。
既然已经有了红色,那还需要创建白色。我们通过按住数字键3,左键点击空白处快捷创建Constant3Vector节点。
通过双击Constant3Vector节点打开Color picker。
通过滑动条或者在R,G,B通道输入1.0将颜色设为白色,然后点击OK按钮。
为了平滑地将颜色从白色改为红色,最简便的方法就是使用线性插值。
什么是线性插值?
线性插值是一种获得[A,B]范围内某个数值的方法。比如,我们可以通过线性插值查找100和200之间的中间值。
通过控制Alpha值,线性插值的作用就显现出来了。你可以将Alpha当成A到B点的百分比。Alpha为0时返回A,Alpha为1时返回B。
比如,你可以随时间增加Alpha,来将一个物体从A点移动到B点。
在本篇教程中,你将通过收集香蕉数量来逐步增加透明度。
使用LinearInterpolate节点
首先,通过长按L键左键点击空白处快捷添加LinearInterpolate节点。
接着,创建Scalar Parameter节点并将其命名为ColorAlpha。随后如下图进行连线:
小结:LinearInterpolate节点会输出A值。因为Alpha值为0。Alpha值越接近1,输出越接近B值。
材质现已制作好了。后续还有很多东西需要做,但我们可以看看现在的进度,点击Apply并关闭材质编辑器。如果你点击Play,应该可以看到方块现在是白色而不是红色的。
为了让方块改变颜色,你需要编辑ColorAlpha参数。然而还有一个问题,你不能在游戏运行中修改材质实例参数。解决方案是使用动态材质实例。
关于动态材质实例
不同于其他实例,你可以在游戏中通过蓝图或C++编辑动态材质实例。
你可以使用动态实例实现很多功能,比如一点点修改物体不透明度直至完全不可见。或者,你可以在物体沾湿时增加物体高光。
还有一个好处是使用动态材质实例,意味着你可以单独修改每个物体。
下面例子是使用动态修改每个材质实例,实现了物体渐隐。
创建动态材质实例
你只能在游戏中通过蓝图或C++创建动态材质实例。
Content Browser窗口双击进入Blueprints文件夹,双击BP_Player打开蓝图编辑器。
首先要做的就是创建动态材质实例,并将其应用在方块上。在Unreal生成角色的时机,也就是Event BeginPlay节点触发时,做这件事比较合适。
确保在Event Graph上添加了Event BeginPlay节点。
现在,添加 Create Dynamic Material Instance (StaticMesh)节点。这个节点会同步创建并给方块应用动态材质实例。
接着,你需要指定方块应用哪个材质。点击Source Material下拉框选择M_Cube。
为了方便后续引用材质,最好用变量表示这个材质。最简单的方法是在节点的Return Value引脚右键点击,随后点击弹出菜单的Promote to Variable。
观察My Blueprint页签,可以看到出现了新变量。按下F2键将其快捷重命名为CubeMaterial。
最后,连接Event BeginPlay与Create Dynamic Material Instance节点。
小结:一旦Unreal生成BP_Player,就会创建动态材质实例并将其应用到StaticMesh组件上,该实例会储存成变量CubeMaterial。
下一步就该创建计数器用于统计香蕉收集数量了。
创建香蕉计数器
如果把面板往下拖,你能看到如下的节点连接。我们会利用这部分节点来更新香蕉计数器和材质。
On Component Begin Overlap节点会在方块接触其他角色时触发执行。接着,Cast to BP_Banana节点会检查触碰角色是不是香蕉,如果是,则DestroyActor节点会将其销毁并移出游戏。
现在我们要做的第一件事是创建变量存储已搜集香蕉数量。随后我们要在每次方块触碰香蕉时累加该变量。
创建Float变量并将其命名为BananaCounter。将变量拖拽至Event Graph并从弹出菜单中选择Get。
为了让计数器每次自增加一,添加IncrementFloat节点,然后连接BananaCounter节点。
接着,连接DestroyActor节点与IncrementFloat节点。
现在,玩家每收集一个香蕉,BananaCounter变量就会自增加一。
如果你直接使用BananaCounter作为alpha值使用,并不会得到预期结果。因为LinearInterpolation节点的alpha值范围是[0,1]。你可以通过归一化将计数转化为[0,1]之间的值。
我们使用BananaCounter节点值除以一个预设值来进行归一化。这个预设值代表着需要收集多少根香蕉才能让方块彻底变红色。
添加float / float节点并将其左上角引脚与IncrementFloat节点相连。
将float / float节点的底部值设置为6。这意味着玩家需要收集6根香蕉让方块彻底变红色。
这里还有个小问题。当玩家收集了超过6根香蕉,alpha值会超过1,为了修正这点,再使用Clamp (float)节点将输出范围限制在[0,1]。
现在,有了alpha值,是时候用它来更新材质了。
更新材质
将CubeMaterial变量拖拽至Event Graph,从弹出菜单中选中Get。
接着,拖拽CubeMaterial变量引脚到空白处,会弹出该变量类型的可用节点列表菜单。选中任意节点后,该节点都会自动连上变量节点。我们添加Set Scalar Parameter Value节点,该节点用于给参数设值。
现在,你需要指明更新的参数。将Parameter Name字段改为ColorAlpha。这个就是方块材质所用的参数名。
连接Clamp (float)节点的返回值与Set Scalar Parameter Value node节点的Value引脚。
最后,连接IncrementFloat节点与Set Scalar Parameter Value node节点。
以下是蓝图执行的顺序:
- On Component Begin Overlap (StaticMesh):当方块与其他角色触碰时触发执行
- Cast to BP_Banana:检查触碰角色是否为香蕉
- DestroyActor:如果触发到了香蕉,销毁移除香蕉
4.IncrementFloat:BananaCounter变量自增加一
5.float / float:计数器除以特定数值进行归一化
6.Clamp(float):限制上一步的输出值不大于1
7.Set Scalar Parameter Value:将上一步的输出值作为方块材质的ColorAlpha参数值。
至此大功告成,一起来检验成果吧!点击Compile并关闭蓝图编辑器。
点击Play并开始收集香蕉。方块一开始是白色的,随着收集了越来越多的香蕉,方块变得越来越红。一旦收集了超过6根香蕉,它就会彻底变红。
后续学习
你可以在这里下载完整项目。
我喜欢材质,因为它们威力强大,能做很多事情。你可以通过搭配不同材质创建更复杂的材质效果,比如缝隙中覆盖着藓苔的石头。你也可以实现像教程动图里所展现的炫酷的溶解效果。
如果你希望学习更多关于材质的内容,推荐你阅读Unreal引擎文档关于材质输入部分内容。学习了解这些,有助于你创建一些更高级的材质。
我建议你多尝试用不同的节点(还有很多其他节点)实验各种效果。毕竟实践出真知 :)
如果你还想继续学习引擎其他内容,点击下篇教程,将讲解如何在游戏中使用文本,按钮等UI元素。