在CCNode的类中,有一个得到 一个节点坐标系转换父亲坐标系的一个矩阵,节点内坐标乘以这个矩阵,就可以转换为在节点父节点中的坐标,方法名为:

Mat4& Node::getNodeToParentTransform()

现在简单分析一下转换原理:

/*
得到节点坐标系转换到父亲的坐标系的 矩阵
某个点(在本地也就是节点坐标) 乘以这个矩阵,就得到自己在父亲节点下的坐标,嵌套坐标
举例子:LayerA 添加 LayerB,B的原点坐标也就是左下角坐标为10,10,也就是这一点在自身坐标下为0,0,在LayerA下
就为10,10,这个矩阵的作用是Mat*(0,0)=(10,10),再比如在B下有一点是10,10,那么在没有旋转和缩放的前提下,在LayerA中的位置应该为20,20 ,Mat*(10,10)=(20,20)
所以这个矩阵叫做 转换 子节点坐标到父节点坐标的 转换矩阵
*/
const Mat4& Node::getNodeToParentTransform() const
{
/* 先 缩放,在旋转,最后平移,
详细可以看3d数学基础 8.3,解释了缩放矩阵,旋转矩阵,平移矩阵,然后相乘
但是这里注意的是(3d数学是行向量,也就是 X * S * R *T,顺序执行),
而cocos 是列向量 是 T * R * S * X,所以计算矩阵的时候要倒着乘, */ if (_transformDirty)
{
// Translate values
float x = _position.x;
float y = _position.y;
float z = _positionZ;
/*
旋转和缩放都是以锚点为中心,所以这里要计算出锚点
1 如果忽略锚点,说明x,y 指的是 左下角坐标,因为计算的时候要以锚点为准,所以需要加上anchorPointInPoints
2 如果没有忽略锚点,说明x,y指的就是锚点,直接往下计算就可以了
*/
if (_ignoreAnchorPointForPosition)//,加上锚点的坐标,计算缩放和旋转,以锚点为中心计算,
{
x += _anchorPointInPoints.x;//_anchorPointInPoints为物体左下角和锚点之间的距离
y += _anchorPointInPoints.y;
}
//计算出cos和sin,这里是4个弦组成的 旋转矩阵,radians为度数,绕着旋转的点是锚点
float cx = , sx = , cy = , sy = ;
if (_rotationZ_X || _rotationZ_Y)// 2D这两个值始终是相等的,暂时不考虑3D
{
//右手坐标系,所以如果旋转45,那么弧度是负,顺时针为负
float radiansX = -CC_DEGREES_TO_RADIANS(_rotationZ_X);
float radiansY = -CC_DEGREES_TO_RADIANS(_rotationZ_Y);
cx = cosf(radiansX);
sx = sinf(radiansX);
cy = cosf(radiansY);
sy = sinf(radiansY);
} bool needsSkewMatrix = ( _skewX || _skewY );//是否切面 /*
这里这么做的原因,因为 旋转和缩放是以锚点为中心,但是平移量是以原点距离父节点原点为准,也就是需要知道
原点的坐标,也就是左下角的坐标,因为涉及到缩放,所以锚点坐标要程序scale,得到新的左下角坐标距离锚点的位置
,比如锚点坐标为30,30(本地坐标),也就是左下角距离锚点30,30,scale=0.5的时候,变为 左下角距离锚点
15,15
*/
Vec2 anchorPoint;
anchorPoint.x = _anchorPointInPoints.x * _scaleX;
anchorPoint.y = _anchorPointInPoints.y * _scaleY; /*
如果锚点不是左下角,那么需要通过下面的计算得出旋转之后的左下角的坐标。
锚点为旋转点,那么左下角距离原点的坐标成为了负数,也就是-30,-30,的出来的结果是相对于
锚点的偏移量,所以下面
anchorPoint要加一个负号,通过-anchorPoint和旋转矩阵想乘,得到了新的左下角的相对于锚点的偏移量
而x,y为锚点的世界坐标(这里是指父节点中的坐标),(也就是到 ‘原点’的距离),加上相对于锚点为中心的旋转后的左下角坐标的偏移量,得到新的(想象一个如果锚点在左下角,就好理解了,一个意思)
左下角的世界坐标(在父节点中的坐标)
*/
//如果不是切变 并且锚点不在左下角,计算出左下角的父节点坐标
//如果是切变,往后会有处理
//其实这里是在mat矩阵形成前,先求出了左下角的x,y,其实如果不在这求出
//先求出 mat矩阵,这个矩阵是集缩放和旋转一体的,然后anchorPointInPoints(初始左下角坐标,相对于锚点)与这个矩阵想乘
//仍然可以求出变换之后的左下角坐标,后面的切变求偏移就是这么计算的,
//因为求切变的时候,最终的矩阵集 切变,缩放,旋转矩阵为一体了,就差一个平移了,然后anchorPointInPoints
//与这个矩阵想乘,然后再被锚点坐标相加,得出来父节点坐标下的左下角最终坐标,并把这个值作为平移值
if (! needsSkewMatrix && !_anchorPointInPoints.equals(Vec2::ZERO))
{
float xx= cy * -anchorPoint.x + -sx * -anchorPoint.y;
x +=xx;
float yy=sy * -anchorPoint.x + cx * -anchorPoint.y;
y += yy; }
//先缩放,在旋转,在平移的组合矩阵
// T * R * S *坐标,顺序别错了
// 这个矩阵* 本地坐标,得到就是相对于父节点的坐标(相当于本地坐标转世界坐标,父节点相当于世界了)
float mat[] = {
cy * _scaleX, sy * _scaleX, , ,
-sx * _scaleY, cx * _scaleY, , ,
, , _scaleZ, ,
x, y, z, }; _transform.set(mat);//应该是更新之后的矩阵 //*************关于3d的东西,忽略*************//
if(!_ignoreAnchorPointForPosition)
{
_transform.translate(anchorPoint.x, anchorPoint.y, );//
} //下面是绕 Y轴或X轴旋转,一般是3d的时候,2d的时候就是围绕点旋转,不考虑
// XXX
// FIX ME: Expensive operation.
// FIX ME: It should be done together with the rotationZ
if(_rotationY) {
Mat4 rotY;
Mat4::createRotationY(CC_DEGREES_TO_RADIANS(_rotationY), &rotY);
_transform = _transform * rotY;
}
if(_rotationX) {
Mat4 rotX;
Mat4::createRotationX(CC_DEGREES_TO_RADIANS(_rotationX), &rotX);
_transform = _transform * rotX;
} if(!_ignoreAnchorPointForPosition)
{
_transform.translate(-anchorPoint.x, -anchorPoint.y, );
}
//*************关于3d的东西,先不看 结束*************// //如果是切变,那么此时的x,y还是锚点坐标
if (needsSkewMatrix)
{
//这个矩阵的意思是 坐标X根据坐标Y被切变,坐标Y根据坐标X被切变,Z轴忽略,只考虑2d
//
Mat4 skewMatrix(, (float)tanf(CC_DEGREES_TO_RADIANS(_skewY)), , ,
(float)tanf(CC_DEGREES_TO_RADIANS(_skewX)), , , ,
, , , ,
, , , );
//这里的顺序是_transform * skewMatrix,而不是相反,本地坐标先被切变得到新的本地坐标,然后在
// 乘以缩放旋转平移矩阵
_transform = _transform * skewMatrix; // adjust anchor point
//和旋转的原理是一样的,12,13指的是 x,y原点距离世界坐标原点的值,因为之前的计算都是围绕锚点展开的
//所以此时的x,y是指锚点世界坐标,需要转换成左下角原点,算法上面说过,和旋转一样
//0 1 4 5代表的是 第一列的前两个和第二列的前两个值,缩放和旋转也是影响的这几个值(只考虑2d情况)
if (!_anchorPointInPoints.equals(Vec2::ZERO))
{
// XXX: Argh, Mat4 needs a "translate" method.
// XXX: Although this is faster than multiplying a vec4 * mat4
_transform.m[] += _transform.m[] * -_anchorPointInPoints.x + _transform.m[] * -_anchorPointInPoints.y;
_transform.m[] += _transform.m[] * -_anchorPointInPoints.x + _transform.m[] * -_anchorPointInPoints.y;
}
} if (_useAdditionalTransform)
{
_transform = _transform * _additionalTransform;
} _transformDirty = false;
} return _transform;
}

