[zz]在cocos2dx中实现水波滤镜
因为工作原因,开始转向cocos2d-x开发方向了。
自然的,凭着之前引擎的经验偏向底层渲染研究。
在此期间看了两本书
《cocos2d-x 权威指南》
《cocos2d-x 高级开发教程》
不得不说,第一本书完全是API介绍,也许适合新手入门,但是于我,只是烂书一本。
第二本书还是不错的,最后的项目有全套源码,教程的风格也很有我的风格,哈哈,就是文章中不一定贴全代码,只贴核心,后期还要自己领会补全。
言归正传,在 《高级开发教程》 中有一篇是实现海底水纹效果的文章,里面代码不全,且代码和Shader并没有对应起来,于是我决定按照自己思路来将其补全,并贴上完整源码。
先上效果图:
动态GIF图地址: http://pan.baidu.com/share/link?shareid=1858640040&uk=3221530571
首先创建一个 ShaderNode.h 类并继承CCNode
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#ifndef __FishingJoy_ShaderNode__
#define __FishingJoy_ShaderNode__ #include "cocos2d.h" USING_NS_CC; class ShaderNode : public CCNode { public: ShaderNode(); bool initWithVertex(const char *vert, const char *frag); void loadShaderVertex(const char *vert, const char *frag); virtual void update(float delta); virtual void setContentSize(const CCSize& var); virtual void setColor(ccColor4F newColor); virtual void draw(); static ShaderNode* shaderNodeWithVertex(const char *vert, const char *frag); private: GLuint m_uniformResolution, m_uniformTime, m_uniformTex0; GLuint m_attributeColor, m_attributePosition; float m_time; ccVertex2F m_resolution,m_center; GLuint m_texture; GLfloat color[4]; }; #endif |
之后创建ShaderNode.cpp 并实现 ShaderNode.h 中的各方法
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
#include "ShaderNode.h"
ShaderNode::ShaderNode() { } ShaderNode* ShaderNode::shaderNodeWithVertex(const char *vert, const char *frag) { ShaderNode* shader = new ShaderNode(); if(shader && shader->initWithVertex(vert,frag)) { shader->autorelease(); return shader; } CC_SAFE_DELETE(shader); return NULL; } void ShaderNode::loadShaderVertex(const char *vert, const char *frag) { CCGLProgram* shader = new CCGLProgram(); shader->initWithVertexShaderFilename(vert, frag); //载入着色器程序 //绑定attribute变量 shader->addAttribute("a_position", 0); shader->addAttribute("a_color", 1); shader->link(); //获取attribute变量标识 m_attributeColor = glGetAttribLocation(shader->getProgram(), "a_color"); m_attributePosition = glGetAttribLocation( shader->getProgram(), "a_position"); shader->updateUniforms(); //获取uniform变量标识 m_uniformResolution = glGetUniformLocation(shader->getProgram(), "resolution"); m_uniformTime = glGetUniformLocation(shader->getProgram(), "time"); m_uniformTex0 = glGetUniformLocation(shader->getProgram(), "tex0"); //使用着色器程序 this->setShaderProgram(shader); shader->release(); } void ShaderNode::setColor(ccColor4F newColor) { color[0] = newColor.r; color[1] = newColor.g; color[2] = newColor.b; color[3] = newColor.a; } bool ShaderNode::initWithVertex(const char *vert, const char *frag) { loadShaderVertex(vert,frag); m_texture = CCTextureCache::sharedTextureCache()->addImage("HelloWorld.png")->getName(); setContentSize(CCSizeMake(1024,768)); setColor(ccc4f(0.5,0.5,1,1)); m_time = 0; scheduleUpdate(); return true; } void ShaderNode::update(float dt) { m_time += dt; } void ShaderNode::setContentSize(const CCSize& var) { CCNode::setContentSize(var); m_resolution = vertex2(getContentSize().width,getContentSize().height); m_center.x = m_resolution.x/2; m_center.y = m_resolution.y/2; } void ShaderNode::draw() { CC_NODE_DRAW_SETUP(); //传递uniform变量 CCGLProgram* shader = getShaderProgram(); shader->setUniformLocationWith2f(m_uniformResolution, m_resolution.x, m_resolution.y); shader->setUniformLocationWith1i(m_uniformTex0, 0); glUniform1f(m_uniformTime, m_time); //获取attribute变量 CCSize size = this->getContentSize(); float w = size.width; float h = size.height; ccGLBindTexture2D(m_texture); //绑定纹理到槽位 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, w, h, 0); //截取屏幕数据到纹理 glEnableVertexAttribArray(m_attributePosition); glDisableVertexAttribArray(m_attributeColor); //传递attribute变量 GLfloat vertices[12] = { 0, 0, //左下0 w, 0, //右下1 w, h, //右上2 0, 0, //左下0 0, h, //左上3 w, h, //右上2 }; glVertexAttribPointer(m_attributePosition, 2, GL_FLOAT, GL_FALSE, 0, vertices); glVertexAttrib4fv(m_attributeColor, color); //绘制 glDrawArrays(GL_TRIANGLES, 0, 6); } |
之后在场景类中添加ShaderNode 即可
1
2 3 4 |
ShaderNode* shader = ShaderNode::shaderNodeWithVertex("shader.vsh","shader.fsh");
shader->setContentSize(getContentSize()); shader->setColor(ccc4f(1,1,1.0,.5)); this->addChild(shader,2); |
shader.vsh 和 shader.fsh 可以从网络中得到,就是glsl文件
shader.vsh 的内容为
1
2 3 4 5 6 7 8 9 |
attribute vec4 a_color;
attribute vec4 a_position; varying vec4 v_color; uniform mat4 u_MVPMatrix; void main() { v_color = a_color; gl_Position = u_MVPMatrix * a_position; } |
shader.fsh 的内容为
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
varying vec4 v_color;
uniform sampler2D tex0; precision highp float; uniform float time; uniform vec2 resolution; const float PI = 3.1415926535897932; const float speed = 0.2; const float speed_x = 0.3; const float speed_y = 0.3; const float intensity = 3.0; const int steps = 8; const float frequency = 4.0; const int angle = 7; const float delta = 20.0; const float intence = 400.0; const float emboss = 0.3; float col(vec2 coord) { float delta_theta = 2.0 * PI / float(angle); float col = 0.0; float theta = 0.0; for (int i = 0; i < steps; i++) { vec2 adjc = coord; theta = delta_theta * float(i); adjc.x += cos(theta)*time*speed + time * speed_x; adjc.y -= sin(theta)*time*speed - time * speed_y; col = col + cos((adjc.x*cos(theta) - adjc.y*sin(theta)) *frequency)*intensity; } return cos(col); } void main(void) { vec2 p = (gl_FragCoord.xy) / resolution.xy, c1 = p, c2 = p; float cc1 = col(c1); c2.x += resolution.x/delta; float dx = emboss*(cc1-col(c2))/delta; c2.x = p.x; c2.y += resolution.y/delta; float dy = emboss*(cc1-col(c2))/delta; c1.x += dx; c1.y += dy; float alpha = 1.+dot(dx,dy)*intence; gl_FragColor = texture2D(tex0,c1)*(alpha) *v_color*(alpha); } |
在使用顶点程序的时候,里面有个模型世界投影矩阵 u_MVPMatrix
我们在cocos2d-x中使用它的时候,需要把 CC_MVPMatrix 赋值给 u_MVPMatrix
或者直接把 u_MVPMatrix 删除,替换成 CC_MVPMatrix
like this
1
2 3 4 5 6 7 8 9 |
attribute vec4 a_color;
attribute vec4 a_position; varying vec4 v_color; void main() { v_color = a_color; gl_Position = CC_MVPMatrix * a_position; } |
cocos2d-x 在创建 GLProgram 的时候,会自动在 GLSL的文件之前加上 cocos2d-x 自身需要的参数
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
const GLchar *sources[] = {
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_LINUX && CC_TARGET_PLATFORM != CC_PLATFORM_MAC) (type == GL_VERTEX_SHADER ? "precision highp float;\n" : "precision mediump float;\n"), #endif "uniform mat4 CC_PMatrix;\n" "uniform mat4 CC_MVMatrix;\n" "uniform mat4 CC_MVPMatrix;\n" "uniform vec4 CC_Time;\n" "uniform vec4 CC_SinTime;\n" "uniform vec4 CC_CosTime;\n" "uniform vec4 CC_Random01;\n" "//CC INCLUDES END\n\n", source, }; |
that’s all.
本文对于原书教程补充的地方如下
修改 shader.vsh 替换 u_MVPMatrix 为 CC_MVPMatrix
删除 ShaderNode.cpp 中全部的 m_uniformCenter 的相关代码, m_uniformCenter 在Shader中并没有该字段,没有补完的意义
添加 ShaderNode.cpp 构造函数及SetColor方法
修改 ShaderNode.h 中 update 的参数