您的位置:首页 > 移动开发 > Cocos引擎

在cocos2dx中实现水波滤镜

2014-06-20 23:00 183 查看
因为工作原因,开始转向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);

}
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

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 的参数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: