ocos2d-x Win32下的节点缩放原理研究心得
来源:互联网 发布:linux 脚本 while 死 编辑:程序博客网 时间:2024/05/18 21:07
[2.1.0]Cocos2d-x Win32下的节点缩放原理研究心得
19
主题2
听众489
积分版主
本帖最后由 火星熊猫 于 2013-3-7 08:07 编辑
说明:按照FireDragon的建议,我把缩放原理这部分发在新帖里(顺便再骗一个精华),但是本帖内容与上一贴讲到的部分内容有联系,所以请自行参考http://bbs.firedragonpzy.com.cn/ ... d=54&extra=page%3D1
二、节点缩放原理
引擎对节点的平移(T)、缩放(S)、旋转(R)等操作,最终都是通过修改OpenGL的模型视图矩阵(MV)和投影矩阵(P)来实现的。
在cocos2dx\kazmath\src\GL\matrix.c中维护了三个栈结构用来保存绘制流程中每个节点的矩阵 三个栈会在第一次访问时被初始化,初始化后栈中都有一个4*4的对角线是1的单位矩阵。 用kmGLMatrixMode(kmGLEnum mode)函数来切换当前操作的栈 用kmGLPushMatrix()函数将当前栈的栈顶矩阵复制后压栈,kmGLPopMatrix()用于出栈,kmGLLoadIdentity()用于将栈顶矩阵初始化成单位矩阵。 kmGLMultMatrix()做矩阵乘法(主要是节点经过变形计算后得到的结果与栈顶矩阵相乘时,以及最终绘制时MV与P相乘时使用)
kmGLGetMatrix ()获得指定栈的栈顶矩阵 当每个节点被访问(visit())时,先压栈(默认操作的是MV),再变形 CCNode::transform()中,CCNode::nodeToParentTransform()负责实际计算,然后将计算结果乘入MV的栈顶矩阵 CCNode::nodeToParentTransform()并不是每一帧都会计算,只有当需要的时候,即m_bTransformDirty为真时,才会重新计算。除了节点的创建的时候,m_bTransformDirty 为真。运行过程中的扭曲(setSkew)、旋转(setRotation)、缩放(setScale)、平移(setPosition)、设置锚点(setAnchorPoint)、设置内容尺寸(setContentSize)等操作会导致节点的 m_bTransformDirty 设置为真。经过一次变形计算后, m_bTransformDirty 再次赋值成false。
我在这里只贴出了缩放生效的代码,其他操作的计算,请参考 CCNode::nodeToParentTransform() 当节点在绘制自身(draw())的时候,以CCLayerColor为例,先将矩阵设置给OpenGL,然后设置颜色数据和顶点数据,指定像素渲染模式,最后绘制顶点
矩阵是在 CC_NODE_DRAW_SETUP 这个宏里设置到OpenGL的 CCGLProgram::setUniformsForBuiltins() 中先取得MV和P,然后将MV和P相乘得到名字很酷的MVP,即模型视图投影矩阵,然后调用setUniformLocationWithMatrix4fv 将各个矩阵写入OpenGL中 至于矩阵的说明,我也不懂,所以请参考OpenGL的相关资料。
超出字数限制了,后面的部分放在二楼
说明:按照FireDragon的建议,我把缩放原理这部分发在新帖里(顺便再骗一个精华),但是本帖内容与上一贴讲到的部分内容有联系,所以请自行参考http://bbs.firedragonpzy.com.cn/ ... d=54&extra=page%3D1
二、节点缩放原理
引擎对节点的平移(T)、缩放(S)、旋转(R)等操作,最终都是通过修改OpenGL的模型视图矩阵(MV)和投影矩阵(P)来实现的。
在cocos2dx\kazmath\src\GL\matrix.c中维护了三个栈结构用来保存绘制流程中每个节点的矩阵 三个栈会在第一次访问时被初始化,初始化后栈中都有一个4*4的对角线是1的单位矩阵。 用kmGLMatrixMode(kmGLEnum mode)函数来切换当前操作的栈 用kmGLPushMatrix()函数将当前栈的栈顶矩阵复制后压栈,kmGLPopMatrix()用于出栈,kmGLLoadIdentity()用于将栈顶矩阵初始化成单位矩阵。 kmGLMultMatrix()做矩阵乘法(主要是节点经过变形计算后得到的结果与栈顶矩阵相乘时,以及最终绘制时MV与P相乘时使用)
kmGLGetMatrix ()获得指定栈的栈顶矩阵 当每个节点被访问(visit())时,先压栈(默认操作的是MV),再变形 CCNode::transform()中,CCNode::nodeToParentTransform()负责实际计算,然后将计算结果乘入MV的栈顶矩阵 CCNode::nodeToParentTransform()并不是每一帧都会计算,只有当需要的时候,即m_bTransformDirty为真时,才会重新计算。除了节点的创建的时候,m_bTransformDirty 为真。运行过程中的扭曲(setSkew)、旋转(setRotation)、缩放(setScale)、平移(setPosition)、设置锚点(setAnchorPoint)、设置内容尺寸(setContentSize)等操作会导致节点的 m_bTransformDirty 设置为真。经过一次变形计算后, m_bTransformDirty 再次赋值成false。
我在这里只贴出了缩放生效的代码,其他操作的计算,请参考 CCNode::nodeToParentTransform() 当节点在绘制自身(draw())的时候,以CCLayerColor为例,先将矩阵设置给OpenGL,然后设置颜色数据和顶点数据,指定像素渲染模式,最后绘制顶点
矩阵是在 CC_NODE_DRAW_SETUP 这个宏里设置到OpenGL的 CCGLProgram::setUniformsForBuiltins() 中先取得MV和P,然后将MV和P相乘得到名字很酷的MVP,即模型视图投影矩阵,然后调用setUniformLocationWithMatrix4fv 将各个矩阵写入OpenGL中 至于矩阵的说明,我也不懂,所以请参考OpenGL的相关资料。
超出字数限制了,后面的部分放在二楼
本主题由 firedragonpzy 于 2013-3-7 09:50 设置高亮
分享到:QQ空间腾讯微博腾讯朋友
转播0淘帖0分享收藏0支持0反对0回复
使用道具 举报
19
主题2
听众489
积分版主
本帖最后由 火星熊猫 于 2013-3-7 08:31 编辑
最后就是调用OpenGL的接口来绘制 注意 m_pSquareVertices 中储存的顶点数据是与缩放无关的,OpenGL在绘制顶点时,会将顶点与矩阵相乘转换后再绘制。
这样当 CCLayerColor::draw() 结束时,屏幕上就应该出现一个填充了颜色的矩形。
以我实验时的程序为例,说明缩放前后矩阵的变化。实验程序以HelloWorld为基础修改而来,共有4个节点,依次是CCScene(即HelloWorldScene)、CCLayer(HelloWorld::scene()创建的)、CCLayerColor 1和 CCLayerColor 2, 增加一个action使 CCLayerColor 1在运行1秒后被缩小 在缩放操作的前后打印log 同时为便于跟踪,增加了如下的log
给CCScene增加一个draw函数 给CCLayer增加一个draw函数 CCLayerColor::draw()增加打印顶点数据以及节点名称 CCNode::nodeToParentTransform(void) 中增加打印变形计算的结果 CCGLProgram::setUniformsForBuiltins() 中增加打印矩阵数据 然后运行,运行结果放到3楼
最后就是调用OpenGL的接口来绘制 注意 m_pSquareVertices 中储存的顶点数据是与缩放无关的,OpenGL在绘制顶点时,会将顶点与矩阵相乘转换后再绘制。
这样当 CCLayerColor::draw() 结束时,屏幕上就应该出现一个填充了颜色的矩形。
以我实验时的程序为例,说明缩放前后矩阵的变化。实验程序以HelloWorld为基础修改而来,共有4个节点,依次是CCScene(即HelloWorldScene)、CCLayer(HelloWorld::scene()创建的)、CCLayerColor 1和 CCLayerColor 2, 增加一个action使 CCLayerColor 1在运行1秒后被缩小 在缩放操作的前后打印log 同时为便于跟踪,增加了如下的log
给CCScene增加一个draw函数 给CCLayer增加一个draw函数 CCLayerColor::draw()增加打印顶点数据以及节点名称 CCNode::nodeToParentTransform(void) 中增加打印变形计算的结果 CCGLProgram::setUniformsForBuiltins() 中增加打印矩阵数据 然后运行,运行结果放到3楼
回复
使用道具 举报
19
主题2
听众489
积分版主
程序运行后效果如上图,红色是CCLayerColor 1,绿色是CCLayerColor2
1秒后,CCLayerColor 1被缩小,同时CCLayerColor 2也被同步的缩小
根据打印的log(因为log是每帧都打印,所以我只截取开始和缩放前后的log)
这时第一帧和第二帧的log,可以看到4个节点只在第一帧运行了nodeToParentTransform,CCScene和CCLayer的draw并不作实际绘制,所以只打印出两个CCLayerColor的MV矩阵这时是1,以及顶点数据是原始尺寸
回复
使用道具 举报
19
主题2
听众489
积分版主
本帖最后由 火星熊猫 于 2013-3-7 09:00 编辑
这是缩放前一帧和缩放后一帧的log 首先 setScale的过程中不涉及任何的绘制动作,事实上setScale 除了记录缩放比和标记需要重新变形计算外也不做其他的操作 其次 setScale后一帧,除了CCLayerColor 1重新变形计算外,其他三个节点没有重新计算,这个符合之前的判断
然后 CCLayerColor 1 重新计算后 MV矩阵变为了 0.5(缩小二分之一),虽然CCLayerColor 2没有重新计算,但是节点MV矩阵的初始值是从父节点获得的,所以CCLayerColor 2的MV矩阵也变成了 0.5
最后 比较缩放前后的顶点数据,两个CCLayerColor的顶点数据都不变,这也就证明缩放是完全依靠对矩阵的操作来实现的。
这是缩放前一帧和缩放后一帧的log 首先 setScale的过程中不涉及任何的绘制动作,事实上setScale 除了记录缩放比和标记需要重新变形计算外也不做其他的操作 其次 setScale后一帧,除了CCLayerColor 1重新变形计算外,其他三个节点没有重新计算,这个符合之前的判断
然后 CCLayerColor 1 重新计算后 MV矩阵变为了 0.5(缩小二分之一),虽然CCLayerColor 2没有重新计算,但是节点MV矩阵的初始值是从父节点获得的,所以CCLayerColor 2的MV矩阵也变成了 0.5
最后 比较缩放前后的顶点数据,两个CCLayerColor的顶点数据都不变,这也就证明缩放是完全依靠对矩阵的操作来实现的。
回复
使用道具 举报
19
主题2
听众489
积分版主
本帖最后由 火星熊猫 于 2013-3-7 10:23 编辑
总结:之所以想要研究2dx的缩放原理,源于过年时和FD的讨论以及对缩放传递的好奇。当时理想的认为当父节点被缩放时,引擎应该是抛出一个缩放事件通知了子节点。但是从目前分析来看,完全不是想象的情况。根据实现机制,当父节点缩放时,子节点是完全不知道的,从原理上讲子节点也不需要知道。但是实际上子节点是否有必要知道父节点以上的节点有缩放呢?从目前的已知的CCScrollView的两个bug来看,都是当父节点缩放后,CCScrollView不知情造成的。如果某个组件中单独设置了某个独立于矩阵的尺寸(比如CCScrollView设置了裁剪区域,且这个区域不受矩阵影响),那么子节点还是需要知道父节点缩放事件的。当然也许可以让这些操作同样受矩阵影响,但是本人水平还有限,需要大神们去解决。
总结:之所以想要研究2dx的缩放原理,源于过年时和FD的讨论以及对缩放传递的好奇。当时理想的认为当父节点被缩放时,引擎应该是抛出一个缩放事件通知了子节点。但是从目前分析来看,完全不是想象的情况。根据实现机制,当父节点缩放时,子节点是完全不知道的,从原理上讲子节点也不需要知道。但是实际上子节点是否有必要知道父节点以上的节点有缩放呢?从目前的已知的CCScrollView的两个bug来看,都是当父节点缩放后,CCScrollView不知情造成的。如果某个组件中单独设置了某个独立于矩阵的尺寸(比如CCScrollView设置了裁剪区域,且这个区域不受矩阵影响),那么子节点还是需要知道父节点缩放事件的。当然也许可以让这些操作同样受矩阵影响,但是本人水平还有限,需要大神们去解决。
回复
使用道具 举报
51
主题2
听众812
积分管理员
回复
使用道具 举报
1
主题1
听众23
积分新手上路
膜拜了。好文。赞一个
回复
使用道具 举报
0
主题0
听众16
积分新手上路
ding 希望论坛火起来
回复
使用道具 举报
51
主题2
听众812
积分管理员
有空多来转转……
回复
使用道具 举报
0
主题0
听众16
积分新手上路
我基本每天都来,2DX新手,论坛为什么不搞大点 是个人时间还是经济问题啊,资源少了 不吸引人呀,我抽点时间把我收集的资源帖上 加点人气
0 0
- ocos2d-x Win32下的节点缩放原理研究心得
- [2.1.0]Cocos2d-x Win32下的节点缩放原理研究心得
- ocos2d-x--SEL_CallFuncN,SEL_CallFuncO等的区别
- 研究spring原理的心得
- ocos2d-x 在 Windows下开启控制台窗口打印 Log
- ocos2d-x 坐标系
- Win32 下的Cocos2d-x
- ocos2d-x 自建动画管理器AnimationManager的方法和使用
- 关于win32 下DEBUG模式的研究
- WIN32无边框窗体的缩放、移动与WM_NCHITTEST消息&&UpdateLayeredWindow重要心得
- WIN32无边框窗体的缩放、移动与WM_NCHITTEST消息&&UpdateLayeredWindow重要心得
- 关于win32下双缓冲的一点心得
- ocos2d-x中CCCallFunc CCCallFuncN CCCallFuncND的区别和使用示例
- ocos2d-x中背景音乐的播放与停止、暂停与继续
- ocos2d-x 3.0开发(三)点击交互的四种处理
- cocos2d-x win32 转android,移植心得。
- WMI win32的研究
- ocos2d-x中使用sqlite数据库
- VMware workstation 10英文版设置
- iOS 常用第三方库
- JAVA之编码---->CSV在文本下是正常的,用EXCEL打开是乱码的问题
- cocos2dx2.2移植到Android
- C#子窗体运行时无法正常最大化的解决办法
- ocos2d-x Win32下的节点缩放原理研究心得
- iOS上生成圆角图片
- OpenGL GLUT扩展库安装与配置(Windows Visual Studio2008)
- httpd.conf配置详解
- imagick-3.1.0RC2 安装错误
- Java输入与输出
- Working with Strings
- 技术网址收集
- cocos2dx在windows下开发,编译到android上(1)