Cocos2dx渲染---从DrawNode切入

一、先从画一条线开始

1.drawLine使用方法

auto scene = Scene::create();
Director::getInstance()->runWithScene(scene);
auto node = DrawNode::create();
//传入两个定点与线的颜色
node->drawLine(Vec2(1,1),Vec2(1,222),Color4F(222,1,1,1));
scene->addChild(node);

2.进入drawLine

//主要是告诉有几个定点以及定点的位置
void DrawNode::drawLine(const Vec2 &origin, const Vec2 &destination, const Color4F &color)
{
ensureCapacityGLLine(2);
V2F_C4B_T2F *point = (V2F_C4B_T2F*)(_bufferGLLine + _bufferCountGLLine);
V2F_C4B_T2F a = {origin, Color4B(color), Tex2F(0.0, 0.0)};
V2F_C4B_T2F b = {destination, Color4B(color), Tex2F(0.0, 0.0)};
*point = a;
*(point+1) = b;
_bufferCountGLLine += 2;
_dirtyGLLine = true;
}

3.渲染准备

bool DrawNode::init()
{
_blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR));
ensureCapacity(512);
ensureCapacityGLPoint(64);
ensureCapacityGLLine(256);
if (Configuration::getInstance()->supportsShareableVAO())
{
//创建一个VAO顶点数组对象:可以被绑定,任何随后的定点属性都会存储在这个_vao中
glGenVertexArrays(1, &_vao);
GL::bindVAO(_vao);
//创建一个VBO顶点缓冲对象:可以在显存里面存储大量的定点,使用的好处是可以一次性的发送一大批数据到显卡上。
glGenBuffers(1, &_vbo);
//把创建的缓冲绑定到GL_ARRAY_BUFFER上面,从这一刻起,使用的任何(在GL_ARRAY_BUFFER目标上的)缓冲调用都会用来配置当前绑定的缓冲(VBO)
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
//把定义的定点数据复制到内存
glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)* _bufferCapacity, _buffer, GL_STREAM_DRAW);
// vertex
//启用定点属性
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
//如何解析定点数据
//参数1:配置的定点属性,与顶点着色器有关
//参数2:一个属性的大小
//参数3:数据类型
//参数4:GL_TRUE的话,数据都会被转化为0-1之间或者有符号的-1-1之间
//参数5:两个定点之间的距离
//参数6:最后一个参数的类型是void*,所以需要我们进行这个奇怪的强制类型转换。
//它表示位置数据在缓冲中起始位置的偏移量(Offset)。
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, vertices));
// color
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, colors));
// texcoord
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_TEX_COORD);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, texCoords));
/*
*
*/
//省略删除
}
else
{
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)* _bufferCapacity, _buffer, GL_STREAM_DRAW);
glGenBuffers(1, &_vboGLLine);
glBindBuffer(GL_ARRAY_BUFFER, _vboGLLine);
glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)*_bufferCapacityGLLine, _bufferGLLine, GL_STREAM_DRAW);
glGenBuffers(1, &_vboGLPoint);
glBindBuffer(GL_ARRAY_BUFFER, _vboGLPoint);
glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)*_bufferCapacityGLPoint, _bufferGLPoint, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
CHECK_GL_ERROR_DEBUG();
_dirty = true;
_dirtyGLLine = true;
_dirtyGLPoint = true;
#if CC_ENABLE_CACHE_TEXTURE_DATA
// Need to listen the event only when not use batchnode, because it will use VBO
auto listener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event){
/** listen the event that renderer was recreated on Android/WP8 */
this->init();
});
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
#endif
return true;
}

4.渲染

(1).draw

void DrawNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
if(_bufferCount)
{
_customCommand.init(_globalZOrder, transform, flags);
_customCommand.func = CC_CALLBACK_0(DrawNode::onDraw, this, transform, flags);
renderer->addCommand(&_customCommand);
}
if(_bufferCountGLPoint)
{
_customCommandGLPoint.init(_globalZOrder, transform, flags);
_customCommandGLPoint.func = CC_CALLBACK_0(DrawNode::onDrawGLPoint, this, transform, flags);
renderer->addCommand(&_customCommandGLPoint);
}
if(_bufferCountGLLine)
{
//这里可以看到,用的是custom自定义的渲染指令
_customCommandGLLine.init(_globalZOrder, transform, flags);
_customCommandGLLine.func = CC_CALLBACK_0(DrawNode::onDrawGLLine, this, transform, flags);
renderer->addCommand(&_customCommandGLLine);
}
}

(2).onDrawGLLine

