使用glsl实现cocos2dx平台下的随机光晕效果

背景:

想要在项目中添加一个随机的光晕效果,使用glsl做了一个简单的实现,实际意义不大,贴上来给看到的人做一个参考

//CirlieLight.h
#include "cocos2d.h"

USING_NS_CC;

class CircleLight : public CCNode
{
public:
    CircleLight();

    bool initWithRadius(int innerRadius, int radius);
    bool initWithAllParm(int innerRadius, int radius, float timeCircle, float alphaParm, ccColor4F color);
    void loadShaderVertex(const char *vert, const char *frag);

    virtual void update(float delta);
    virtual void setContentSize(const CCSize& contentSize);
    virtual void setColor(ccColor4F newColor);
    virtual void draw();
    void setRelativePosition(CCPoint point);

    static CircleLight* createCircleLight(int innerRadius, int radius);
    static CircleLight* createCircleLight(int innerRadius, int radius, float timeCircle, float alphaParm, ccColor4F color);

    void setWatchLayer(CCLayer *layer, int distance = 0);
private:
    GLuint m_ucenter, m_uinnerRadius, m_uradius, m_utime, m_ualphaParm, m_utimeCircle, m_ucolor;
    GLuint m_attributeColor, m_attributePosition;
    GLuint m_utexture;

    GLuint m_uniformTex0;
    GLfloat m_innerRadius, m_radius, m_time, m_alphaParm, m_timeCircle;
    ccVertex2F m_center;
    ccColor4F m_color;
    GLfloat color[4];

    ccBlendFunc m_blendFunc;// = {GL_SRC_ALPHA, GL_ONE};  

    int m_distance;
    CCLayer *m_watchLayer;
    int m_initialHeight;

    CCPoint m_relativePosition;
    
};

#include "CircleLight.h"


CircleLight::CircleLight()
{


}


CircleLight *CircleLight::createCircleLight(int innerRadius, int radius)
{
    CircleLight *circel = new CircleLight();
    if(circel && circel->initWithRadius(innerRadius, radius))
    {
        circel->autorelease();
        return circel;
    }
    else
    {
        CC_SAFE_DELETE(circel);
        return NULL;
    }
}


//如参数名所示,我们的光晕由以下参数生成:光晕内直径,外直径,闪烁周期,alpha参数,颜色
//其中alpha参数传递给shader使用,可以调控闪烁的强度
CircleLight *CircleLight::createCircleLight(int innerRadius, int radius, float timeCircle, float alphaParm, ccColor4F color)
{
    CircleLight* light = new CircleLight();


    if(light != NULL && light->initWithAllParm(innerRadius, radius, timeCircle, alphaParm, color))
    {
        light->autorelease();
        return light;
    }
    else
    {
        CC_SAFE_DELETE(light);
        return NULL;
    }
}


bool CircleLight::initWithAllParm(int innerRadius, int radius, float timeCircle, float alphaParm, ccColor4F color)
{
    if(innerRadius > radius || timeCircle <= 0.0f || alphaParm < 0.0f)
        return false;


    m_innerRadius = innerRadius;
    m_radius = radius;
    m_timeCircle = timeCircle;
    m_alphaParm = alphaParm;
    m_color = color;


    m_watchLayer = NULL;


    loadShaderVertex("circlelight.vsh", "circlelight.fsh");


    setContentSize(CCSizeMake(m_radius * 2, m_radius * 2));


    m_blendFunc.src = GL_SRC_ALPHA;
    m_blendFunc.dst = GL_ZERO;


    m_time = 0.0f;
    this->scheduleUpdate();
    return true;
}


bool CircleLight::initWithRadius(int innerRadius, int radius)
{
    return initWithAllParm(innerRadius, radius, 3.0f, 0.0f, ccc4f(1.0f, 0.0f, 0.0f, 0.0f));


    //loadShaderVertex("circlelight.vsh", "circlelight.fsh");
    //m_innerRadius = innerRadius;
    //m_radius = radius;
    //m_utexture = CCTextureCache::sharedTextureCache()->addImage("CloseNormal.png")->getName();


    //setContentSize(CCSizeMake(100, 100));
    //setColor(ccc4f(0.5, 0.5, 0.5, 1));


    m_blendFunc = ccBlendFunc(GL_SRC_ALPHA, GL_ONE);
    //m_blendFunc.src = GL_SRC_ALPHA;
    //m_blendFunc.dst = GL_ONE;


    //m_time = 0.0f;
    //this->scheduleUpdate();
    //return true;
}


//加载shader程序,为shader准备对应的参数
void CircleLight::loadShaderVertex(const char *vert, const char *frag)
{
    CCGLProgram *shader = new CCGLProgram();


    shader->initWithVertexShaderFilename(vert, frag);


    shader->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
    shader->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
    shader->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);

    shader->link();

    shader->updateUniforms();
    m_ucenter = glGetUniformLocation(shader->getProgram(), "center");
    m_uinnerRadius = glGetUniformLocation(shader->getProgram(), "u_innerRadius");
    m_uradius = glGetUniformLocation(shader->getProgram(), "u_radius");
    m_utime = glGetUniformLocation(shader->getProgram(), "u_time");
    m_utimeCircle = glGetUniformLocation(shader->getProgram(), "u_timeCircle");
    m_ualphaParm = glGetUniformLocation(shader->getProgram(), "u_alphaParm");
    m_ucolor = glGetUniformLocation(shader->getProgram(), "u_color");


    this->setShaderProgram(shader);
    shader->release();
}


