ShaderHelper组件演示视频(1)
http://v.youku.com/v_show/id_XMzkxNTg5MTUzNg==.html
一、ShaderHelper组件
今天把ShaderHelper组件重新整理,代码已经上传到github,地址:https://github.com/ShawnZhang2015/ShaderHelper
说实话楼主对Shader也是刚刚起步,目前只会依葫芦画瓢,根据论坛中panda、Colin、小叔叔等大佬们的教程和源码结合自己的使用体验,编写了ShaderHelper组件,请先看使用方法:
http://v.youku.com/v_show/id_XMzkxNTg5NTk2MA==.html
1. ShaderHelper使用
通过上面视频,你会发现使用ShaderHelper组件基本上没有任何负担,通过ShaderHelper的属性Program下拉菜单选择需要的Shader效果即可,看下图:
同时注意,ShaderHelper组件目前必须配合cc.Sprite组件一起使用,就是说节点上必须有一个Sprite组件。
2. Shader模板对象
有人可能会问,Program下拉菜单中Shader效果都不是我想要的,要自己添加Shader怎么做呢?
我这里设计了一个Shader程序的模板结构,下面以Wave动态效果的Shader为例说明一下Shader程序的使用规则:
/**
* shader模版对象
* */
const renderEngine = cc.renderer.renderEngine;
const renderer = renderEngine.renderer;
//定义一个shader对象
const shader = {
//名字必须字段
name: "xxx",
//着色器代码中需要与js交互的参数名字与数据类型
params: [
{name: 'yyy', type: renderer.PARAM_FLOAT},
{name: 'zzz', type: renderer.PARAM_FLOAT2}
],
//着色器中使用到的define定义,非必要字段
defines: [],
//start回调,此可以初始化着色器中的参数
start(sprite, material) { ... },
//update每帧回调,如果是动态效果,可以在此设置Shader参数
update(sprite, material) { ... },
//vert顶点着色器代码,它是一个字符串
vert: '...',
//frag片元着色器
frag: `...`
};
//注意这里,通过CustomMaterial.addShader添加shader对象,
//这样就可以被ShaderHelper组件所显示
let CustomMaterial = require('CustomMaterial');
CustomMaterial.addShader(shader);
如果要自定义Shader并能被ShaderHelper所显示且正常加载运行,需要实现上面的一些字段和方法。其中比较重要的几点说明一下:
- 定义一个最简单的shader对像只要需要有name、vert、frag三个属性
- 如果着色器代码中有需要初始化的变量,需要定义params字段,描述参数的名字和数据类型,如下所示:
params: [
{name: 'iCenter', type: renderer.PARAM_FLOAT2},
{name: 'iResolution', type: renderer.PARAM_FLOAT3}
]
- 如果着色器中的变量需要初值,可以通过start回调函数中进行初始化
- 如果需要每帧修改着色器中的变量值,实现动态特效,可以在update中进行设置
- 如果着色器中用到了define,需要在js代码中控制,可以定义define字段 ,同样他是一个数组,描述各个define是否开启或关闭,如下所示:
defines: [
{ name: 'HAS_HEART', value: true },
{ name: 'USE_POST_PROCESSING', value: false },
],
- 最后需要让shader被ShaderHelper组件加载,还需要将shader添加到CustomMaterial自定义材质对象中。
let CustomMaterial = require('CustomMaterial');
CustomMaterial.addShader(shader);
至此你就可以在ShaderHelper中看到新增的shader了。
#二、CustomMaterial.js源码分析
ShaderHelper组件只是对论坛Colin大神提供的CustomMaterial的调用,CustomMaterial又是对Cocos Creator引擎中的渲染引擎、材质系统API的运用,其中四个重要的对象:
Material(材质)、Effect(表现)、Technique(技术)、Pass(过程)
1. CustomMaterial自定义材质系统
我们先看一下CustomMaterial类的整体框架,首先CustomMaterial继承了引擎的Material类,同时实现对Effect的实例化,看下面代码:
...
var CustomMaterial = (function (Material$$1) {
...
//继承Material
cc.js.extend(CustomMaterial, Material$$1);
//定义了三个属性effect、texture、color
var prototypeAccessors = {
effect: { configurable: true },
texture: { configurable: true },
color: { configurable: true }
};
...
Object.defineProperties(CustomMaterial.prototype, prototypeAccessors);
...
}(Material));
上面我将干扰代码移除,基中最为关键的是effect属性的定义,我们看Effect是怎么实例化出来的:
//实现化Effect对象
this._effect = new renderer.Effect(
[ mainTech ],
{},
defines, //第三个参数defines就是我们之前定义的shader.dfines字段
);
this._texture = null;
this._color = { r: 1, g: 1, b: 1, a: 1 };
...
//定义effect\texutre\color的get方法
prototypeAccessors.effect.get = function () {
return this._effect;
};
prototypeAccessors.texture.get = function () {
return this._texture;
};
prototypeAccessors.color.get = function () {
return this._color;
};
上面代码为_effect、_texture、_color三个对象实现get方法,使其可以被外部访问。
2. Effect的实例化
_texture与_color的初始化比较简,但Eeffect实例化需要三个参数,看下引擎源码:
//--------------CustomMaterail.js-----------------
this._effect = new renderer.Effect(
[ mainTech ],
{},
defines, //defines就是我们之前定义的shader.dfines字段
);
//-----------------render-engine.js-----------------
//看下Effect类构建函数参数
var Effect = function Effect(techniques, properties, defines) {
...
};
Effect中三个数组分别是:techniques, properties, defines,其中关键在techniques,接下来看CustomMaterial中是怎么创建的。
3. Technique的实例化
Effect类的第一个参数需要Technique的数组,再看Technique的创建
//--------------------CustomMaterial.js-----------------------
//定义了两个默认的参数:texture、color
var techParams = [
{ name: 'texture', type: renderer.PARAM_TEXTURE_2D },
{ name: 'color', type: renderer.PARAM_COLOR4 }
];
//params就是之前定义的shader.params
if (params) {
techParams = techParams.concat(params);
}
//实例化Technique,我们之前定义的params成了Technique的参数
var mainTech = new renderer.Technique(
['transparent'], //stages参数,暂时也没搞懂具体意思
techParams,
[pass]
);
//--------------------render-engine.js-----------------------
//Technique类的构建函数
var Technique = function Technique(stages, parameters, passes, layer) {
...
}
Technique的构建函数需要4个参数,上面代码中给了前三个,其中techParams就是我们前面shader对象中定义的params字段,stages参数这里给的是[‘transparent’]我暂时也没搞懂是什么意思,先暂时不管它。passes又是什么鬼呢?我看再看pass的创建过程。
4. Pass的实例化
创建Technique又需要一个passes数组,再看代码pass的实例化过程:
//我们之前定义的shader.name成了Pass的构造参数
var pass = new renderer.Pass(shaderName);
//下面的函数调用Shawn也不太了解,这里就不解释了,等弄明白了再回来
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
);
说话实Pass的实例化我也不太了解,通过字面意思猜测是设置材质相关的参数,参考了论坛中Panda提供的heartfelt工程,也是同样的写法。
5. 小结
我们暂且不纠结细节,从整体上理清楚Cocos Creator 2.x材质系统的框架结构,请看下图:
其实楼主只是做了一个搬运工,整合了一下Cocos官网论坛中大佬们分享的项目源码,目前ShaderHelper还是有不少问题,比如:组件上不能设置shader参数;ShaderHelper只能配全精灵组件使用;切换program时曾经的shader效果没有清除等。
虽然组件还不是很完善,但提供一个思路和测试Shader的方法,一点一滴地去改进相信能把它做的更好,也期待大家的参与!
项目源码:
参考资源:
http://forum.cocos.com/t/creator2-0/64727
http://forum.cocos.com/t/shader/59401
https://github.com/pandamicro/heartfelt