void DrawNode::onDrawGLLine(const Mat4 &transform, uint32_t /*flags*/)
{
//使用默认的着色器
auto glProgram = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR);
glProgram->use();
glProgram->setUniformsForBuiltins(transform);
glProgram->setUniformLocationWith1f(glProgram->getUniformLocation("u_alpha"), _displayedOpacity / 255.0);
//设置混合模式
GL::blendFunc(_blendFunc.src, _blendFunc.dst);
if (_dirtyGLLine)
{
glBindBuffer(GL_ARRAY_BUFFER, _vboGLLine);
glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)*_bufferCapacityGLLine, _bufferGLLine, GL_STREAM_DRAW);
_dirtyGLLine = false;
}
if (Configuration::getInstance()->supportsShareableVAO())
{
//绑定vao
GL::bindVAO(_vaoGLLine);
}
else
{
glBindBuffer(GL_ARRAY_BUFFER, _vboGLLine);
GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);
// vertex
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, vertices));
// color
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, colors));
// texcoord
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, texCoords));
}
//设置线的宽度
glLineWidth(_lineWidth);
//绘制GL_LINES
glDrawArrays(GL_LINES, 0, _bufferCountGLLine);
//解绑vao
if (Configuration::getInstance()->supportsShareableVAO())
{
GL::bindVAO(0);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
//添加本次渲染的信息 3个顶点信息与一次drawCall
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,_bufferCountGLLine);
CHECK_GL_ERROR_DEBUG();
}

二、看看其他图形

1.点

void DrawNode::drawPoint(const Vec2& position, const float pointSize, const Color4F &color)
{
ensureCapacityGLPoint(1);
V2F_C4B_T2F *point = (V2F_C4B_T2F*)(_bufferGLPoint + _bufferCountGLPoint);
V2F_C4B_T2F a = {position, Color4B(color), Tex2F(pointSize,0)};
*point = a;
_bufferCountGLPoint += 1;
_dirtyGLPoint = true;
}

可以看到drawPoint用的是_bufferGLPoint,对应的VAO是_vaoGLPoint,所以渲染的方法对应使用的vao、vbo是:

void DrawNode::onDrawGLPoint(const Mat4 &transform, uint32_t /*flags*/)
{
auto glProgram = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_COLOR_TEXASPOINTSIZE);
glProgram->use();
glProgram->setUniformsForBuiltins(transform);
glProgram->setUniformLocationWith1f(glProgram->getUniformLocation("u_alpha"), _displayedOpacity / 255.0);
GL::blendFunc(_blendFunc.src, _blendFunc.dst);
if (_dirtyGLPoint)
{
glBindBuffer(GL_ARRAY_BUFFER, _vboGLPoint);
glBufferData(GL_ARRAY_BUFFER, sizeof(V2F_C4B_T2F)*_bufferCapacityGLPoint, _bufferGLPoint, GL_STREAM_DRAW);
_dirtyGLPoint = false;
}
if (Configuration::getInstance()->supportsShareableVAO())
{
GL::bindVAO(_vaoGLPoint);
}
else
{
glBindBuffer(GL_ARRAY_BUFFER, _vboGLPoint);
GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, vertices));
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, colors));
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), (GLvoid *)offsetof(V2F_C4B_T2F, texCoords));
}
glDrawArrays(GL_POINTS, 0, _bufferCountGLPoint);
if (Configuration::getInstance()->supportsShareableVAO())
{
GL::bindVAO(0);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,_bufferCountGLPoint);
CHECK_GL_ERROR_DEBUG();
}

2.其他,例如drawDot

void DrawNode::drawDot(const Vec2 &pos, float radius, const Color4F &color)
{
unsigned int vertex_count = 2*3;
ensureCapacity(vertex_count);
V2F_C4B_T2F a = {Vec2(pos.x - radius, pos.y - radius), Color4B(color), Tex2F(-1.0, -1.0) };
V2F_C4B_T2F b = {Vec2(pos.x - radius, pos.y + radius), Color4B(color), Tex2F(-1.0, 1.0) };
V2F_C4B_T2F c = {Vec2(pos.x + radius, pos.y + radius), Color4B(color), Tex2F( 1.0, 1.0) };
V2F_C4B_T2F d = {Vec2(pos.x + radius, pos.y - radius), Color4B(color), Tex2F( 1.0, -1.0) };
V2F_C4B_T2F_Triangle *triangles = (V2F_C4B_T2F_Triangle *)(_buffer + _bufferCount);
V2F_C4B_T2F_Triangle triangle0 = {a, b, c};
V2F_C4B_T2F_Triangle triangle1 = {a, c, d};
triangles[0] = triangle0;
triangles[1] = triangle1;
_bufferCount += vertex_count;
_dirty = true;
}

用的数据块是_buffer,对应的是_vao。


如有问题,及时指出。

posted @   HahaAndZoe  阅读(111)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示