写在前面
最近比较空闲,准备趁着这个时候把shader研究一下。前几年写过Unity的Shader,但两三年不用发现忘得都差不多了,这次从头开始查资料发现都比较零散,所以就在这里记录一下,方便日后回顾。
本文使用的环境是:CocosCreator 2.0.8
注意:CocosCreator 1.x和2.x的差别很大,本文仅适用于2.x的版本。
准备开始
CocosCreator并没有提供Shader编辑的接口,据说2.1.x会完善材质系统(Shader就是依托于材质的),因为短时间内不会升级到2.1,所以也没有关注。
为了能够使用自定义的Shader,我们需要对引擎的功能做一些扩展,在cocos论坛中找到了大佬提供的源码,点击这里。
其中最重要的就是三个文件:CustomMaterial.js,ShaderHook.js,ShaderHelper.js
看懂这三个文件,就能随心所欲的添加自定义Shader啦~接下来的内容是对这三个文件的分析,并做了一定的修改以适应自己的习惯。
自定义材质
CocosCreator中所有渲染组件都有材质material,这也是渲染的基础,引擎提供了两个默认材质SpriteMaterial(正常模式)和GraySpriteMaterial(灰度模式),具体的可以看引擎源码。
为了支持自定义Shader,我们新增了一个材质ShaderMaterial,即上文的CustomMaterial,改名只是个人习惯。
/**
* Shader材质
*/
const renderEngine = cc.renderer.renderEngine;
const renderer = renderEngine.renderer;
const gfx = renderEngine.gfx;
const Material = renderEngine.Material;
let ShaderMaterial = (function (Material$$1) {
function ShaderMaterial(name, params, defines) {
Material$$1.call(this, false);
var pass = new renderer.Pass(name);
pass.setDepth(false, false);
pass.setCullMode(gfx.CULL_NONE);
// 设置混合模式
pass.setBlend(
gfx.BLEND_FUNC_ADD,
gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA,
gfx.BLEND_FUNC_ADD,
gfx.BLEND_SRC_ALPHA, gfx.BLEND_ONE_MINUS_SRC_ALPHA
);
// 默认参数
let techParams = [
{
name: 'texture', type: renderer.PARAM_TEXTURE_2D },
{
name: 'color', type: renderer.PARAM_COLOR4 }
];
// 额外参数(每个Shader自定义的参数)
if (params) {
techParams = techParams.concat(params);
}
var mainTech = new renderer.Technique(
['transparent'], // 固定transparent,貌似只有这种模式
techParams, // 配置的参数
[pass]
);
this.name = name;
this._color = {
r: 1, g: 1, b: 1, a: 1 };
this._effect = new renderer.Effect(
[mainTech],
{
}, // proteries,传入的uniform参数,即params,此处留空,将在后面设置
[defines] // Shader配置的defines
);
this._mainTech = mainTech;
this._texture = null;
}
// 继承Material
cc.js.extend(ShaderMaterial, Material$$1);
var prototypeAccessors = {
effect: {
configurable: true },
texture: {
configurable: true },
color: {
configurable: true }
};
// 以下是对一些参数的get/set方法
prototypeAccessors.effect.get = function () {
return this._effect;
};
prototypeAccessors.texture.get = function () {
return this._texture;
};
prototypeAccessors.texture.set = function (val) {
if (this._texture !== val) {
this._texture = val;
this._effect.setProperty('texture', val