有时候想得到一些例如灰度图等特殊的渲染效果,就得用到自定义shader,关于shader的一些背景知识,自行谷歌,列出两篇cocos2dx里介绍shader的相关文章 http://blog.csdn.net/while0/article/details/9666829 http://blog.sina.com.cn/s/blog_aa01f7030101mdom.html
cocos2dx在wp8平台不知道是不是在渲染时OpenGL要转成D3D的原因还是其他原因,不能在运行时编译链接shader,cocos2dx的做法就是事先把相关的shader编译好成特定的机器码存放到 precompiledshaders.h 文件里,通过预先生成好的sha1码指向不同的shader,运行时直接获取,关于这部分,参考了: http://www.ispinel.com/2014/07/03/12393/。 现在需要做的工作就是,给出了顶点shader和片元shader,如何生成机器码,这部分参考了 http://cn.cocos2d-x.org/tutorial/show?id=1274 。 本文采用了第二种方法,使用winrtcompiler.exe生成shader的机器码,以使用自定义灰度图shader为例,具体做法如下。
顶点shader文件——myShader.vert:
1 uniform mat4 CC_PMatrix; 2 uniform mat4 CC_MVMatrix; 3 uniform mat4 CC_MVPMatrix; 4 uniform vec4 CC_Time; 5 uniform vec4 CC_SinTime; 6 uniform vec4 CC_CosTime; 7 uniform vec4 CC_Random01; 8 attribute vec4 a_position; 9 attribute vec2 a_texCoord; 10 attribute vec4 a_color; 11 12 #ifdef GL_ES 13 varying lowp vec4 v_fragmentColor; 14 varying mediump vec2 v_texCoord; 15 #else 16 varying vec4 v_fragmentColor; 17 varying vec2 v_texCoord; 18 #endif 19 20 void main() 21 { 22 gl_Position = CC_MVPMatrix * a_position; 23 v_fragmentColor = a_color; 24 v_texCoord = a_texCoord; 25 }
片元shader文件——myShader.frag文件
1 #ifdef GL_ES 2 precision lowp float; 3 #endif 4 5 varying vec4 v_fragmentColor; 6 varying vec2 v_texCoord; 7 uniform sampler2D CC_Texture0; 8 9 void main() 10 { 11 vec4 texColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord); 12 float gray = dot(texColor.rgb, vec3(0.299,0.587,0.114)); 13 gl_FragColor = vec4(gray, gray, gray, texColor.a); 14 }
使用命令行通过 顶点shader文件、片元shader文件和winrtcompiler.exe文件生成机器码文件:把winrtcompiler.exe 、顶点shader文件和片元shader文件拷到统一文件夹里,通过cd 命令进入到那个文件夹,然后输入命令行如下:winrtcompiler.exe -o=shader_wp8.h -p=wp8 -a=gProgram -v=myShader.vert -f=myShader.frag ,生成的机器码就在 -o 参数所指向的 shader_wp8.h 文件里了。
把机器码更新到precompiledshaders.h 文件里,包括 num、length、program和programKey,programKey就是根据myShader.vert文件和myShader.frag文件得到的sha1码。最后一个问题,如何获取到这个sha1码?
可以参考 http://www.cnblogs.com/yeshanghai/p/cocos2dx_shader.html 的 1~5 点,不过需要改动一下
第1点的改动:把我们上面的myShader.vert和myShader.frag文件改造一下,也就是前后加上双引号、最后加上分号、每一行(除了最后分号那行)后面加上 \n\ 符号,因为这次是需要在运行时被动态加载编译的。
其他步骤的改动就是,原文只有片元shader,需要补上顶点shader的相关信息。
最后,在 CCPrecompiledShaders.cpp 里的 bool CCPrecompiledShaders::loadProgram(GLuint program, const GLchar* vShaderByteArray, const GLchar* fShaderByteArray) 方法里的 std::string id = computeHash(vShaderByteArray, fShaderByteArray); 代码前断点, 这个id就是顶点shader文件和片元shader文件计算出来的 sha1 值。