zoukankan      html  css  js  c++  java
  • cocos2dx

     本节主要讲利用cocos2dx机制实现opengl es shader脚本的绘制

      这里先看下最终效果:

                        

    这里分别实现了灰度效果及残影的效果。

    一、绘制基类

      这里主要参考了cocos2dx源码中 RenderTexture 的实现,有兴趣的可以了解下。

    绘制基类RenderShader主要实现以下方法:

    //******************************************************************
    // 文件名:    RenderShader.h
    // 创建人:    稀饭lei
    // 版  本:    1.0
    // 描  述:    特效基类
    //******************************************************************
    #ifndef _RenderShader_H__
    #define _RenderShader_H__ 
    #include "cocos2d.h"
    USING_NS_CC;
    
    // GL纹理坐标组
    static const  GLfloat ccRenderTextcord[8] ={
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,
    };
    class RenderShader : public Node
    {
    public:
        static RenderShader* create();
    
        virtual bool LoadByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray);    //加载 shader文件
    
        void    begin();                // 用于设置绘制开始要调用的onBegin
    
        void    end();                    // 用于设置绘制结束要调用的onEnd
    
        void    push2Draw(Node* node);  // 添加待绘制节点
    
        virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;  // cocos2dx绘制回调
    
    protected:
        virtual void onBegin();
    
        virtual void onEnd();
    
        //virtual void onClear();
    
        virtual void Render();                // 绘制实现
    
    
        virtual bool init();
    
        virtual void CreateFrameBuffer();    //创建FBO及texture
    
        RenderShader(void);
    
        virtual ~RenderShader(void);
     
    
        GLuint m_nFrameBuffer;            // 用于当前绘制的fbo
    
        GLuint m_nFrameBufferTexture;    // 用于绑定在fbo中的texture
    
        GLProgram* m_glprogram;            // GL绘制管理
    
        GLint m_nOldFBO;                // 原来的fbo
    
        
        CustomCommand _beginCommand;
        CustomCommand _endCommand;
        GroupCommand _groupCommand;
    
        std::set<Node*> sRenderChild;    // 需要绘制的节点
    
        Size    m_sRenderSize;
    };
    
    #endif

    这里有几个主要实现:

    1、我们用push2Draw(Node* node);  方法将待绘制的节点添加到sRenderChild中等待处理。

    2、参考RenderTexture 的实现,我们也利用begin,end将需要绘制的节点利用visit访问添加到当前的RenderShader类所在的render层中进行绘制。

    3、在实际绘制过程中调用的onBegin中缓存对应的坐标系,同时绑定我们创建FBO使得visit进来的节点可以绘制到当前FBO中。然后在onEnd中调用render方法将我们的FBO内容绘制原来cocos2dx底层的FBO上。

    4、在render()实现如何绘制当前FBO的内容到cocos2dx的FBO上。(实际shader作业的地方)

    详细实现代码如下:

    #include "RenderShader.h"  
    #define STRINGIFY(A)  #A
    const char* ccPositionTextureColor_frag_test = STRINGIFY(
    
    #ifdef GL_ES
    
      precision lowp float;
    
    #endif
    
     
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    
    void main()
    {
        vec4 color = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
        float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
        gl_FragColor = vec4(vec3(gray), color.a);
    }
    );
    
    RenderShader* RenderShader::create()
    {
        auto node = new RenderShader();
        if (node  && node->init())
        {
            node->autorelease();
            return node;
        }
        delete node;
        return nullptr;
    }
    
    bool RenderShader::init()
    {
        if (m_glprogram)
        {
            m_glprogram->release();
            m_glprogram = nullptr;
        }
    
        CreateFrameBuffer();
      
        m_glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, ccPositionTextureColor_frag_test);
        m_glprogram->retain();
    
        return true;
    }
    
    RenderShader::RenderShader(void)
        :m_nFrameBuffer(0), m_nFrameBufferTexture(0), m_glprogram(nullptr)
    {
        GLView* glView = Director::getInstance()->getOpenGLView();
        if (!glView)
        {
            return;
        }
        //屏幕大小 
        m_sRenderSize = glView->getFrameSize();
    }
    
    RenderShader::~RenderShader(void)
    {
        if (m_glprogram)
        {
            m_glprogram->release();
            m_glprogram = nullptr;
        }
        if (m_nFrameBuffer)
        {
            glDeleteFramebuffers(1, &m_nFrameBuffer);
            m_nFrameBuffer = 0;
        }
        if (m_nFrameBufferTexture)
        {
            glDeleteTextures(1, &m_nFrameBufferTexture);
            m_nFrameBufferTexture = 0;
        }
    }
    
    bool RenderShader::LoadByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray)
    {
        if (m_glprogram)
        {
            m_glprogram->release();
            m_glprogram = nullptr;
        }
    
        this->CreateFrameBuffer();
    
        m_glprogram = GLProgram::createWithByteArrays(vShaderByteArray, fShaderByteArray);
        m_glprogram->retain();
    
        return true;
    }
    
    
    void RenderShader::onBegin()
    {
        if (!m_nFrameBuffer)
        {
            return;
        }
        Director* director = Director::getInstance();
        director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
        director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
        //save old fbo and bind own
        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_nOldFBO);
        glBindFramebuffer(GL_FRAMEBUFFER, m_nFrameBuffer);
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glClear(GL_COLOR_BUFFER_BIT);
    }
    
    void RenderShader::onEnd()
    {
        if (!m_nFrameBuffer)
        {
            return;
        }
    
        // restore viewport for render to direct fbo
        Director *director = Director::getInstance();
        // restore viewport
        director->setViewport();
        this->Render();
    
        glBindFramebuffer(GL_FRAMEBUFFER, m_nOldFBO);
        director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
        director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    }
    
    
    void RenderShader::Render()
    {
        if (!m_glprogram || !m_nFrameBufferTexture)
        {
            return;
        }
    
        glBindFramebuffer(GL_FRAMEBUFFER, m_nOldFBO);
        m_glprogram->use();
        m_glprogram->setUniformsForBuiltins();
    
        //GLuint glTexture = m_glprogram->getUniformLocationForName("CC_Texture0");
        //glActiveTexture(GL_TEXTURE0);
        //glBindTexture(GL_TEXTURE_2D, m_nFrameBufferTexture);
        //glUniform1i(glTexture, 0);
        GL::bindTexture2D(m_nFrameBufferTexture);
        Size sSize = Director::getInstance()->getVisibleSize();
        float x = 0;
        float y = 0;
        float w = sSize.width;
        float h = sSize.height;
        GLfloat vertices[] = {
            x, y + h,
            x + w, y + h,
            x, y,
            x + w, y
        };
        
        glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
        glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, 0, ccRenderTextcord);
    
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    
        /*GL::bindVAO(0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/
    }
    
    
    
    void RenderShader::CreateFrameBuffer()
    {
        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_nOldFBO);
        if (m_nFrameBuffer == 0)
        {
            glGenFramebuffers(1, &m_nFrameBuffer);
    
            if (m_nFrameBuffer == 0)
            {
                CCLOG("m_FilterFrameBuffer == 0");
                return;
            }
        }
        glBindFramebuffer(GL_FRAMEBUFFER, m_nFrameBuffer);
    
        if (m_nFrameBufferTexture == 0)
        {
            glGenTextures(1, &m_nFrameBufferTexture);  
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, m_nFrameBufferTexture);
    
            GLsizei nWidth = m_sRenderSize.width;
            GLsizei nHeight = m_sRenderSize.height;
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
            GLenum err = glGetError();
            if (err != GL_NO_ERROR)
            {
                CCLOG("cocos2d: Texture2D: Error uploading compressed texture glError: 0x%04X", err);
                return;
            }
    
        }
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_nFrameBufferTexture, 0);
    
    
        GLenum error;
        if ((error = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE)
        {
            CCLOG("Failed to make complete framebuffer object 0x%X", error);
            return;
        }
    
        glBindFramebuffer(GL_FRAMEBUFFER, m_nOldFBO);
    }
    
    void RenderShader::begin()
    { 
        Director* director = Director::getInstance();
        CCASSERT(nullptr != director, "Director is null when seting matrix stack");
        director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
        director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
        _groupCommand.init(_globalZOrder);
    
        Renderer *renderer = Director::getInstance()->getRenderer();
        renderer->addCommand(&_groupCommand);
        renderer->pushGroup(_groupCommand.getRenderQueueID());
    
        _beginCommand.init(_globalZOrder);
        _beginCommand.func = CC_CALLBACK_0(RenderShader::onBegin, this);
    
        renderer->addCommand(&_beginCommand);
    }
    
    void RenderShader::end()
    {
        _endCommand.init(_globalZOrder);
        _endCommand.func = CC_CALLBACK_0(RenderShader::onEnd, this);
    
        Director* director = Director::getInstance();
        CCASSERT(nullptr != director, "Director is null when seting matrix stack");
    
        Renderer *renderer = director->getRenderer();
        renderer->addCommand(&_endCommand);
        renderer->popGroup();
    
        director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
        director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
    }
    
    void RenderShader::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
    {
        //Begin will create a render group using new render target
        begin();
    
        ////clear screen
        //_clearCommand.init(_globalZOrder);
        //_clearCommand.func = CC_CALLBACK_0(RenderShader::onClear, this);
        //renderer->addCommand(&_clearCommand);
    
        //! make sure all children are drawn
        {
            auto it = sRenderChild.begin();
            while (it != sRenderChild.end())
            {
                if (Node* node = *it)
                {
                    node->visit(renderer, transform, flags);
                    node->release();
                }
                ++it;
            }
            sRenderChild.clear();
        }
        //End will pop the current render group
        end();
    }
    
    
    void    RenderShader::push2Draw(Node* node)
    {
        if (node && sRenderChild.find(node) == sRenderChild.end())
        {
            node->retain();
            sRenderChild.insert(node);
        }
        else
        {
            CCLOG(" push same!!!");
        }
    }
    View Code

    这里shader代码实现的是灰度图的效果,其他效果可以自己修改ccPositionTextureColor_frag_test内容。

    二、实际使用

    1、将RenderShader当成正常的Node使用,设置父节点及index坐标等。

            m_pShader = RenderShader::create();
            this->addChild(m_pShader);

    2、因为RenderShader在draw中对需要绘制的子节点进行了清理,所以需要每次重新对子节点进行添加,添加动画节点如下:

    void CPlayer::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
    { 
        if (m_pShader)
        {
            m_pShader->push2Draw(m_pNode);
        } 
    }

    主要事项:RenderShader在Render方法中将内容绘制到原来的FBO中,而cocos2dx对每个需要绘制的同一index层级会在开始的时候单独创建一个FBO来处理。因而如果RenderShader单独一个层级可能导致此时的FBO没有创建,导致没有绘制效果。

    到这里我们就实现灰色角色的效果了,使用也依照cocos2dx的用法,相对简单。

    三、残影效果扩展

    主要实现代码如下:

    //******************************************************************
    // 文件名:    RemindShader.h
    // 创建人:    稀饭lei
    // 版  本:    1.0
    // 描  述:    残影特效
    //******************************************************************
    #ifndef _RemindShader_H__
    #define _RemindShader_H__ 
    #include "RenderShader.h"
    USING_NS_CC;
    #define REMIND_RENDER_COUNT 5  // 残影个数
    class RemindShader :public RenderShader
    {
    public:
        static RemindShader* create();
    
        virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;
    private:
        virtual void onBegin() override;
    
        //virtual void onClear();
    
        virtual void Render() override;
    
        virtual bool init() override;
    
        virtual void CreateFrameBuffer() override;
    
        RemindShader(void);
    
        virtual ~RemindShader(void);
    
        GLuint m_pTextureArr[REMIND_RENDER_COUNT]; 
          
        int   m_nRenderFrq;            // 渲染间隔帧率
    
        int      m_nRenderCount;        // 渲染间隔计数
    
        int   m_nCurTexutreIndex;    // 当前渲染的纹理ID
    };
    
    #endif
    
    #include "RemindShader.h"
    
    #define STRINGIFY(A)  #A
    const char* ccRemind_fsh = STRINGIFY(
        
    #ifdef GL_ES
    
        precision lowp float;
        
    #endif
    
    
        varying vec2 v_texCoord;
        uniform float u_alpha;
    
        void main()
        {
            vec4 pcolor = texture2D(CC_Texture0, v_texCoord) * u_alpha;
            gl_FragColor = pcolor;
        }
        );
    
    
    RemindShader* RemindShader::create()
    {
        auto node = new RemindShader();
        if (node  && node->init())
        {
            node->autorelease();
            return node;
        }
        delete node;
        return nullptr;
    }
    
    bool RemindShader::init()
    {
        if (m_glprogram)
        {
            m_glprogram->release();
            m_glprogram = nullptr;
        }
    
        CreateFrameBuffer();
        m_glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, ccRemind_fsh);
        m_glprogram->retain();
        return true;
    }
    
    RemindShader::RemindShader(void)
    : m_nCurTexutreIndex(0), m_nRenderFrq(10), m_nRenderCount(0)
    {
        memset(m_pTextureArr, 0, REMIND_RENDER_COUNT);
    }
    
    RemindShader::~RemindShader(void)
    {
        if (m_pTextureArr[0])
        {
            glDeleteTextures(REMIND_RENDER_COUNT, m_pTextureArr);
            memset(m_pTextureArr, 0, REMIND_RENDER_COUNT);
        }
    }
     
    void RemindShader::onBegin()
    {
        if (!m_nFrameBuffer)
        {
            return;
        }    
        Director* director = Director::getInstance(); 
        director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
        director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    //    director->setProjection(director->getProjection());
    //    GLView* glView = director->getOpenGLView();
    //    if (!glView)
    //    {
    //        return;
    //    }
    //    Size frameSize =glView->getFrameSize();
    //    {
    //        // Calculate the adjustment ratios based on the old and new projections
    //        Size size = director->getWinSizeInPixels();
    //        float widthRatio = size.width / frameSize.width;
    //        float heightRatio = size.height / frameSize.height;
    //        //caculate the projections of size change
    //        Mat4 orthoMatrix;
    //        Mat4::createOrthographicOffCenter((float)-1.0 / widthRatio, (float)1.0 / widthRatio, (float)-1.0 / heightRatio, (float)1.0 / heightRatio, -1, 1, &orthoMatrix);
    //        director->multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, orthoMatrix);
    //    }
    //    
    //    //calculate viewport
    //    {
    //        glViewport(0, 0, (GLsizei)(frameSize.width), (GLsizei)(frameSize.height));
    //    }
        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_nOldFBO);
        // 仅在计数为0才更新新的渲染
        if (m_nRenderCount == 0)
        {
            glBindFramebuffer(GL_FRAMEBUFFER, m_nFrameBuffer);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pTextureArr[m_nCurTexutreIndex], 0);
            m_nCurTexutreIndex = m_nCurTexutreIndex + 1 < REMIND_RENDER_COUNT ? m_nCurTexutreIndex + 1 : 0;
    
             glClearColor(0.0, 0.0, 0.0, 0.0);
             glClear(GL_COLOR_BUFFER_BIT);
        }
    }
    
    void RemindShader::Render()
    {
        if (!m_glprogram )
        {
            return;
        }
    
        glBindFramebuffer(GL_FRAMEBUFFER, m_nOldFBO);
        m_glprogram->use();
        m_glprogram->setUniformsForBuiltins();
    
        Size sSize = Director::getInstance()->getVisibleSize();
        float x = 0;
        float y = 0;
        float w = sSize.width;
        float h = sSize.height;
    
        // 除当前纹理外的纹理存储的都是拖影
        int nBeginIndex = m_nCurTexutreIndex;
        int nCurIndex = nBeginIndex;
        GLfloat falpha = 0.3f;
        float addf = 0.05f;
    
        // 渲染存在m_pTextureArr队列里的拖影纹理到主场景
        do
        {    
            Point delta = _position;// this->convertToWorldSpace(_position);
            GLfloat vertices[] = {
                x   - delta.x,y+ h - delta.y,
                x+w - delta.x,y+ h - delta.y,
                x - delta.x  , y - delta.y,
                x+w - delta.x, y - delta.y
            };
            //GLuint glTexture = m_glprogram->getUniformLocationForName("CC_Texture0");
            //glActiveTexture(GL_TEXTURE0);
            //glBindTexture(GL_TEXTURE_2D, m_pTextureArr[nCurIndex]);
            //glUniform1i(glTexture, 0);
            GL::bindTexture2D(m_pTextureArr[nCurIndex]);
    
            GLuint glAlpha = m_glprogram->getUniformLocationForName("u_alpha");
            glUniform1f(glAlpha, falpha);
    
            glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
            glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, 0, ccRenderTextcord);
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
            falpha += addf;
            addf += 0.025f;
            nCurIndex = ++nCurIndex<REMIND_RENDER_COUNT ? nCurIndex : 0; 
        } while (nCurIndex != nBeginIndex);
    //
    //    GL::bindVAO(0);
        //glBindBuffer(GL_ARRAY_BUFFER, 0);
        //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    }
    void RemindShader::CreateFrameBuffer()
    {
    
        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_nOldFBO);
        if (m_nFrameBuffer == 0)
        {
            glGenFramebuffers(1, &m_nFrameBuffer);
    
            if (m_nFrameBuffer == 0)
            {
                CCLOG("m_FilterFrameBuffer == 0");
                return;
            }
        }
        GLsizei nWidth = m_sRenderSize.width;
        GLsizei nHeight = m_sRenderSize.height;
        glBindFramebuffer(GL_FRAMEBUFFER, m_nFrameBuffer);
        if (m_pTextureArr[0] == 0)
        {
            glGenTextures(REMIND_RENDER_COUNT, m_pTextureArr);
            for (int i = 0; i < REMIND_RENDER_COUNT; i++)
            {
                glActiveTexture(GL_TEXTURE0);
                glBindTexture(GL_TEXTURE_2D, m_pTextureArr[i]);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
                GLenum err = glGetError();
                if (err != GL_NO_ERROR)
                {
                    CCLOG("cocos2d: Texture2D: Error uploading compressed texture glError: 0x%04X", err);
                    return;
                }
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pTextureArr[i], 0);
                glClearColor(0.0, 0.0, 0.0, 0.0);
                glClear(GL_COLOR_BUFFER_BIT);
            }
        }
        glBindFramebuffer(GL_FRAMEBUFFER, m_nOldFBO);
    }
      
    
    void RemindShader::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
    {
        if (sRenderChild.size() <= 0 )
        {
            if (m_nFrameBuffer)
            {
                // 清理所有缓存的纹理
                glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_nOldFBO);
                glBindFramebuffer(GL_FRAMEBUFFER, m_nFrameBuffer);
                for (int i = 0; i < REMIND_RENDER_COUNT; i++)
                {
                    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pTextureArr[i], 0);
                    glClearColor(0.0, 0.0, 0.0, 0.0);
                    glClear(GL_COLOR_BUFFER_BIT);
                }
                glBindFramebuffer(GL_FRAMEBUFFER, m_nOldFBO);
            }
            m_nRenderCount = m_nRenderFrq - 1;
            return;
        }
        //Begin will create a render group using new render target
        begin();
    
        if (++m_nRenderCount == m_nRenderFrq)
        {
            //! make sure all children are drawn 
            auto it = sRenderChild.begin();
            while (it != sRenderChild.end())
            {
                if (Node* node = *it)
                {
                    node->visit(renderer, transform, flags);
                    node->release();
                }
                ++it;
            }
            m_nRenderCount = 0;    // 0 提示需要渲染进去
        }
        sRenderChild.clear();
        //End will pop the current render group
        end();
    
    }
    View Code

    几个关键点:

    1、利用REMIND_RENDER_COUNT控制需要创建的Texture个数,通过每次绘制到不同的Texture上来保存原来的效果。

    2、shader中利用u_alpha参数控制残影的透明度,在render中绘制到原来的FBO上时调用不同的透明度来实现残影渐隐的效果。

    3、通过m_nRenderFrq来控制间隔的绘制次数,来实现残影的残留效果远近。

    这样就实现了残影的效果了,使用的方法还是跟基类一样。

    完整代码地址:https://github.com/mydishes/cocos2dx-Ex/tree/master/Shader

  • 相关阅读:
    [HDU1087]Super Jumping! Jumping! Jumping!<dp>
    [codeforces]Page Numbers <模拟>
    [POJ1190]生日蛋糕<DFS>
    [HDU1029]Ignatius and the Princess IV<桶 水题>
    矩阵优化
    康复式训练
    bzoj1036 [ZJOI2008]树的统计Count
    luogu3761 [TJOI2017]城市
    bzoj2282 [SDOI2011]消防
    NOI2014
  • 原文地址:https://www.cnblogs.com/stratrail/p/5072632.html
Copyright © 2011-2022 走看看