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 ...
随机推荐
- css动画和js动画的差异
代码复杂度,js 动画代码相对复杂一些 动画运行时,对动画的控制程度上,js 能够让动画,暂停,取消,终止,css动画不能添加事件 动画性能看,js 动画多了一个js 解析的过程,性能不如 css 动 ...
- BTrace学习总结
一.简介: 在生产环境中经常遇到格式各样的问题,如OOM或者莫名其妙的进程死掉.一般情况下是通过修改程序,添加打印日志:然后重新发布程序来完成.然而,这不仅麻烦,而且带来很多不可控的因素.有没有一种方 ...
- requestAnimationFrame 知识点
与setTimeout相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机.具体一点讲,如果屏幕刷新率是60Hz,那么回调函数就每16.7ms被执行一次,如果刷新 ...
- 关于TP5的一对一、一对多同时存在的关联查询
主表SQL(tp_member) CREATE TABLE `tp_member` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', `us ...
- 在pypi上发布python包详细教程
使用Python编程中Python的包安装非常方便,一般都是可以pip来安装搞定:pip install <package name>,我们自己写的python也可以发布在pypi上,很简 ...
- makedepend: command not found(转)
makedepend: command not found 解决方案: 修改Makefile MAKEDEPEND=$(CC) -M 参考: When I set CROSS_COMPILE, `MA ...
- jsp配置文件数据信息读取
一.jsp从配置文件*.properties读取信息 <%@ page language="java" import="java.util.*" cont ...
- ASP.NET AJAX入门系列
ASP.NET AJAX入门系列将会写关于ASP.NET AJAX一些控件的使用方法以及基础知识,其中部分文章为原创,也有一些文章是直接翻译自官方文档,本部分内容会不断更新. 目录 ASP.NET A ...
- VMware Ubuntu配置虚拟机和主机互相ping通
安装VMware后,主机会有两个虚拟网卡: vmnet1和vmnet8是两个虚拟网卡,主要作用是让虚拟机可以通过你的宿主机的网线上网.注意:如果有“!”,说明不能用. vmnet1是为host-on ...
- golang中defer的详解 转自https://blog.csdn.net/skh2015java/article/details/77081250
Go里的defer很有用,尤其在很多执行模块化操作时,初始化时给各个需要执行的模块传入参数,但是这些参数有些事在模块执行过程中才赋值的. 这时候有了defer就不会把代码写的很凌乱. Go的defer ...