Cocos Shader入门基础四:Uniform与材质参数控制_3D游戏开发

零、这个时代,太快


如果有朋友年龄和麒麟子相仿的话,小时候应该玩过DVD播放机,就下面图里这东西。

Cocos Shader入门基础四:Uniform与材质参数控制_3D游戏开发_02

那么问题来了,你还记得,如果想要播放自己想看的内容,一共分几步吗?

和把大象装进冰箱一样简单,只需要三步:


第一步、出仓:弹出光盘托盘

第二步、换碟:把想放的光碟放进去

第三步、关仓:收回光盘托盘


如果我们想从刘德华的专辑切换到张学友的专辑,你需要重复上面的步骤。

如果我们想从听歌切换到某电影,你需要重复上面的步骤。

如果我们想从电视剧的某一集切换到另一集,你还是需要重复上面的步骤。

现在让你这样去播放节目,你肯定会觉得烦。

因为我们已经习惯了当下更先进的计算机系统和功能强大的多媒体软件。


不再需要从成堆的光碟中去寻找想要的内容。

不再需要从舒适的沙发里起身去更换想要播放的光碟。

不再需要担心心爱的光碟损坏或者被邻家王哥哥借走。


麒麟子学Shader也经历了类似的时代跨度。


80后嘛,总是免不了处于时代交叉口的命运。


十几年前,人们发现​​固定渲染管线(Fixed Render Pipeline)​​​难以满足日益增长的画面要求,​​可编程渲染管线(Programmable Render Pipeline)​​应运而生。

但​​可编程管线​​需要硬件支持,由于硬件更新的成本远远大于软件成本,普及速度并不能像软件那样快。

处于时代交替的​​3D引擎​​​,为了兼顾所有用户的需求,一般都会支持​​固定管线​​​和​​可编程管线​​。

那处于时代交叉口的程序员,别无选择,要同时掌握​​固定管线​​​和​​可编程管线​​,才能吃饱饭。

早期的​​可编程程管线​​​就是在​​固定管线​​​的基础上,将​​T&L​​​(变换与光照)以​​Vertex Shader​​​方式呈现,而纹理采样和混合则以​​Fragment Shader​​方式呈现。

随着​​固定管线​​​的淘汰,​​可编程管线​​​不再考虑兼容前者,如今的​​可编程管线​​不管是从功能性还是便利性而言,早已经是当初的版本无法比拟的了。

为什么麒麟子要浪费大量篇幅来讲这个。


享受当下,畅想未来,回顾历史,可以让我们生活的充满诗意。


一、什么是Uniform


Cocos Shader入门基础四:Uniform与材质参数控制_3D游戏开发教程_03

制服?统一的?似乎都不对。

​Uniform​​​是​​GLSL​​​的关键字,当我们需要从外部传递参数给​​GLSL​​​时,就需要申明一个​​uniform​​​常量。比如 ​​uniform​​​、​​float​​​ 、​​time​


麒麟子觉得,​​Direct3D​​​中的称呼更确切,它叫 ​​constant​​, 常量。


它有两个特点


  • 可以通过图形​​API​​​(如​​D3D​​​、​​OpenGL​​​、​​WebGL​​)修改
  • ​Shader​​内不可以修改

这也是为什么​​Direct3D​​要把它叫做常量

常量的传递需要使用​​GPU​​​中的​​常量寄存器​​,显然显卡寄存器并非是一个无限资源。

我们可以通过​​GL​​的枚举来查看限制。


顶点着色器常量数量限制:​​GL_MAX_VERTEX_UNIFORM_COMPONENTS​

像素着色器常量数量限制:​​GL_MAX_FRAGMENT_UNIFORM_COMPONENTS​


好在,这些限制都比较大,对于日常开发,我们可以暂时不关注这个问题。


如果哪天遇上特殊需求,请记得,硬件资源不是无限的。


二、Cocos Shader中的Uniform


在Cocos中,我们可以使用如下常量类型

​bool​​​ ​​int​​​ ​​float​​​ ​​vec2​​​ ​​vec3​​​ ​​vec4​

除了声明单个常量之外,我们还可以声明常量数组。


比如,引擎中的骨骼动画(在不使用顶点纹理的情况下),需要将整个骨骼矩阵传递过来,此时就需要用到数组。


接下来,我们将在通过在Cocos Shader中添加变量的方式,一步步让大家掌握Cocos Shader中​​uniform​​的使用。

三、第一个Uniform


Cocos Shader入门基础四:Uniform与材质参数控制_Cocos 3D_04

请看上图的示例

Cocos Shader要求,常量需要定义在​​uniform-block​​​中,麒麟子就直接翻译成​​常量块​​了。

不用去管为什么,先记住就行。

我们定义了一个​​vec4 mainColor​​​和一个​​vec4 colorScaleAndCutoff​

其中​​mainColor​​​用于物体渲染时的颜色值​​r,g,b,a​​通道都用上

而​​colorScaleAndCutoff​​​中,​​colorScaleAndCutoff.rgb​​​用于颜色因子调子,而​​colorScaleAndCutoff.w​​用于Alpha测试判断。


Alpha测试后面会讲,这里我们暂时忽略它。