cocos子节点转父节点坐标 原理浅析(局部坐标转世界坐标同理)的更多相关文章

  1. 红黑树之 原理和算法详细介绍(阿里面试-treemap使用了红黑树) 红黑树的时间复杂度是O(lgn) 高度<=2log(n+1)1、X节点左旋-将X右边的子节点变成 父节点 2、X节点右旋-将X左边的子节点变成父节点

    红黑树插入删除 具体参考:红黑树原理以及插入.删除算法 附图例说明   (阿里的高德一直追着问) 或者插入的情况参考:红黑树原理以及插入.删除算法 附图例说明 红黑树与AVL树 红黑树 的时间复杂度 ...

  2. treeview插件使用:根据子节点选中父节点

    鄙人公司没有专门的前端,所以项目开发中都是前后端一起抡.最近用bootstrap用的比较频繁,发现bootstrap除了框架本身的样式组件外,还提供了多种插件供开发者选择.本篇博文讲的就是bootst ...

  3. ztree 获取子节点所有父节点的name的拼接

    ztree 获取子节点所有父节点的name的拼接 //获取子节点,所有父节点的name的拼接字符串function getFilePath(treeObj){if(treeObj==null)retu ...

  4. JS获取子节点、父节点和兄弟节点的方法实例总结

    转自:https://www.jb51.net/article/143286.htm 本文实例讲述了JS获取子节点.父节点和兄弟节点的方法.分享给大家供大家参考,具体如下: 一.js获取子节点的方式 ...

  5. (Elementui) el-tree 中英文过滤以及搜索到父子显示子节点,搜索到子节点显示父节点(filter-node-method)

    案例下载:https://gitee.com/tudoumlp/just1.git   (vue-ele-demo) 在项目中,会遇到树节点的搜索,中文和英文搜索,以及搜索到父节点匹配的时候同步显示该 ...

  6. CSS 子节点继承父节点(祖先节点)的样式

    CSS 有些属性可以让子节点从父节点或祖先节点继承,文本.字体.列表属性等样式都可以被子节点继承.子节点没有自身的样式,子节点将继承父节点或祖先节点的样式. <ul class="co ...

  7. SQL SERVER 2000 遍历父子关系数据的表(二叉树)获得所有子节点 所有父节点及节点层数函数

    ---SQL SERVER 2000 遍历父子关系數據表(二叉树)获得所有子节点 所有父节点及节点层数函数---Geovin Du 涂聚文--建立測試環境Create Table GeovinDu([ ...

  8. vue+element-ui之tree树形控件有关子节点和父节点之间的各种选中关系详解

    做后端管理系统,永远是最蛋疼.最复杂也最欠揍的事情,也永远是前端开发人员最苦逼.最无奈也最尿性的时刻.蛋疼的是需求变幻无穷,如同二师兄的三十六般变化:复杂的是开发难度寸步难行,如同蜀道难,难于上青天: ...

  9. element-ui tree控件获取当前节点和父节点

    今天使用element-ui 遇到两个问题,第一个问题是获取tree控件的当前节点和父节点, 一开始使用tree控件的getCurrentNode()函数,结果发现返回的是当前节点的data属性,和u ...

随机推荐

  1. python 调试之assert and logging

    断言 assert assert后面跟的表达式应该是True,否则,根据程序运行的逻辑,后面的代码肯定会出错. 如果断言失败,会抛出AssertionError def foo(s): n = int ...

  2. SELECT 语句语法

    SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_R ...

  3. How to Export to Excel

    https://simpleisbetterthancomplex.com/tutorial/2016/07/29/how-to-export-to-excel.html Export data to ...

  4. deque/defaultdict/orderedict/collections.namedtuple()/collections.ChainMap() 笔记

    关于deque的使用 collections.deque([list[, max_length]]) # 不限定长度,可随意添加没有上限 >>> from collections i ...

  5. CentOS7创建本地yum源

    [root@master ~]# mkdir -p /var/www/html 使用安装系统的ISO镜像文件CentOS-7-x86_64-Everything-1611.iso 把CentOS-7- ...

  6. GTX_SDI搭建流程

    GTX_SDI搭建流程 1.GTX wrapper 因为顶层的GTX wrapper在实际的SDI工程中用不到,我们只是需要GTX wrapper模块中的部分文件.因此,在SDI工程中,我们并不需要生 ...

  7. 使用Tesseract-OCR 进行文字识别

    关于中文的识别,效果比较好而且开源的应该就是Tesseract-OCR了,所以自己亲身试用一下,分享到博客让有同样兴趣的人少走弯路. 文中所用到的身份证图片资源是百度找的,如有侵权可联系我删除. 一. ...

  8. 解决 VUE 微信登录验证 【感谢原文:https://segmentfault.com/a/1190000009493199】

    [感谢原文:https://segmentfault.com/a/1190000009493199] SPA单页应用中微信授权登录的一点思路 单页应用应该如何解决微信授权登录的尴尬跳转?后退无法返回? ...

  9. django1.10.3下admin后台管理老是显示object

    在设置了一个新models phone book后,admin管理显示数据名称都是object 尝试为model重写__unicode__方法后无效,经查询,在py3环境中,需要重写__str__方法 ...

  10. Xshell5 评估过期,需要采购,不能使用

    Xshell5 评估过期,需要采购,不能使用 标签: Xshell linux 2017年10月10日 13:13:1029507人阅读 评论(9) 收藏 举报 版权声明:本文为博主原创文章,未经博主 ...