关于与GLSL Shader特效,有两个比较重要的问题,下边分别讲一下:

1、如何管理自定义的shader?

2、如何解决Android上游戏从后台切换回来时,自定义shader不能自动加载?

下面针对2个问题来解答:

       Cocos2d-x从2.2-3.0,对于shader部分基本上没有做很多的变化,而在引擎中使用自定义的shader相对而言是比较麻烦的,尤其是在Android上。你会发现app从后台切换回来的时候,自定义的shader没有被加载。而为了解决这个问题你不得不修改引擎的内部代码。这是很不好的习惯。【在3.2以后版本,提供了GLProgramState来解决】

下面先分析下,Cocos2d-x shader的框架:(Cocos2d-x 3.0 Android)

引擎内置的shader program由一个全局的ShaderCache初始化并持有。

初始化:

getInstance-->init()--->loadDefaultShaders();

释放:

Director::purgeDirector-->ShaderCache::destroyInstance();

后台返回(Javaactivity.cpp):

cocos2d::ShaderCache::getInstance()->reloadDefaultGLPrograms();

(在3.2的版本中,ShaderCache的名字改为了ProgramCache。其他部分基本没有变化。)

基于上述框架,如果用户在Android上添加自己shader,就不得不在Javaactivity.cpp中添加自己的reload代码。这反映了目前引擎的shader部分存在不足。本人认为shader部分应该被重写,向开发者提供一个custom的接口。

先看下opengl中,使用shader的流程:

1. 编译vertex shader或者fragment shader;

2. 链接shader;

3. 初始化需要向shader传递的变量;(如:getUniformLocation)

4. 在render函数中,实时传递shader变量。(如:setUniformLocation)

       问题症结在第三步,对于不同的shader,需要初始化的shader变量不同,也很难预测开发者需要向shader传递哪些变量。

解决这个问题的方法是:

        抽象一个shaderNode父类,完成shader的前面2个步骤,并提供一个抽象接口(如:virtual void buildCustomUniforms() = 0;)来完成第三步的初始化,让所有继承的子类来实现这个接口。

举例:

        ShaderNode:所有shader的父类,提供公共接口的实现,如shader的编译和链接,shader从后台切换回来时reload函数的实现。

CustomShader:开发者自定义的shader,继承ShaderNode,并实现抽象接口buildCustomUniforms。在buildCustomUniforms中初始化自定义的shader变量。

ShaderCache:全局shader cache的持有者,使用shader_dec来描述所持有的ShaderNode。

shader_dec:ShaderNode的描述结构体,包括vertex shader和fragment shader的文件名,查找key和ShaderNode指针(回调具体ShaderNode的reload函数)。

如图:


1.jpg

源代码见文件。

使用方法:

1. 定义需要加载的shader table:

static cocos2d::shaderDes shader_tbl[] = {

{shader_comm_vs, shader_a_fs, “a”, NULL},

{shader_comm_vs, shader_b_fs, "b", NULL}

{shader_comm_vs, shader_c_fs, "c", NULL}

};

2. 在预加载页面(如:loading scene):

 for (int i = 0; i < ARRAYSIZE(shader_tbl); i++) {

CustomShaderCache::getInstance()->addShader(shader_tbl[i]);

}

3. 使用shader:

xxxShader::create(shader_key); /* @shader_key是自定义的shader table中的key。*/

说明:

       附件的源代码没有修改引擎的shader cache的实现模块,是另外实现的CustomShaderCache ,并添加在Cocos2d-x-3.0\cocos\2d”下,作为libcocos2d编译进引擎中。当然,也可以重写引擎的shadercache模块。 CustomShaderCache的实现和引擎的shadercache模块基本相似,只是 CustomShaderCache向外提供了一个自定义shader的类。这样自定义的shader只需要继承ShaderNode即可。其他的reload等工作由CustomShaderCache实现。

需要修改的地方:


2.jpg