cocos2d-x中流光效果

shader代码

#ifdef GL_ES 
precision lowp float;                        
#endif 

uniform sampler2D u_texture;                
uniform sampler2D u_mask;               
uniform float factor;
uniform float width;                
uniform float offset;               
uniform vec3 color; 

varying vec4 v_fragmentColor;                
varying vec2 v_texCoord;

const float SQRT_2 = 1.414f;

void main()                                    
{                                            
    vec4 texColor = texture2D(u_texture, v_texCoord);
    // line (x+y-offset=0) offset:[0, 2] (2->0)
    // |y
    // |
    // ____|0___ 1___2____x
    // | |
    // |____|*
    float distance = abs(v_texCoord[0]+v_texCoord[1]-offset)/SQRT_2; 
    // linear gradient 
    // (1/width)x + y = 1
    distance = 1.0f-(1.0f/width)*distance;
    distance = max(distance, 0.0f);

    vec4 sample = vec4(0.0f,0.0f,0.0f,0.0f);
    sample.rgb = color * distance;
    sample.a = distance;

    // blend additive 
    float alpha = sample[3]*texColor[3];
    texColor[0] = texColor[0] + sample[0]*alpha*factor;
    texColor[1] = texColor[1] + sample[1]*alpha*factor;
    texColor[2] = texColor[2] + sample[2]*alpha*factor;
    gl_FragColor = v_fragmentColor * texColor;            
}

cocos2d-x中的代码

  • ShaderNode.h
#pragma once
#pragma ececution_character_set("utf-8")
#include <iostream>
#include "cocos2d.h"
#include "ui/CocosGUI.h"


class ShaderNode : public cocos2d::Node
{
public:
    CREATE_FUNC(ShaderNode);
    static ShaderNode* shaderNodeWithVertex(const std::string &vert, const std::string &frag);

    virtual void update(float dt) override;
    virtual void setPosition(const cocos2d::Vec2 &newPosition) override;
    virtual void draw(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t flags) override;

protected:
    ShaderNode();
    ~ShaderNode();

    bool initWithVertex(const std::string &vert, const std::string &frag);
    void loadShaderVertex(const std::string &vert, const std::string &frag);

    void onDraw(const cocos2d::Mat4& transform, uint32_t flags);

    cocos2d::Vec2 _center;
    cocos2d::Vec2 _resolution;
    cocos2d::Vec3  _color;
    float      _factor;
    float      _windth;
    float      _offset;
    float      _time;
    cocos2d::Sprite * _sprite;
    std::string _vertFileName;
    std::string _fragFileName;
    cocos2d::CustomCommand _customCommand;
};
  • ShaderNode.cpp
#include "ShaderNode.h"
USING_NS_CC;
///---------------------------------------
// 
// ShaderNode
// 
///---------------------------------------
enum
{
    SIZE_X = 256,
    SIZE_Y = 256,
};

ShaderNode::ShaderNode()
:_time(0.0f)
, _factor(1.0f)
, _windth(0.3f)
, _offset(2.0f)
, _color(Vec3(0.4f,0.4f,0.4f))
{
}

ShaderNode::~ShaderNode()
{
}

ShaderNode* ShaderNode::shaderNodeWithVertex(const std::string &vert, const std::string& frag)
{
    auto node = new (std::nothrow) ShaderNode();
    node->initWithVertex(vert, frag);
    node->autorelease();

    return node;
}

bool ShaderNode::initWithVertex(const std::string &vert, const std::string &frag)
{
    _vertFileName = vert;
    _fragFileName = frag;
#if CC_ENABLE_CACHE_TEXTURE_DATA
    auto listener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event){
        this->setGLProgramState(nullptr);
        loadShaderVertex(_vertFileName, _fragFileName);
    });

    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
#endif

    loadShaderVertex(vert, frag);

    _time = 0;
    _resolution = Vec2(SIZE_X, SIZE_Y);

    scheduleUpdate();

    setContentSize(Size(SIZE_X, SIZE_Y));
    setAnchorPoint(Vec2(0.5f, 0.5f));


    return true;
}

void ShaderNode::loadShaderVertex(const std::string &vert, const std::string &frag)
{
    auto fileUtiles = FileUtils::getInstance();

    // frag
    auto fragmentFilePath = fileUtiles->fullPathForFilename(frag);
    auto fragSource = fileUtiles->getStringFromFile(fragmentFilePath);

    // vert
    std::string vertSource;
    if (vert.empty()) {
        vertSource = ccPositionTextureColor_vert;
    }
    else {
        std::string vertexFilePath = fileUtiles->fullPathForFilename(vert);
        vertSource = fileUtiles->getStringFromFile(vertexFilePath);
    }
    //_sprite = Sprite::createWithSpriteFrameName("PushCard1.png");
    auto sp = Sprite::create("PushCard1.png");
    _sprite = Sprite::createWithTexture(sp->getTexture());
    auto glprogram = GLProgram::createWithByteArrays(vertSource.c_str(), fragSource.c_str());
    auto glprogramstate = GLProgramState::getOrCreateWithGLProgram(glprogram);
    _sprite->setGLProgramState(glprogramstate);

    addChild(_sprite);
    //setGLProgramState(glprogramstate);
}

void ShaderNode::update(float dt)
{
    //_time += dt;
    if (_factor > 4.0f)
    {
        _factor = 1.4f;
    }
    _offset = _offset - dt;
    if (_offset < 0.0f)
    {
        _offset = 3.0f;
    }
}

void ShaderNode::setPosition(const Vec2 &newPosition)
{
    Node::setPosition(newPosition);
    auto position = getPosition();
    auto frameSize = Director::getInstance()->getOpenGLView()->getFrameSize();
    auto visibleSize = Director::getInstance()->getVisibleSize();
    auto retinaFactor = Director::getInstance()->getOpenGLView()->getRetinaFactor();
    _center = Vec2(position.x * frameSize.width / visibleSize.width * retinaFactor, position.y * frameSize.height / visibleSize.height * retinaFactor);
}

void ShaderNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    _customCommand.init(_globalZOrder, transform, flags);
    _customCommand.func = CC_CALLBACK_0(ShaderNode::onDraw, this, transform, flags);
    renderer->addCommand(&_customCommand);
}

void ShaderNode::onDraw(const Mat4 &transform, uint32_t flags)
{
    //float w = SIZE_X, h = SIZE_Y;
    //GLfloat vertices[12] = { 0, 0, w, 0, w, h, 0, 0, 0, h, w, h };

    auto glProgramState = _sprite->getGLProgramState();
    //glProgramState->setUniformVec2("resolution", _resolution);
    //glProgramState->setUniformVec2("center", _center);
    glProgramState->setUniformFloat("factor", _factor);
    glProgramState->setUniformFloat("width", _windth);
    glProgramState->setUniformFloat("offset", _offset);
    glProgramState->setUniformVec3("color", _color);
    glProgramState->setUniformTexture("u_texture", _sprite->getTexture());
    //glProgramState->setVertexAttribPointer("a_position", 2, GL_FLOAT, GL_FALSE, 0, vertices);
    //glProgramState->apply(transform);

    //glDrawArrays(GL_TRIANGLES, 0, 6);

    //CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, 6);
}

ShaderNode用法

auto sn = ShaderNode::shaderNodeWithVertex("", "efx_stream.fsh");
    auto s = Director::getInstance()->getWinSize();
    sn->setPosition(Vec2(s.width / 2, s.height / 2));
    addChild(sn);