零、这个时代,太快
如果有朋友年龄和麒麟子相仿的话,小时候应该玩过DVD播放机,就下面图里这东西。
那么问题来了,你还记得,如果想要播放自己想看的内容,一共分几步吗?
和把大象装进冰箱一样简单,只需要三步:
第一步、出仓:弹出光盘托盘
第二步、换碟:把想放的光碟放进去
第三步、关仓:收回光盘托盘
如果我们想从刘德华的专辑切换到张学友的专辑,你需要重复上面的步骤。
如果我们想从听歌切换到某电影,你需要重复上面的步骤。
如果我们想从电视剧的某一集切换到另一集,你还是需要重复上面的步骤。
现在让你这样去播放节目,你肯定会觉得烦。
因为我们已经习惯了当下更先进的计算机系统和功能强大的多媒体软件。
不再需要从成堆的光碟中去寻找想要的内容。
不再需要从舒适的沙发里起身去更换想要播放的光碟。
不再需要担心心爱的光碟损坏或者被邻家王哥哥借走。
麒麟子学Shader也经历了类似的时代跨度。
80后嘛,总是免不了处于时代交叉口的命运。
十几年前,人们发现固定渲染管线(Fixed Render Pipeline)
难以满足日益增长的画面要求,可编程渲染管线(Programmable Render Pipeline)
应运而生。
但可编程管线
需要硬件支持,由于硬件更新的成本远远大于软件成本,普及速度并不能像软件那样快。
处于时代交替的3D引擎
,为了兼顾所有用户的需求,一般都会支持固定管线
和可编程管线
。
那处于时代交叉口的程序员,别无选择,要同时掌握固定管线
和可编程管线
,才能吃饱饭。
早期的可编程程管线
就是在固定管线
的基础上,将T&L
(变换与光照)以Vertex Shader
方式呈现,而纹理采样和混合则以Fragment Shader
方式呈现。
随着固定管线
的淘汰,可编程管线
不再考虑兼容前者,如今的可编程管线
不管是从功能性还是便利性而言,早已经是当初的版本无法比拟的了。
为什么麒麟子要浪费大量篇幅来讲这个。
享受当下,畅想未来,回顾历史,可以让我们生活的充满诗意。
一、什么是Uniform
制服?统一的?似乎都不对。
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-block
中,麒麟子就直接翻译成常量块
了。
不用去管为什么,先记住就行。
我们定义了一个vec4 mainColor
和一个vec4 colorScaleAndCutoff
其中mainColor
用于物体渲染时的颜色值r,g,b,a
通道都用上
而colorScaleAndCutoff
中,colorScaleAndCutoff.rgb
用于颜色因子调子,而colorScaleAndCutoff.w
用于Alpha测试判断。
Alpha测试后面会讲,这里我们暂时忽略它。
渲染效果如下,由于我们没有设置变量值,常量的默认值是0.0,所以会渲染出黑色。
四、通过代码控制Uniform参数
为了照顾大家迫切的心情,我们先看看如何使用代码控制常量吧。
其实使用代码控制常量非常简单。
1、新建一个TS脚本
麒麟子把脚本取名为MaterialCtrl.ts
然后写上下面这样的代码。
这么少的代码,大家手抄吧。
2、将MaterialCtrl.ts
挂在了球体上。
3、启动浏览器预览
在浏览器中,你就能看到一个紫色的球。
注意:在编辑器中是看不到紫色的,因为我们需要TS代码行执行起来才行。
五、通过属性面板(Inspector)控制Uniform参数
有的朋友应该发现了,刚刚我们添加的mainColor
和 colorScaleAndCutoff
并没有出现在Inspector面板里。
接下来我们就来看看,如何将一个uniform
显示在面板上。
在cocos-shader-helloworld.effect
中,我们添加上图红框部分的代码。再次回到编辑器,就可以看见材质面板上多出了mainColor
和colorScale
两个调节参数。
通过调节面板,我们就能在编辑器里看到直接的效果变化,是不是很棒?
麒麟子逐一解释一下各个部分的含义。
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
对应部分。如下图所示:
六、需要注意的点
一、
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入门基础五:是纹理给了你这个花花世界》 中,麒麟子将会给大家介绍纹理相关知识。
- 纹理坐标
UV
是什么? - 纹理类型
- 纹理寻址方式
- 纹理采样方式
- 定义一个类型为
smapler2D
的uniform