zoukankan      html  css  js  c++  java
  • [zz]在cocos2dx中实现水波滤镜

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

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

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

    先上效果图:
    waveCover
    动态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; " : "precision mediump float; "),
    #endif
            "uniform mat4 CC_PMatrix; "
            "uniform mat4 CC_MVMatrix; "
            "uniform mat4 CC_MVPMatrix; "
            "uniform vec4 CC_Time; "
            "uniform vec4 CC_SinTime; "
            "uniform vec4 CC_CosTime; "
            "uniform vec4 CC_Random01; "
            "//CC INCLUDES END ",
            source,
        };

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

  • 相关阅读:
    《那些年啊,那些事——一个程序员的奋斗史》——29
    《那些年啊,那些事——一个程序员的奋斗史》——28
    《那些年啊,那些事——一个程序员的奋斗史》——28
    《那些年啊,那些事——一个程序员的奋斗史》——29
    《那些年啊,那些事——一个程序员的奋斗史》——30
    《那些年啊,那些事——一个程序员的奋斗史》——29
    《那些年啊,那些事——一个程序员的奋斗史》——28
    小议如何改变指针的指向
    X Window Troubleshooting
    终于把傅雷的《世界美术名作二十讲》看完了
  • 原文地址:https://www.cnblogs.com/wishing/p/3473568.html
Copyright © 2011-2022 走看看