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

零、这个时代,太快


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

一、什么是Uniform


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

UniformGLSL的关键字,当我们需要从外部传递参数给GLSL时,就需要申明一个uniform常量。比如 uniformfloattime

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

它有两个特点

  • 可以通过图形API(如D3DOpenGLWebGL)修改
  • 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参数


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

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

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

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

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

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:用于指定需要使用的变量,在这里,我们使用colorScaleAndCutoffxyz三个通道。

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

六、需要注意的点


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

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

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

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

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

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

七、总结


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

并以mainColorcolorScale两个uniform实例演示了如何在Cocos Shader中使用uniform

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

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

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

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

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

八、预告

下一篇文章 《Cocos Shader入门基础五:是纹理给了你这个花花世界》 中,麒麟子将会给大家介绍纹理相关知识。

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

9赞

汪~顶一下

dingyixia

真不戳~~

通俗易懂,建议大佬把往期的链接挂载文章最后,这样中途来的也可以顺着查看整个教程系列

公众号里对应文章有往期链接

支持支持!

可以出书了 :grinning: