移植:在Cocos2d-X中实现水波滤镜

因为工作原因,开始转向cocos2d-x开发方向了。
自然的,凭着之前引擎的经验偏向底层渲染研究。

在此期间看了两本书
《cocos2d-x 权威指南》
《cocos2d-x 高级开发教程》
不得不说,第一本书完全是API介绍,也许适合新手入门,但是于我,只是烂书一本。
第二本书还是不错的,最后的项目有全套源码,教程的风格也很有我的风格,哈哈,就是文章中不一定贴全代码,只贴核心,后期还要自己领会补全。

言归正传,在 《高级开发教程》 中有一篇是实现海底水纹效果的文章,里面代码不全,且代码和Shader并没有对应起来,于是我决定按照自己思路来将其补全,并贴上完整源码。

先上效果图:
waveCover
动态GIF图地址: http://pan.baidu.com/share/link?shareid=1858640040&uk=3221530571

首先创建一个 ShaderNode.h 类并继承CCNode
[cc lang=”C++”]
#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
[/cc]

之后创建ShaderNode.cpp 并实现 ShaderNode.h 中的各方法

[cc lang=”C++”]
#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);
}
[/cc]

之后在场景类中添加ShaderNode 即可
[cc lang=”C++”]
ShaderNode* shader = ShaderNode::shaderNodeWithVertex(“shader.vsh”,”shader.fsh”);
shader->setContentSize(getContentSize());
shader->setColor(ccc4f(1,1,1.0,.5));
this->addChild(shader,2);
[/cc]

shader.vsh 和 shader.fsh 可以从网络中得到,就是glsl文件
shader.vsh 的内容为
[cc lang=”C++”]
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;
}
[/cc]

shader.fsh 的内容为
[cc lang=”C++”]
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); } [/cc] github地址为: https://github.com/AlexandreRangel/QuaseCinemaFeijoada/blob/master/QuaseCinemaFeijoada07d/data/water.glsl

在使用顶点程序的时候,里面有个模型世界投影矩阵 u_MVPMatrix
我们在cocos2d-x中使用它的时候,需要把 CC_MVPMatrix 赋值给 u_MVPMatrix
或者直接把 u_MVPMatrix 删除,替换成 CC_MVPMatrix
like this

[cc lang=”C++”]
attribute vec4 a_color;
attribute vec4 a_position;
varying vec4 v_color;

void main()
{
v_color = a_color;
gl_Position = CC_MVPMatrix * a_position;
}
[/cc]

cocos2d-x 在创建 GLProgram 的时候,会自动在 GLSL的文件之前加上 cocos2d-x 自身需要的参数
[cc lang=”C++”]
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 ENDnn”,
source,
};
[/cc]

that’s all.
本文对于原书教程补充的地方如下
修改 shader.vsh 替换 u_MVPMatrix 为 CC_MVPMatrix
删除 ShaderNode.cpp 中全部的 m_uniformCenter 的相关代码, m_uniformCenter 在Shader中并没有该字段,没有补完的意义
添加 ShaderNode.cpp 构造函数及SetColor方法
修改 ShaderNode.h 中 update 的参数

发表评论

电子邮件地址不会被公开。 必填项已用*标注