前言
本文介绍了如何在cocos2d-x中使用自定义shader来实现混合颜色矩形的绘制。文中继续使用前一篇文章中定义的CustomDrawNode类来实现绘制过程,在其基础上派生出ColorfulRectangle
类,使用一对新的shader。
绘制的效果图如下所示:
绘制的实现
关于CustomDrawNode类的实现这里不再介绍,详情请参考前一篇文章《使用CCGLProgram实现自定义绘制》。下面给出着色器源码和彩色矩形绘制类ColorfulRectangle
的实现:
1.顶点着色器: colorful_rect_vert.glsl
#ifdef GL_ES
precision mediump float;
#endif
attribute vec2 custom_a_position; // 顶点位置
attribute vec4 custom_a_color; // 顶点颜色
varying vec4 v_color; // 输出变量到片段着色器
void main()
{
vec4 pos = vec4(custom_a_position,0,1);
gl_Position = CC_MVPMatrix * pos;
v_color = custom_a_color;
}
2. 片段着色器:colorful_rect_frag.glsl
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color; // 从顶点shader中输入的颜色
void main()
{
gl_FragColor = v_color;
}
3. ColorfulRectangle的实现
// .h
class ColorfulRectangle : public CustomDrawNode
{
public:
static ColorfulRectangle* create(const char *vs,const char *fs);
void draw() override;
void customSetupBeforeLink() override; // 模板方法请参见CustomDrawNode的实现
void customUniformsUpdate() override; // 模板方法请参见CustomDrawNode的实现
protected:
// 顶点数组结构,两个float类型的顶点位置和四个float表示的顶点颜色。
struct V2F_C4F
{
GLfloat x,y;
GLfloat r,g,b,a;
};
ColorfulRectangle() : _attribPosition(0),_attribColor(1)
{
for ( size_t i = 0; i < 4; ++i )
{
_randomColor4f[i][0] = CCRANDOM_0_1(); // 顶点使用随机颜色值分量 r
_randomColor4f[i][1] = CCRANDOM_0_1(); // 顶点使用随机颜色值分量 g
_randomColor4f[i][2] = CCRANDOM_0_1(); // 顶点使用随机颜色值分量 b
}
}
const attribute _attribPosition; // 绑定顶点着色器中custom_a_position变量
const attribute _attribColor; // 绑定顶点着色器中custom_a_color变量
GLfloat _randomColor4f[4][3]; // 四个顶点颜色变量
};
// .cpp
// 使用shader文件名来创建一个ColorfulRectangle对象
ColorfulRectangle* ColorfulRectangle::create(const char *vs,const char *fs)
{
auto self = new ColorfulRectangle;
if (self && self->initWithShaders(vs,fs)) // 调用CustomDrawNode的initWithShaders()方法
{
self->autorelease();
return self;
}
return nullptr;
}
// 绘制方法
void ColorfulRectangle::draw()
{
CC_NODE_DRAW_SETUP(); // 调用program->use(),为预定义的uniform赋值
// 定义矩形的宽高和位置
auto size = CocosWindow::size();
auto center = CocosWindow::center();
GLfloat width = size.width / 2;
GLfloat height = size.height / 2;
GLfloat x = center.x - width / 2;
GLfloat y = center.y - height / 2;
// 顶点数组,两个位置分量(x,y) + 4个颜色分量,color.rgb使用随机值,color.a使用1,不透明
V2F_C4F vertexes[] =
{
x,y,_randomColor4f[0][0],_randomColor4f[0][1],_randomColor4f[0][2],1,x + width,_randomColor4f[1][0],_randomColor4f[1][1],_randomColor4f[1][2],x,y + height,_randomColor4f[2][0],_randomColor4f[2][1],_randomColor4f[2][2],_randomColor4f[3][0],_randomColor4f[3][1],_randomColor4f[3][2],};
// 启用顶点数组
glEnableVertexAttribArray(_attribPosition);
glEnableVertexAttribArray(_attribColor);
// 上传顶点数组值到OpenGL服务器
glVertexAttribPointer(_attribPosition,2,GL_FLOAT,false,sizeof(V2F_C4F),&vertexes[0].x);
glVertexAttribPointer(_attribColor,4,&vertexes[0].r);
// 绘制
glDrawArrays(GL_TRIANGLE_STRIP,4);
CC_INCREMENT_GL_DRAWS(1);
}
void ColorfulRectangle::customSetupBeforeLink()
{
// 在shader program link之前,绑定shader中的attribute.
getShaderProgram()->addAttribute("custom_a_position",_attribPosition);
getShaderProgram()->addAttribute("custom_a_color",_attribColor);
}
void ColorfulRectangle::customUniformsUpdate()
{
// nothing.
}
4. 测试代码
测试代码在CustomDrawNode::loadUI()方法中:
auto colorRectangle = ColorfulRectangle::create("shaders/colorful_rect_vert.glsl","shaders/colorful_rect_frag.glsl");
addChild(colorRectangle);
遇到的问题
犯了一个低级错误,调试了半天才发现。
在colorRectangle的构造函数中,错误的把两个attribute的绑定常量都初始化为0,导致在draw方法中在使用glVertexAttribPointer(location,…)时候,顶点位置被颜色覆盖,绘制的结果就只有一个点,而不是矩形。
ColorfulRectangle() : _attribPosition(0),_attribColor(0) // 第二个常量应该为:_attribColor(1)
{
for ( size_t i = 0; i < 4; ++i )
{
_randomColor4f[i][0] = CCRANDOM_0_1();
_randomColor4f[i][1] = CCRANDOM_0_1();
_randomColor4f[i][2] = CCRANDOM_0_1();
}
}
// 如果两个常量都是0,绑定attribute的时候顶点位置的绑定就被颜色覆盖了。
void ColorfulRectangle::customSetupBeforeLink()
{
getShaderProgram()->addAttribute("custom_a_position",_attribPosition); // 0
getShaderProgram()->addAttribute("custom_a_color",_attribColor); // alse 0,no no no.
}
源码
作者水平有限,对相关知识的理解和总结难免有错误,还望给予指正,非常感谢!