zoukankan      html  css  js  c++  java
  • cocos子节点转父节点坐标 原理浅析(局部坐标转世界坐标同理)

    在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 = 1, sx = 0, cy = 1, sy = 0;
            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,   0,          0,
                            -sx * _scaleY,  cx * _scaleY,   0,          0,
                            0,              0,              _scaleZ,    0,
                            x,              y,              z,          1 };
            
            _transform.set(mat);//应该是更新之后的矩阵
    
            
            
            //*************关于3d的东西,忽略*************//
            if(!_ignoreAnchorPointForPosition)
            {
                _transform.translate(anchorPoint.x, anchorPoint.y, 0);//
            }
            
            //下面是绕 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, 0);
            }
            //*************关于3d的东西,先不看 结束*************//
            
           //如果是切变,那么此时的x,y还是锚点坐标
            if (needsSkewMatrix)
            {
                //这个矩阵的意思是 坐标X根据坐标Y被切变,坐标Y根据坐标X被切变,Z轴忽略,只考虑2d
                //
                Mat4 skewMatrix(1, (float)tanf(CC_DEGREES_TO_RADIANS(_skewY)), 0, 0,
                                  (float)tanf(CC_DEGREES_TO_RADIANS(_skewX)), 1, 0, 0,
                                  0,  0,  1, 0,
                                  0,  0,  0, 1);
                 //这里的顺序是_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[12] += _transform.m[0] * -_anchorPointInPoints.x + _transform.m[4] * -_anchorPointInPoints.y; _transform.m[13] += _transform.m[1] * -_anchorPointInPoints.x + _transform.m[5] * -_anchorPointInPoints.y; } } if (_useAdditionalTransform) { _transform = _transform * _additionalTransform; } _transformDirty = false; } return _transform; }
  • 相关阅读:
    EntityFramework优缺点
    领导者与管理者的区别
    七个对我最好的职业建议(精简版)
    The best career advice I’ve received
    Difference between Stored Procedure and Function in SQL Server
    2015年上半年一次通过 信息系统项目管理师
    Difference between WCF and Web API and WCF REST and Web Service
    What’s the difference between data mining and data warehousing?
    What is the difference between a Clustered and Non Clustered Index?
    用new创建函数的过程发生了什么
  • 原文地址:https://www.cnblogs.com/xiaonanxia/p/9104248.html
Copyright © 2011-2022 走看看