cocos源码分析--LayerColor的绘制过程
1开始,先创建一个LayerColor
Scene *scene=Scene::create();
director->runWithScene(scene);
//目标
auto layer = LayerColor::create(Color4B(, , , ), , );
//主要的步骤就是设置了node 的 _position
layer->setPosition(,);
scene->addChild(layer);
2 看一下LayerColor的初始化方法
bool LayerColor::initWithColor(const Color4B& color, GLfloat w, GLfloat h)
{
if (Layer::init())
{ // default blend function
//指定混合模式
_blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED; /*
realColor和displayedColor 记录元素本身的颜色属性
displayedColor和displayedOpacity方法用于表示和父亲元素叠加过后的最终绘制颜色
sprite用于父亲颜色和自己纹理的混合,LayColor默认一致,不叠加颜色
*/
_displayedColor.r = _realColor.r = color.r;
_displayedColor.g = _realColor.g = color.g;
_displayedColor.b = _realColor.b = color.b;
_displayedOpacity = _realOpacity = color.a; //四个顶点 初始化
for (size_t i = ; i<sizeof(_squareVertices) / sizeof( _squareVertices[]); i++ )
{
_squareVertices[i].x = 0.0f;
_squareVertices[i].y = 0.0f;
}
//四个顶点的颜色归一化,颜色是一样的
updateColor();
//w,h 为 设计分辨率,设置顶点的范围
setContentSize(Size(w, h));
/*
每个node拥有一个GLProgramState实例
查找这种类型的shader GLProgram SHADER_NAME_POSITION_COLOR_NO_MVP
*/
GLProgramState* state=GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_COLOR_NO_MVP); setGLProgramState(state);
return true;
}
return false;
}
/// override contentSize
void LayerColor::setContentSize(const Size & size)
{
//没有赋值的为0,也就是 0(0,0) 1(w,0) 2 (0,h) 3(w,h)
//绘制顺序为012 213
_squareVertices[].x = size.width;
_squareVertices[].y = size.height;
_squareVertices[].x = size.width;
_squareVertices[].y = size.height; Layer::setContentSize(size);
}
void Node::setContentSize(const Size & size)
{
if ( ! size.equals(_contentSize))
{
_contentSize = size;
//得到锚点在本地坐标系下的坐标
_anchorPointInPoints = Vec2(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y );
//告诉该更新了
_transformUpdated = _transformDirty = _inverseDirty = _contentSizeDirty = true;
}
}
3 Director::drawScene方法为正式绘图,如下
void Director::drawScene()
{
//省略部分代码 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //兼容cocos2.0,暂时忽略
pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); // draw the scene
if (_runningScene)
{//正式访问
_runningScene->visit(_renderer, Mat4::IDENTITY, false);//第一次的矩阵是单位矩阵 _eventDispatcher->dispatchEvent(_eventAfterVisit);
}
//开始真正的opengl
_renderer->render(); popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); _totalFrames++; // swap buffers
if (_openGLView)
{
_openGLView->swapBuffers();//这个之后再看
} if (_displayStats)
{
calculateMPF();//不知道啥意思
}
}
标红不分为开始遍历节点,但不进行opengl绘制,进入代码如下:
void Node::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags)
{
// quick return if not visible. children won't be drawn.
if (!_visible)
{
return;
} uint32_t flags = processParentFlags(parentTransform, parentFlags); // IMPORTANT:
// To ease the migration to v3.0, we still support the Mat4 stack,
// but it is deprecated and your code should not rely on it
/*
为了便于迁移到v3.0,我们仍然支持Mat4堆栈,
但它已被弃用,您的代码不应该依赖它
*/
Director* director = Director::getInstance();
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
//把刚生产的模型视图矩阵加入到顶部的modeview,作为最顶部的最新的modelviewTransform
//有的地方会用到这个,比如RenderTexture,她的孩子用不到,因为直接从_modelViewTransform传就可以了
//
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform); int i = ; if(!_children.empty())
{
sortAllChildren();
// draw children zOrder < 0
for( ; i < _children.size(); i++ )
{
auto node = _children.at(i); if ( node && node->_localZOrder < )
node->visit(renderer, _modelViewTransform, flags);
else
break;
}
// self draw
this->draw(renderer, _modelViewTransform, flags); for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _modelViewTransform, flags);
}
else
{
this->draw(renderer, _modelViewTransform, flags);
} /*
画完了就退出战,是兼容2.0的时候,把最顶部最新计算的modeviewtrnasform退出去
矩阵的转换都在GPU的shader中
*/
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); // FIX ME: Why need to set _orderOfArrival to 0??
// Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920
// reset for next frame
// _orderOfArrival = 0;
}
self->draw为绘制自己,但不是真的绘制,而是让自己关联一个绘制命令Command,LayerColor的draw方法重写如下:
//transform为本地坐标转世界坐标的矩阵
void LayerColor::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
_customCommand.init(_globalZOrder);
//回调函数
_customCommand.func = CC_CALLBACK_0(LayerColor::onDraw, this, transform, flags);
//把绘制命令的东西放到renderer里面
renderer->addCommand(&_customCommand); for(int i = ; i < ; ++i)
{
Vec4 pos;
//四个顶点的设计分辨率坐标
pos.x = _squareVertices[i].x; pos.y = _squareVertices[i].y; pos.z = _positionZ;
pos.w = ;//齐次坐标
//得出来的pos就是世界坐标下的pos了
_modelViewTransform.transformVector(&pos);
//pos.w 世界坐标的w始终为1
//这个世界坐标会在shader内乘以相机矩阵和裁剪矩阵,得出最后的视口需要的坐标
_noMVPVertices[i] = Vec3(pos.x,pos.y,pos.z)/pos.w;
}
}
代码把需要绘制的信息加入到了customCommand里面。
4 _renderer->render(); 负责执行command内的opengl绘制命令,代码如下:
void Renderer::render()
{ //Process render commands
//1. Sort render commands based on ID
//renderGroups包括若干rederqueue,默认使用第一个,
//renderquque包括若干个rendercommand
for (auto &renderqueue : _renderGroups)
{
renderqueue.sort();
} visitRenderQueue(_renderGroups[]); flush(); clean(); }
void Renderer::visitRenderQueue(const RenderQueue& queue)
{
ssize_t size = queue.size(); for (ssize_t index = ; index < size; ++index)
{
auto command = queue[index];
auto commandType = command->getType(); if(RenderCommand::Type::CUSTOM_COMMAND == commandType)//比如 LayerColor
{
flush();
auto cmd = static_cast<CustomCommand*>(command);
cmd->execute();//会调用LayerColor::onDraw,直接开始绘图
} }
}
5 cmd->execute会调用customCommand的回调函数,在LayerColor中为onDraw,代码如下:
//通过自定义方法进行回调 transform为 本地坐标转世界坐标的旋转矩阵
void LayerColor::onDraw(const Mat4& transform, uint32_t flags)
{
getGLProgram()->use();//layercolor 的tansform为相机矩阵*裁剪矩阵
getGLProgram()->setUniformsForBuiltins(transform);//设置顶点着色器中全局变量的值,如MVP矩阵
//启用 顶点坐标和颜色
GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_COLOR );
//
// Attributes
//
#ifdef EMSCRIPTEN
setGLBufferData(_noMVPVertices, * sizeof(Vec3), );
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, , GL_FLOAT, GL_FALSE, , ); setGLBufferData(_squareColors, * sizeof(Color4F), );
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, , GL_FLOAT, GL_FALSE, , );
#else //找到顶点的索引 _noMVPVertices为世界坐标中的四个顶点的值,存在了cpu中,没有存到显存
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, , GL_FLOAT, GL_FALSE, , _noMVPVertices); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, , GL_FLOAT, GL_FALSE, , _squareColors);
#endif // EMSCRIPTEN //混合,源和目标 颜色的混合
GL::blendFunc( _blendFunc.src, _blendFunc.dst ); //画这四个点
glDrawArrays(GL_TRIANGLE_STRIP, , ); //这是记录图元和顶点吗
// CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,4);
auto __renderer__ = Director::getInstance()->getRenderer();
__renderer__->addDrawnBatches();
__renderer__->addDrawnVertices(); }
LayerColor绘制过程比较简单,没有纹理设置,只有顶点和颜色,通过glDrawArrays绘制完成
cocos源码分析--LayerColor的绘制过程的更多相关文章
- MyBatis 源码分析 - 映射文件解析过程
1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...
- Spring源码分析之`BeanFactoryPostProcessor`调用过程
前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 本文内容: AbstractApplicationContext#refresh前部分的一点小内容 ...
- Spring Ioc源码分析系列--Bean实例化过程(一)
Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...
- Spring Ioc源码分析系列--Bean实例化过程(二)
Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...
- MyBatis 源码分析 - SQL 的执行过程
* 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析 ...
- 【Netty源码分析】发送数据过程
前面两篇博客[Netty源码分析]Netty服务端bind端口过程和[Netty源码分析]客户端connect服务端过程中我们分别介绍了服务端绑定端口和客户端连接到服务端的过程,接下来我们分析一下数据 ...
- 【Canal源码分析】parser工作过程
本文主要分析的部分是instance启动时,parser的一个启动和工作过程.主要关注的是AbstractEventParser的start()方法中的parseThread. 一.序列图 二.源码分 ...
- tomcat8 源码分析 | 组件及启动过程
tomcat 8 源码分析 ,本文主要讲解tomcat拥有哪些组件,容器,又是如何启动的 推荐访问我的个人网站,排版更好看呦: https://chenmingyu.top/tomcat-source ...
- Spark 源码分析 -- task实际执行过程
Spark源码分析 – SparkContext 中的例子, 只分析到sc.runJob 那么最终是怎么执行的? 通过DAGScheduler切分成Stage, 封装成taskset, 提交给Task ...
随机推荐
- VBA: 怎样批量数据从Excel派出到Visio
上周派到了个case, 是批量从Excel导出数据导Visio每个图形中. 花了些时间实现了这个功能. 原理如下: 打开Excel 新建/打开表单 指向所选择的表单 遍历所在列的所有数据 打开Visi ...
- php格式化数字:位数不足前面加0补足
<?php $var=sprintf("%02d", 2);//生成2位数,不足前面补0 echo $var;//结果为02 ?> 參考:https://blog.cs ...
- IDEA各个版本激活(亲测有效,永久有效)(转)
之前使用的license server 老是失效,今天又失效了,于是乎,在强大的网上找到了永久激活的方式,有个网站专门提供注册码,但是很这激活码有一定的期限,到期之后再获取一次即可,灰常方便. 激活方 ...
- cvsnt报错:Administrator: Switch to user failed due to configuration error. Contact your System Administrator
在安装CVSNT一开始用Administrator登录时总是报[login aborted]Switch to user failed due to configuration error. Cont ...
- win10 + VS2015 + 64位OSG3.4.0
一.下载 1.osg源码 2.整理好的第三方库 3.cmake3.7.1绿色版 4.osg3.4.0数据包 二.编译前的准备工作 在D:\下新建一个OSG文件夹,在其下再新建4个文件夹 D:\OSG\ ...
- phpmailer使用qq邮箱、163邮箱成功发送邮件实例代码
以前使用qq邮箱.163服务器发送邮件,帐号直接使用密码,现在不行了,得使用授权码,简单记录下 1.首先开通POP3/SMTP服务,qq邮箱——帐号——设置,找到POP3/SMTP点开启,输入短信会有 ...
- Block Design 小技巧之添加RTL代码到block_design
Block Design 小技巧之添加RTL代码到block_design 1.首先得打开Block Design,右击RTL文件,才会出现Add module to Block Design选项. ...
- angular的组件通信
参见这里 总结如下: @Input和@Ouptut 获取父实例,获取子实例 通过service共享数据 发送事件EventEmitter(个人喜欢angular-event-service) rx ...
- 跟着未名学Office - 高效工作Outlook
目录 第一篇邮件与联系人 1 第一节 使用与技巧 1 第二节 高效 11 第二篇 事务助手 21 第一节 日程管理 21 第二节 任务 ...
- flex布局demo
flex布局 http://static.vgee.cn/static/index.html