在cocos2dx中实现水波滤镜

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

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

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

先上效果图:
在cocos2dx中实现水波滤镜_第1张图片
动态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,  00, w, h,  0 ) ;  //截取屏幕数据到纹理  
    glEnableVertexAttribArray (m_attributePosition ) ;  
    glDisableVertexAttribArray (m_attributeColor ) ;  

     //传递attribute变量  
    GLfloat vertices [ 12 ]  =  {  
         00//左下0
        w,  0//右下1
        w, h,  //右上2
         00//左下0
         0, h,  //左上3
        w, h,  //右上2
     } ;  
    glVertexAttribPointer (m_attributePosition,  2, GL_FLOAT, GL_FALSE,  0, vertices ) ;  
    glVertexAttrib4fv (m_attributeColor, color ) ;  

     //绘制  
    glDrawArrays (GL_TRIANGLES,  06 ) ;  
}

之后在场景类中添加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 的参数

你可能感兴趣的:(android)