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 ...
随机推荐
- 论 大并发 下的 乐观锁定 Redis锁定 和 新时代事务
在 <企业应用架构模式> 中 提到了 乐观锁定, 用 时间戳 来 判定 交易 是否有效, 避免 传统事务 的 表锁定 造成 的 瓶颈 . 在 现在的 大并发 的 大环境下, 传统事务 及其 ...
- mongodb之 3.4.0 mongodb sharing 副本集群搭建
系统系统 centos6.5三台服务器:10.100.25.42/43/44安装包: mongodb-linux-x86_64-rhel62-3.4.0.tgz 服务器规划:mongos mongos ...
- 昨天办了一张地铁卡,我想到一个app
如果成都开通 扫 二维码 做地铁.地铁是距离收费的,如果我们有一个平台,搜集所有用户的 入站 和出站二维码,然后重新分配,那么每个用户就只用 出 2块钱每次的最低消费了.哈哈............. ...
- Linux下Python与C++混合编程
最近在做一个CUDA的项目,记录下学习心得. 系统 Linux --generic #-Ubuntu x86_64 GNU/Linux C++调用Python Python模块代码: #!/usr/b ...
- piwik custom variables
piwik custom variables 是一个功能非常强大的自定义变量跟踪方案,多用于基于访客或是页面级别的变量跟踪.piwik默认最多可以添加5个自定义变量. 使用方式是在客户端脚本里添加如 ...
- 【java】进制转换
进制的表现形式: 十进制:0-9 ,满10 进1 八进制:0-7,满8进1,用0开头表示 十六进制:0-9,A-F,满16进1,用0x开头表示 十进制转换二进制: 原理:对十进制数进行除2运算,如37 ...
- python re 实例
#!/usr/bin/env python#_*_coding:utf-8_*_ import reimport timeimport jsonimport MySQLdbimport context ...
- https 不检验证书
System.Net.ServicePointManager.ServerCertificateValidationCallback += (s, cert, chain, sslPolicyErro ...
- 生成OSIDAAuto.OPCServer失败
来源:https://pisquare.osisoft.com/message/13441 A failuare of generating OSIDAAuto.OPCServer dorislipe ...
- java网络编程Socket通信详解
Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket.像大家熟悉的QQ.MSN都使用了Socket相关的技术. ...