背景:
想要在项目中添加一个随机的光晕效果,使用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;
}
效果如下:
玩具而已,大家作个参考。