渲染效果如下,由于我们没有设置变量值,常量的默认值是0.0,所以会渲染出黑色。

Cocos Shader入门基础四:Uniform与材质参数控制_Cocos 3D_05

四、通过代码控制Uniform参数


为了照顾大家迫切的心情,我们先看看如何使用代码控制常量吧。

其实使用代码控制常量非常简单。

1、新建一个TS脚本

麒麟子把脚本取名为​​MaterialCtrl.ts​​ 然后写上下面这样的代码。

Cocos Shader入门基础四:Uniform与材质参数控制_Cocos 3D_06


这么少的代码,大家手抄吧。


2、将​​MaterialCtrl.ts​​挂在了球体上。

3、启动浏览器预览

Cocos Shader入门基础四:Uniform与材质参数控制_3D游戏开发_07

在浏览器中,你就能看到一个紫色的球。

Cocos Shader入门基础四:Uniform与材质参数控制_3D游戏开发_08


注意:在编辑器中是看不到紫色的,因为我们需要TS代码行执行起来才行。


五、通过属性面板(Inspector)控制Uniform参数


有的朋友应该发现了,刚刚我们添加的​​mainColor​​​ 和 ​​colorScaleAndCutoff​​并没有出现在Inspector面板里。

接下来我们就来看看,如何将一个​​uniform​​显示在面板上。

Cocos Shader入门基础四:Uniform与材质参数控制_Cocos 3D_09

在​​cocos-shader-helloworld.effect​​​中,我们添加上图红框部分的代码。再次回到编辑器,就可以看见材质面板上多出了​​mainColor​​​和​​colorScale​​两个调节参数。

Cocos Shader入门基础四:Uniform与材质参数控制_3D游戏开发_10

通过调节面板,我们就能在编辑器里看到直接的效果变化,是不是很棒?

麒麟子逐一解释一下各个部分的含义。

​mainColor: { value: [1, 1, 1, 1], editor: { type: color } }​


​mainColor​​​:是显示在面板上的属性名称,这个名称直接与下面的​​uniform​​​ ​​Constant​​​中的 ​​vec4​​​ ​​uniform​​自动匹配。

​value​​:默认值

​editor​​​:用于配置编辑器面板相关参数,比如 ​​type​​​则用于指定面板显示内容。如果不指定,​​mainColor​​​将默认以​​vec4​​显示。

这里我们希望​​mainColor​​​是一个颜色,所以我们指定为​​color​


​colorScale: { value: [1, 1, 1], target: colorScaleAndCutoff.xyz }​


​colorScale​​:是属性名称,它将显示在面板上。

​value​​:默认值

​target​​​:用于指定需要使用的变量,在这里,我们使用​​colorScaleAndCutoff​​​的​​xyz​​三个通道。


掌握了上面的知识,足够满足日常Shader编写的需求。如果需要进一步研究的朋友,可以查看官方文档​​Pass Params​​对应部分。如下图所示:

Cocos Shader入门基础四:Uniform与材质参数控制_Cocos Shader_11

六、需要注意的点



一、​​mainColor​​​可以通过​​Color​​​设置,也可以通过​​vec4​​​设置。在Cocos代码中,​​Color​​​和​​vec4​​​有一个差别,就是​​Color​​的分量是按0~255取值的,注意这个细节就行。



二、在使用代码设置材质时,请注意​​target.sharedMaterial​​​和​​target.material​​的区别。

​target.sharedMaterial​​会直接对材质进行设置,所有引用同一个材质文件的对象均会受到影响。

​target.material​​​ 若未复制,则​​target.material​​​会先复制一个​​sharedMaterial​​​材质,再进行操作。这样设置后,不会对其他对象造成影响,但会影响​​GPU Instancing​​等优化效果。使用的时候要慎重。



三、使用代码控制材质,编辑器中看不到效果,需要运行后查看。



四、在使用代码设置时,对于像示例中​​colorScale​​​这样的定义,我们既可以对​​colorScaleAndCutoff​​​进行整体设置,也可以单独对​​colorScale​​​进行设置。换句话说,​​setProperty​​​方法既能识别​​Shader​​​中的​​uniform​​​定义,也能识别​​Pass​​描述中的属性定义.


七、总结


本文从​​uniform​​​含义和用途解释了​​uniform​​存在的意义。

并以​​mainColor​​​和​​colorScale​​​两个​​uniform​​​实例演示了如何在Cocos Shader中使用​​uniform​​。

与此同时,也展示了如何通过代码进行​​uniform​​操控。

在掌握本文的内容后,朋友们应该对​​Cocos Shader​​的使用流程有了整体认识。

后面的内容虽然多,但已经不再有流程上的新增,只是内容会更丰富。

能走到这里的朋友已经很厉害了,悄悄告诉你。

离渲染出美妙的花花世界,只有一步之遥。

八、预告

Cocos Shader入门基础四:Uniform与材质参数控制_Cocos Shader_12



  • 纹理坐标​​UV​​是什么?
  • 纹理类型
  • 纹理寻址方式
  • 纹理采样方式
  • 定义一个类型为​​smapler2D​​​的​​uniform​