void CircleLight::setColor(ccColor4F newColor)
{
    m_color = newColor;
}


void CircleLight::setWatchLayer(CCLayer *layer, int distance /* = 0 */)
{
    m_watchLayer = layer;
    
    m_distance = distance;


    m_initialHeight = m_watchLayer->getPositionY();


    this->setZOrder(-m_distance);
}


void CircleLight::setRelativePosition(CCPoint point)
{
    m_relativePosition = point;
   
}


void CircleLight::update(float delta)
{
    m_time += delta;


    if(m_watchLayer != NULL)
    {
        int yOffset = (m_watchLayer->getPositionY() - m_initialHeight) / m_distance;
        
        this->setPosition(ccp(m_relativePosition.x, m_relativePosition.y + yOffset));
    }


    if(this->getPositionY() < -100)
    {
        this->getParent()->removeChild(this);
    }


    //CCLog("light position : (%f, %f)", this->getPositionX(), this->getPositionY());
}


void CircleLight::setContentSize(const CCSize& contentSize)
{
    CCNode::setContentSize(contentSize);


    m_center.x = contentSize.width / 2.0f;
    m_center.y = contentSize.height/2.0f;
}


void CircleLight::draw()
{
    CC_NODE_DRAW_SETUP();


    CCGLProgram *shader = getShaderProgram();
    shader->setUniformLocationWith2f(m_ucenter, m_center.x, m_center.y);
    shader->setUniformLocationWith1f(m_uinnerRadius, m_innerRadius);
    shader->setUniformLocationWith1f(m_uradius, m_radius);
    shader->setUniformLocationWith1f(m_utime, m_time);
    shader->setUniformLocationWith1f(m_utimeCircle, m_timeCircle);
    shader->setUniformLocationWith1f(m_ualphaParm, m_alphaParm);
    shader->setUniformLocationWith4f(m_ucolor, m_color.r, m_color.g, m_color.b, m_color.a);


    CCSize size = this->getContentSize();
    float w = size.width;
    float h = size.height;


    //ccGLBindTexture2D(GL_TEXTURE_2D);
    //glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, w, h, 0);
    glEnableVertexAttribArray(kCCVertexAttrib_Position);
    //ccGLBlendFunc(m_blendFunc.src, m_blendFunc.dst);


    GLfloat vertices1[12] = {
        0, 0,
        w, 0,
        w, h,
        0, 0,
        w, h,
        0, h,
    };




    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices1);
    //glVertexAttrib4fv(kCCVertexAttrib_Color, color);


    glDrawArrays(GL_TRIANGLES, 0, 6);
}

//circlelight.fsh
varying vec4 v_position;

uniform vec2 center;
uniform float u_innerRadius;
uniform float u_radius;
uniform float u_time;
uniform float u_timeCircle;
uniform float u_alphaParm;
uniform vec4 u_color;

void main(void)
{
    float dis = distance(center, vec2(v_position.x, v_position.y));
    float alpha;
	float timeCircle = u_timeCircle;
	float time = mod(u_time, timeCircle);
	time = abs(time - timeCircle/2.0);
	if(dis < u_radius)
	{
		alpha =1- smoothstep(u_innerRadius, u_radius, dis);
		//alpha = alpha * clamp((time + 1) / timeCircle/2.0, 0.0f, 1.0f);
		alpha = alpha * (time / timeCircle/2.0f +u_alphaParm);
		//gl_FragColor = vec4(1.0, 0.0, 0.0, alpha);
		gl_FragColor = vec4(u_color.rgb, alpha);
	}
	else
	{
		gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
	}

}


//circlelight.vsh
attribute vec4 a_position;
varying vec4 v_position;

void main()
{
    gl_Position = CC_MVPMatrix * a_position;
    v_position = a_position;
}

效果如下:

玩具而已,大家作个参考。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cocos2d-x中实现流光效果可以使用shader来进行渲染。首先,我们需要创建一个自定义的shader,并将其应用于需要实现流光效果的节点上。 在使用Cocos2d-x的过程中,我们可以使用GLSL语言编写shader代码。在实现流光效果的shader中,我们可以通过改变像素的颜色和透明度来创建流动的效果。 首先,我们定义一个uniform变量time,用于控制流光的移动速度。然后,在片段着色器中,通过改变颜色和透明度的计算公式来实现流动的效果。我们可以使用sin函数或者其他数学函数来计算出每个像素点的颜色和透明度,然后将其应用到节点上。 在节点的渲染流程中,我们将这个自定义的shader应用到节点上,然后传入时间参数,即更新uniform变量time的值。随着时间的增加,我们就可以看到节点上的流光效果在不断地移动。 为了实现更加逼真的流光效果,我们可以尝试给流光添加一些额外的效果,比如模糊、叠加等。通过调整shader代码中的计算公式和传入的参数,我们可以根据自己的需求来调整流光效果的强度和样式。 总结起来,在Cocos2d-x中实现流光效果需要创建一个自定义的shader,并将其应用于需要实现效果的节点上。通过改变颜色和透明度的计算公式、传入时间参数等,我们可以实现一个流光效果,使节点看起来具有流动的动画效果

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值