20 January 2016
版权声明:本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名elloop(包含链接)

#前言

本文介绍了如何在cocos2d-x中使用自定义shader来实现混合颜色矩形的绘制。文中继续使用前一篇文章中定义的CustomDrawNode类来实现绘制过程,在其基础上派生出ColorfulRectangle类,使用一对新的shader。

绘制的效果图如下所示:

colorful_rectangle.jpg

绘制的实现

关于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,  y,          _randomColor4f[1][0], _randomColor4f[1][1], _randomColor4f[1][2], 1,
        x,          y + height, _randomColor4f[2][0], _randomColor4f[2][1], _randomColor4f[2][2], 1,
        x + width,  y + height, _randomColor4f[3][0], _randomColor4f[3][1], _randomColor4f[3][2], 1,
    };

    // 启用顶点数组
    glEnableVertexAttribArray(_attribPosition);
    glEnableVertexAttribArray(_attribColor);

    // 上传顶点数组值到OpenGL服务器
    glVertexAttribPointer(_attribPosition, 2, GL_FLOAT, false, sizeof(V2F_C4F), &vertexes[0].x);
    glVertexAttribPointer(_attribColor, 4, GL_FLOAT, false, sizeof(V2F_C4F), &vertexes[0].r);

    // 绘制
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 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.
}

源码

CustomDrawNodePage.h

CustomDrawNodePage.cpp


作者水平有限,对相关知识的理解和总结难免有错误,还望给予指正,非常感谢!

在这里也能看到这篇文章:github博客, CSDN博客, 欢迎访问



分享到