cocos2dx 2.1.4 CCNode解析(重点:局部坐标转换机制分析)

这一篇博客我主要想分析CCNode的坐标转换相关的底层实现,其他功能只做大概的介绍,先给出头文件的代码分析


  1. #include "ccMacros.h"  
  2. #include "cocoa/CCAffineTransform.h"  
  3. #include "cocoa/CCArray.h"  
  4. #include "CCGL.h"  
  5. #include "shaders/ccGLStateCache.h"  
  6. #include "shaders/CCGLProgram.h"  
  7. #include "kazmath/kazmath.h"  
  8. #include "script_support/CCScriptSupport.h"  
  9. #include "CCProtocols.h"  
  10.   
  11. NS_CC_BEGIN  
  12.   
  13. class CCCamera;  
  14. class CCGridBase;  
  15. class CCPoint;  
  16. class CCTouch;  
  17. class CCAction;  
  18. class CCRGBAProtocol;  
  19. class CCLabelProtocol;  
  20. class CCScheduler;  
  21. class CCActionManager;  
  22. class CCDictionary;  
  23.   
  24. //2dx 2.1.4新出来的东西  
  25. class CCComponent;  
  26. class CCComponentContainer;  
  27.   
  28. enum {  
  29.     //CCNode tag的默认值  
  30.     kCCNodeTagInvalid = -1,  
  31. };  
  32.   
  33. /** 
  34. CCNode能够产生的5个事件,如果有脚本回调将通知给对应的脚本 
  35. */  
  36. enum {  
  37.     kCCNodeOnEnter,                     //节点准备进入runningScene子节点  
  38.     kCCNodeOnExit,                      //节点已经退出runningScene子节点  
  39.     kCCNodeOnEnterTransitionDidFinish,  //节点已经进入runningScene子节点  
  40.     kCCNodeOnExitTransitionDidStart,    //节点准备退出runningScene子节点  
  41.     kCCNodeOnCleanup                    //Stops all running actions and schedulers  
  42. };  
  43.   
  44. /** 
  45. 为了方便阅读我按照功能模块来划分将相关代码换了次序 
  46. */  
  47. class CC_DLL CCNode : public CCObject  
  48. {  
  49. protected:  
  50.     /** 
  51.     父子节点关系 
  52.     */  
  53.     bool        m_bVisible;             ///< is this node visible  
  54.     int         m_nZOrder;              ///< z-order value that affects the draw order  
  55.     bool        m_bReorderChildDirty;   ///< children order dirty flag  
  56.     CCArray*    m_pChildren;            ///< array of children nodes  
  57.     CCNode*     m_pParent;              ///< weak reference to parent node  
  58.     int m_nTag;                         ///< a tag. Can be any number you assigned just to identify this node  
  59.     unsigned int m_uOrderOfArrival;     ///< used to preserve sequence while sorting children with the same zOrder  
  60.     bool m_bRunning;                    ///< is running  
  61.       
  62.   
  63.     /** 
  64.     节点位置信息(与<strong>坐标</strong><strong>转换</strong>相关的) 
  65.     */  
  66.     float   m_fRotationX;  
  67.     float   m_fRotationY;  
  68.     float   m_fScaleX;  
  69.     float   m_fScaleY;  
  70.     CCPoint m_obPosition;  
  71.     float   m_fSkewX;  
  72.     float   m_fSkewY;  
  73.     CCPoint m_obAnchorPointInPoints;//只读  
  74.     CCPoint m_obAnchorPoint;  
  75.     bool    m_bIgnoreAnchorPointForPosition;  
  76.     CCSize  m_obContentSize;  
  77.     //<strong>转换</strong>矩阵  
  78.     CCAffineTransform m_sAdditionalTransform;   //为什么需要新增这个<strong>转换</strong>矩阵看对应的函数注释  
  79.     CCAffineTransform m_sTransform;             //node to parent transform  
  80.     CCAffineTransform m_sInverse;               //inverse matrix of node to parent transform  
  81.   
  82.     bool m_bTransformDirty;             ///< transform dirty flag  
  83.     bool m_bInverseDirty;               ///< transform dirty flag  
  84.     bool m_bAdditionalTransformDirty;   ///< The flag to check whether the additional transform is dirty  
  85.       
  86.     CCCamera *m_pCamera;                ///< a camera  
  87.       
  88.     CCGridBase *m_pGrid;                ///< a grid  
  89.       
  90.     /** 
  91.     渲染相关 
  92.     */  
  93.     CCGLProgram *m_pShaderProgram;      ///< OpenGL shader  
  94.     ccGLServerState m_eGLServerState;   ///< OpenGL servier side state(这个state貌似这个版本没什么用了)  
  95.       
  96.     /** 
  97.     计时器与action的支持 
  98.     */  
  99.     CCScheduler*    m_pScheduler;      ///< scheduler used to schedule timers and updates  
  100.     CCActionManager*m_pActionManager;  ///< a pointer to ActionManager singleton, which is used to handle all the actions  
  101.       
  102.     /** 
  103.     相关事件脚本回调 
  104.     */  
  105.     int m_nScriptHandler;      ///< script handler for onEnter() & onExit(), used in Javascript binding and Lua binding.  
  106.     int m_nUpdateScriptHandler;///< script handler for update() callback per frame, which is invoked from lua & javascript.  
  107.     ccScriptType m_eScriptType;///< type of script binding, lua or javascript  
  108.       
  109.     /** 
  110.     自定义数据存储 
  111.     */  
  112.     void *m_pUserData;                              ///< A user assingned void pointer, Can be point to any cpp object  
  113.     CCObject *m_pUserObject;                        ///< A user assigned CCObject  
  114.     CCComponentContainer *m_pComponentContainer;    ///< Dictionary of components  
  115.   
  116.     /** 
  117.     OpenGL real Z vertex 
  118.     */  
  119.     float m_fVertexZ;  
  120. public:  
  121.     CCNode(void);  
  122.     virtual ~CCNode(void);  
  123.     virtual bool init();  
  124.     static CCNode * create(void);  
  125.     const char* description(void);  
  126.   
  127.     /** 
  128.     父子节点之间关系 
  129.     */  
  130.     //改变zorder如果有父节点,则根据新的zorder排序  
  131.     virtual void setZOrder(int zOrder);  
  132.     //只改变zorder  
  133.     virtual void _setZOrder(int z);  
  134.     virtual int getZOrder();  
  135.   
  136.     //CCNode的id标识符  
  137.     virtual int getTag() const;  
  138.     virtual void setTag(int nTag);  
  139.   
  140.     //可见性,如果不可见该节点以及子节点将不会被visit  
  141.     virtual void setVisible(bool visible);  
  142.     virtual bool isVisible();  
  143.   
  144.     //以下函数无需纠结  
  145.     virtual void addChild(CCNode * child);  
  146.     virtual void addChild(CCNode * child, int zOrder);  
  147.     virtual void addChild(CCNode* child, int zOrder, int tag);  
  148.     CCNode *            getChildByTag(int tag);  
  149.     virtual CCArray*    getChildren();  
  150.     unsigned int        getChildrenCount(voidconst;  
  151.     virtual void        setParent(CCNode* parent);//parent a weak reference  
  152.     virtual CCNode*     getParent();  
  153.       
  154.     virtual void removeFromParent();  
  155.     virtual void removeFromParentAndCleanup(bool cleanup);  
  156.     virtual void removeChild(CCNode* child);  
  157.     virtual void removeChild(CCNode* child, bool cleanup);  
  158.     virtual void removeChildByTag(int tag);  
  159.     virtual void removeChildByTag(int tag, bool cleanup);  
  160.     virtual void removeAllChildren();  
  161.     virtual void removeAllChildrenWithCleanup(bool cleanup);  
  162.       
  163.     virtual void reorderChild(CCNode * child, int zOrder);  
  164.     virtual void sortAllChildren();  
  165.   
  166.     virtual void            setOrderOfArrival(unsigned int uOrderOfArrival);  
  167.     virtual unsigned int    getOrderOfArrival();  
  168.   
  169.     virtual bool isRunning();//节点是否在runningScene的子节点  
  170.   
  171.     //5种事件(对应最上面的枚举)  
  172.     virtual void onEnter();  
  173.     virtual void onEnterTransitionDidFinish();  
  174.     virtual void onExitTransitionDidStart();  
  175.     virtual void onExit();  
  176.     virtual void cleanup(void);//此函数将停条该节点以及子节点的所有计时器以及actions如果有脚本回调则通知 给脚本  
  177.       
  178.     /** 
  179.     <strong>坐标</strong>系<strong>转换</strong><strong>机制</strong>相关函数 
  180.     <strong>分析</strong>的<strong>重点</strong>: 
  181.     */  
  182.     virtual void    setScaleX(float fScaleX);  
  183.     virtual float   getScaleX();  
  184.     virtual void    setScaleY(float fScaleY);  
  185.     virtual float   getScaleY();  
  186.     virtual void    setScale(float scale);  
  187.     virtual float   getScale();  
  188.       
  189.     virtual void            setPosition(const CCPoint &position);  
  190.     virtual const CCPoint&  getPosition();  
  191.     virtual void            setPosition(float x, float y);  
  192.     virtual void            getPosition(float* x, float* y);  
  193.     virtual void            setPositionX(float x);  
  194.     virtual float           getPositionX(void);  
  195.     virtual void            setPositionY(float y);  
  196.     virtual float           getPositionY(void);  
  197.       
  198.     virtual void    setSkewX(float fSkewX);  
  199.     virtual float   getSkewX();  
  200.     virtual void    setSkewY(float fSkewY);  
  201.     virtual float   getSkewY();  
  202.       
  203.     virtual void            setAnchorPoint(const CCPoint& anchorPoint);  
  204.     virtual const CCPoint&  getAnchorPoint();  
  205.     virtual const CCPoint&  getAnchorPointInPoints();  
  206.     virtual void            ignoreAnchorPointForPosition(bool ignore);  
  207.     virtual bool            isIgnoreAnchorPointForPosition();  
  208.       
  209.       
  210.     virtual void            setContentSize(const CCSize& contentSize);  
  211.     virtual const CCSize&   getContentSize() const;  
  212.   
  213.   
  214.     virtual void    setRotation(float fRotation);  
  215.     virtual float   getRotation();  
  216.     virtual void    setRotationX(float fRotaionX);  
  217.     virtual float   getRotationX();  
  218.     virtual void    setRotationY(float fRotationY);  
  219.     virtual float   getRotationY();  
  220.   
  221.     //矩阵<strong>转换</strong>  
  222.     void transform(void);  
  223.     void transformAncestors(void);  
  224.     virtual void updateTransform(void);  
  225.     virtual CCAffineTransform nodeToParentTransform(void);//将node<strong>坐标</strong>系<strong>转换</strong>到parent<strong>坐标</strong>系  
  226.     virtual CCAffineTransform parentToNodeTransform(void);  
  227.     virtual CCAffineTransform nodeToWorldTransform(void);  
  228.     virtual CCAffineTransform worldToNodeTransform(void);  
  229.       
  230.     CCPoint convertToNodeSpace(const CCPoint& worldPoint);  
  231.     CCPoint convertToWorldSpace(const CCPoint& nodePoint);  
  232.     CCPoint convertTouchToNodeSpace(CCTouch * touch);  
  233.      //treating the returned/received node point as anchor relative.  
  234.     CCPoint convertToNodeSpaceAR(const CCPoint& worldPoint);  
  235.     CCPoint convertToWorldSpaceAR(const CCPoint& nodePoint);  
  236.     CCPoint convertTouchToNodeSpaceAR(CCTouch * touch);  
  237.       
  238.     /** 
  239.      *  Sets the additional transform. 
  240.      * 
  241.      *  @note The additional transform will be concatenated at the end of nodeToParentTransform. 
  242.      *        It could be used to simulate `parent-child` relationship between two nodes (e.g. one is in BatchNode, another isn't). 
  243.      *  @code 
  244.         // create a batchNode 
  245.         CCSpriteBatchNode* batch= CCSpriteBatchNode::create("Icon-114.png"); 
  246.         this->addChild(batch); 
  247.       
  248.         // create two sprites, spriteA will be added to batchNode, they are using different textures. 
  249.         CCSprite* spriteA = CCSprite::createWithTexture(batch->getTexture()); 
  250.         CCSprite* spriteB = CCSprite::create("Icon-72.png"); 
  251.  
  252.         batch->addChild(spriteA);  
  253.       
  254.         // We can't make spriteB as spriteA's child since they use different textures. So just add it to layer. 
  255.         // But we want to simulate `parent-child` relationship for these two node. 
  256.         this->addChild(spriteB);  
  257.  
  258.         //position 
  259.         spriteA->setPosition(ccp(200, 200)); 
  260.       
  261.         // Gets the spriteA's transform. 
  262.         CCAffineTransform t = spriteA->nodeToParentTransform(); 
  263.       
  264.         // Sets the additional transform to spriteB, spriteB's postion will based on its pseudo parent i.e. spriteA. 
  265.         spriteB->setAdditionalTransform(t); 
  266.  
  267.         //scale 
  268.         spriteA->setScale(2); 
  269.       
  270.         // Gets the spriteA's transform. 
  271.         t = spriteA->nodeToParentTransform(); 
  272.       
  273.         // Sets the additional transform to spriteB, spriteB's scale will based on its pseudo parent i.e. spriteA. 
  274.         spriteB->setAdditionalTransform(t); 
  275.  
  276.         //rotation 
  277.         spriteA->setRotation(20); 
  278.       
  279.         // Gets the spriteA's transform. 
  280.         t = spriteA->nodeToParentTransform(); 
  281.       
  282.         // Sets the additional transform to spriteB, spriteB's rotation will based on its pseudo parent i.e. spriteA. 
  283.         spriteB->setAdditionalTransform(t); 
  284.      *  @endcode 
  285.      */  
  286.     void setAdditionalTransform(const CCAffineTransform& additionalTransform);  
  287.   
  288.     //网格(暂时没研究过以后有时间研究)  
  289.     virtual CCGridBase* getGrid();  
  290.     virtual void setGrid(CCGridBase *pGrid);  
  291.     virtual CCCamera* getCamera();  
  292.   
  293.     CCRect boundingBox(void);  
  294.       
  295.     virtual void visit(void);  
  296.     virtual void draw(void);  
  297.       
  298.     /** 
  299.     绘制相关 
  300.     */  
  301.     virtual CCGLProgram* getShaderProgram();  
  302.     virtual void setShaderProgram(CCGLProgram *pShaderProgram);  
  303.     virtual void            setGLServerState(ccGLServerState glServerState);  
  304.     virtual ccGLServerState getGLServerState();  
  305.       
  306.     /** 
  307.     action相关,可直接参照CCActionManager的相关函数 
  308.     */  
  309.     virtual void setActionManager(CCActionManager* actionManager);  
  310.     virtual CCActionManager* getActionManager();  
  311.     CCAction* runAction(CCAction* action);  
  312.     void stopAllActions(void);  
  313.     void stopAction(CCAction* action);  
  314.     void stopActionByTag(int tag);  
  315.     CCAction* getActionByTag(int tag);  
  316.     unsigned int numberOfRunningActions(void);  
  317.   
  318.     /** 
  319.     Scheduler 
  320.     直接查看CCScheduler的相关定义即可 
  321.     */  
  322.     virtual void setScheduler(CCScheduler* scheduler);  
  323.     virtual CCScheduler* getScheduler();  
  324.     bool isScheduled(SEL_SCHEDULE selector);  
  325.     void scheduleUpdate(void);  
  326.     void scheduleUpdateWithPriority(int priority);  
  327.     void unscheduleUpdate(void);  
  328.     void schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay);  
  329.     void schedule(SEL_SCHEDULE selector, float interval);  
  330.     void scheduleOnce(SEL_SCHEDULE selector, float delay);  
  331.     void schedule(SEL_SCHEDULE selector);  
  332.     void unschedule(SEL_SCHEDULE selector);  
  333.     void unscheduleAllSelectors(void);  
  334.   
  335.     void resumeSchedulerAndActions(void);  
  336.     void pauseSchedulerAndActions(void);  
  337.       
  338.     //Update method will be called automatically every frame if "scheduleUpdate" is called, and the node is "live"  
  339.     virtual void update(float delta);  
  340.   
  341.     /** 
  342.     脚本事件回调相关 
  343.     */  
  344.     virtual void    registerScriptHandler(int handler);  
  345.     virtual void    unregisterScriptHandler(void);  
  346.     inline int      getScriptHandler() { return m_nScriptHandler; };  
  347.     void            scheduleUpdateWithPriorityLua(int nHandler, int priority);//Schedule update for lua script.   
  348.   
  349.     /** 
  350.     自定义数据存储 
  351.     */  
  352.     virtual void* getUserData();  
  353.     virtual void setUserData(void *pUserData);  
  354.     virtual CCObject* getUserObject();  
  355.     virtual void setUserObject(CCObject *pUserObject);  
  356.   
  357.     CCComponent* getComponent(const char *pName) const;  
  358.     virtual bool addComponent(CCComponent *pComponent);  
  359.     virtual bool removeComponent(const char *pName);  
  360.     virtual void removeAllComponents();  
  361.   
  362.     /** 
  363.     opengl 顶点流中的顶点<strong>坐标</strong>的z值 
  364.     无实现,需要在派生类中实现 
  365.     */  
  366.     virtual void setVertexZ(float vertexZ);  
  367.     virtual float getVertexZ();  
  368.   
  369. private:  
  370.     /// lazy allocs m_pChildren  
  371.     void childrenAlloc(void);  
  372.       
  373.     /// helper that reorder a child  
  374.     void insertChild(CCNode* child, int z);  
  375.       
  376.     /// Removes a child, call child->onExit(), do cleanup, remove it from children array.  
  377.     void detachChild(CCNode *child, bool doCleanup);  
  378.       
  379.     /// Convert cocos2d coordinates to UI windows coordinate.  
  380.     CCPoint convertToWindowSpace(const CCPoint& nodePoint);  
  381. };  


回想一下director的drawScene函数里每帧都会调用一次函数里面有这写代码:

    kmGLPushMatrix();


    // draw the scene
    if (m_pRunningScene)
    {
        m_pRunningScene->visit();
    }


    // draw the notifications node
    if (m_pNotificationNode)
    {
        m_pNotificationNode->visit();
    }
    
    if (m_bDisplayStats)
    {
        showStats();
    }

    kmGLPopMatrix();


这样就开始访问遍历以m_pRunningScene为根节点的结点树了。


为了更加明确的说明转换的流程,再回忆下director设置投影矩阵的时候(最初使用 kazmath来设置view matrix 与 projection matrix的函数):

的CCDirector::setProjection函数(可以参考 cocos2dx 2.1.4 程序运行脉络解析3—解析CCEGLView )的分析


再看visit函数:


  1. void CCNode::visit()  
  2. {  
  3.     // quick return if not visible. children won't be drawn.  
  4.     if (!m_bVisible)  
  5.     {  
  6.         return;  
  7.     }  
  8.   
  9.     //压入该节点的<strong>转换</strong>矩阵  
  10.     kmGLPushMatrix();  
  11.   
  12.     //grid暂且不<strong>分析</strong>  
  13.      if (m_pGrid && m_pGrid->isActive())  
  14.      {  
  15.          m_pGrid->beforeDraw();  
  16.      }  
  17.   
  18.      //将压入矩阵堆栈的矩阵生成依据该节点相关属性的<strong>转换</strong>矩阵  
  19.     this->transform();  
  20.   
  21.   
  22.     //visit 的访问(绘制次序):先访问zorder小于0的、再draw自己,再访问zorder大于0的  
  23.     CCNode* pNode = NULL;  
  24.     unsigned int i = 0;  
  25.   
  26.     if(m_pChildren && m_pChildren->count() > 0)  
  27.     {  
  28.         sortAllChildren();  
  29.         // draw children zOrder < 0  
  30.         ccArray *arrayData = m_pChildren->data;  
  31.         for( ; i < arrayData->num; i++ )  
  32.         {  
  33.             pNode = (CCNode*) arrayData->arr[i];  
  34.   
  35.             if ( pNode && pNode->m_nZOrder < 0 )   
  36.             {  
  37.                 pNode->visit();  
  38.             }  
  39.             else  
  40.             {  
  41.                 break;  
  42.             }  
  43.         }  
  44.         // self draw  
  45.         this->draw();  
  46.   
  47.         for( ; i < arrayData->num; i++ )  
  48.         {  
  49.             pNode = (CCNode*) arrayData->arr[i];  
  50.             if (pNode)  
  51.             {  
  52.                 pNode->visit();  
  53.             }  
  54.         }          
  55.     }  
  56.     else  
  57.     {  
  58.         this->draw();  
  59.     }  
  60.   
  61.     // reset for next frame  
  62.     m_uOrderOfArrival = 0;  
  63.   
  64.     //grid暂且不<strong>分析</strong>  
  65.      if (m_pGrid && m_pGrid->isActive())  
  66.      {  
  67.          m_pGrid->afterDraw(this);  
  68.     }  
  69.       
  70.      //当前节点访问完成后pop出该节点关联的<strong>转换</strong>矩阵  
  71.     kmGLPopMatrix();  
  72. }  


CCNode实际上是调用transform函数将自己的转换矩阵正确的设置到 KM_GL_MODELVIEW 矩阵堆栈栈顶:


  1. void CCNode::transform()  
  2. {      
  3.     kmMat4 transfrom4x4;  
  4.   
  5.     // Convert 3x3 into 4x4 matrix  
  6.     //获取根据CCNode相关属性而生成的转置矩阵  
  7.     CCAffineTransform tmpAffine = this->nodeToParentTransform();  
  8.   
  9.     //将cocos2dx矩阵<strong>转换</strong>成opengl矩阵  
  10.     CGAffineToGL(&tmpAffine, transfrom4x4.mat);  
  11.   
  12.     // Update Z vertex manually  
  13.     transfrom4x4.mat[14] = m_fVertexZ;  
  14.   
  15.     //将栈顶执行该节点的<strong>转换</strong>操作  
  16.     kmGLMultMatrix( &transfrom4x4 );  
  17.   
  18.   
  19.     // XXX: Expensive calls. Camera should be integrated into the cached affine matrix  
  20.     //如果设置了camera的话需要额外的设置camera对应<strong>转换</strong>  
  21.     //2dx限定如果有了grid就无视camera了  
  22.     //camera 相关参数合成的matrix与view transform matrix是一致的  
  23.     //经过camera<strong>转换</strong>后就能够呈现使用不同角度(位置)来观看这个节点要绘制的2d图片的效果了  
  24.     //(猜想2dx的45度的视觉效果就是用camera实现的吧)  
  25.     if ( m_pCamera != NULL && !(m_pGrid != NULL && m_pGrid->isActive()) )  
  26.     {  
  27.         bool translate = (m_obAnchorPointInPoints.x != 0.0f || m_obAnchorPointInPoints.y != 0.0f);  
  28.   
  29.         //将锚点移到<strong>局部</strong><strong>坐标</strong>系的原点  
  30.         if( translate )  
  31.             kmGLTranslatef(RENDER_IN_SUBPIXEL(m_obAnchorPointInPoints.x), RENDER_IN_SUBPIXEL(m_obAnchorPointInPoints.y), 0 );  
  32.   
  33.         //添加一个额外的view Matrix transform  
  34.         m_pCamera->locate();  
  35.   
  36.         //恢复锚点原来的位置  
  37.         if( translate )  
  38.             kmGLTranslatef(RENDER_IN_SUBPIXEL(-m_obAnchorPointInPoints.x), RENDER_IN_SUBPIXEL(-m_obAnchorPointInPoints.y), 0 );  
  39.     }  
  40.   
  41. }  


需要注意的是cocos2dx米有使用kazmath 的 kmMat4 而是使用 CCAffineTransform,

其原因是:CCAffineTransform只针对cocos2dx底层支持的2d转换来实现的,效率上而言CCAffineTransform肯定是更快的。

struct CCAffineTransform {
  float a, b, c, d;
  float tx, ty;
};

给出两个矩阵转换的关系图:



CCAffineTransform.h里面有相关的函数对CCAffineTransform 结构体进行相关的转换操作类似kazmath里面的基本数据的相关功能分布形式。


要根据CCNode的相关参数来合成一个 针对父节点转换的矩阵,使CCNode的坐标为父节点坐标系的坐标,由于父节点在node之前被访问父节点的转换矩阵也预先push

进栈了,以此类推当CCNode将相关的转换矩设置到栈顶后得到的坐标是全局坐标系(相关坐标数据经过该转换矩阵转换后),其原点是左下角,与opengl坐标系一致。

下面分析CCNode::nodeToParentTransform:

额,在解释之前为了让大家更清楚具体的转换流程大家想想CCSprite里面有存储这这么一个结构:

    // vertex coords, texture coords and color info
    ccV3F_C4B_T2F_Quad m_sQuad;

这个结构体保存了4个点结构体有个字段是顶点坐标的字段,里面保存了要传入opengl的顶点坐标,而这个值传入后经过mazmath栈顶转换矩阵转换后才得出正确的坐标(这个过程是在shader里面发生的可以参考shader解析篇)你可以把m_sQuad对应的4个点形成的矩形当做看得见的一张图片,而里面的坐标位置是一个相对于该点的局部坐标,一般而言这4个点组成的矩形大小跟对应CCNode的大小相当(一般为origin=(0,0) size = contentSize  ,姑且以这4个点的坐标为参考再来看一下下面的函数实现)。


  1. CCAffineTransform CCNode::nodeToParentTransform(void)  
  2. {  
  3.     if (m_bTransformDirty)   
  4.     {  
  5.         //x,y执行平移<strong>转换</strong>  
  6.         float x = m_obPosition.x;  
  7.         float y = m_obPosition.y;  
  8.   
  9.         //如果忽略锚点则需要将左下角移至<strong>坐标</strong>(父节点<strong>坐标</strong>系)原点  
  10.         if (m_bIgnoreAnchorPointForPosition)   
  11.         {  
  12.             x += m_obAnchorPointInPoints.x;  
  13.             y += m_obAnchorPointInPoints.y;  
  14.         }  
  15.   
  16.         //执行旋转操作  
  17.         //执行旋转的方向为:CW(顺时针)  
  18.         //rotate x:执行旋转后矩形的竖直方向与y轴所成的角度  
  19.         //rotate y:执行旋转后矩形的水平方向与x轴所成的角度  
  20.         //If we skew with the exact same value for both x and y then we're simply just rotating  
  21.         float cx = 1, sx = 0, cy = 1, sy = 0;  
  22.         if (m_fRotationX || m_fRotationY)  
  23.         {  
  24.             float radiansX = -CC_DEGREES_TO_RADIANS(m_fRotationX);  
  25.             float radiansY = -CC_DEGREES_TO_RADIANS(m_fRotationY);  
  26.             cx = cosf(radiansX);  
  27.             sx = sinf(radiansX);  
  28.             cy = cosf(radiansY);  
  29.             sy = sinf(radiansY);  
  30.         }  
  31.   
  32.         bool needsSkewMatrix = ( m_fSkewX || m_fSkewY );  
  33.   
  34.   
  35.         // optimization:  
  36.         // inline anchor point calculation if skew is not needed  
  37.         // Adjusted transform calculation for rotational skew  
  38.         if (! needsSkewMatrix && !m_obAnchorPointInPoints.equals(CCPointZero))  
  39.         {  
  40.             x += cy * -m_obAnchorPointInPoints.x * m_fScaleX + -sx * -m_obAnchorPointInPoints.y * m_fScaleY;  
  41.             y += sy * -m_obAnchorPointInPoints.x * m_fScaleX +  cx * -m_obAnchorPointInPoints.y * m_fScaleY;  
  42.         }  
  43.   
  44.   
  45.         // Build Transform Matrix  
  46.         // Adjusted transform calculation for rotational skew  
  47.         //生成的矩阵相当于下面的矩阵,如果x == y 那么右边的矩阵为绕z轴旋转的矩阵了  
  48.         //  
  49.         //m_sTransform =:  
  50.         //  
  51.         //|1 , 0 , x|   |cy * m_fScaleX , -sx * m_fScaleY   , 0|  
  52.         //|0 , 1 , y| * |sy * m_fScaleX , cx * m_fScaleY    , 0|  
  53.         //|0 , 0 , 1|   |   0   ,   0       , 1|  
  54.         m_sTransform = CCAffineTransformMake( cy * m_fScaleX,  sy * m_fScaleX,  
  55.             -sx * m_fScaleY, cx * m_fScaleY,  
  56.             x, y );  
  57.   
  58.         // XXX: Try to inline skew  
  59.         // If skew is needed, apply skew and then anchor point  
  60.         if (needsSkewMatrix)   
  61.         {  
  62.             CCAffineTransform skewMatrix = CCAffineTransformMake(1.0f, tanf(CC_DEGREES_TO_RADIANS(m_fSkewY)),  
  63.                 tanf(CC_DEGREES_TO_RADIANS(m_fSkewX)), 1.0f,  
  64.                 0.0f, 0.0f );  
  65.   
  66.             //m_sTransform = m_sTransform * skewMatrix  
  67.             m_sTransform = CCAffineTransformConcat(skewMatrix, m_sTransform);  
  68.   
  69.             // adjust anchor point  
  70.             if (!m_obAnchorPointInPoints.equals(CCPointZero))  
  71.             {  
  72.                 //m_sTransform = m_sTransform * TM(-m_obAnchorPointInPoints.x,-m_obAnchorPointInPoints.y)  
  73.                 m_sTransform = CCAffineTransformTranslate(m_sTransform, -m_obAnchorPointInPoints.x, -m_obAnchorPointInPoints.y);  
  74.             }  
  75.         }  
  76.           
  77.           
  78.         if (m_bAdditionalTransformDirty)  
  79.         {  
  80.             //最后执行AdditionalTransform<strong>转换</strong>  
  81.             //m_sTransform = m_sAdditionalTransform * m_sTransform  
  82.             m_sTransform = CCAffineTransformConcat(m_sTransform, m_sAdditionalTransform);  
  83.             m_bAdditionalTransformDirty = false;  
  84.         }  
  85.         //总结一下<strong>转换</strong>的顺序:(有括号的矩阵可能不需要执行<strong>转换</strong>)  
  86.         //m_sTransform = [m_sAdditionalTransform  *] translate * rotate [* skewMatrix [* TM(-m_obAnchorPointInPoints.x,-m_obAnchorPointInPoints.y)]]  
  87.         //顶点的<strong>转换</strong>顺序是由右到左一次与上面的矩阵相乘执行<strong>转换</strong>的其中最左边锚点偏移<strong>转换</strong>是可选的是因为translate矩阵的生成过程做了优化处理(skew<strong>转换</strong>优化),  
  88.         //参考上面2dx注释,可将条件if (! needsSkewMatrix && !m_obAnchorPointInPoints.equals(CCPointZero))使之为真来推算<strong>转换</strong>结果是一样的  
  89.         //如果将所有的<strong>转换</strong>全部都用上则<strong>转换</strong>顺序为:先移动让锚点为<strong>坐标</strong>原点,再执行skew<strong>转换</strong>,在执行rotation<strong>转换</strong>,最后执行移动让锚点位置在父节点<strong>坐标</strong>系对应的<strong>坐标</strong>位置,  
  90.         //最后如果有额外的<strong>转换</strong>则执行m_sAdditionalTransform<strong>转换</strong>  
  91.   
  92.         m_bTransformDirty = false;  
  93.     }  
  94.   
  95.     return m_sTransform;  
  96. }  


最后请大家注意下CCAffineTransform有个很奇葩的现象:

执行函数:
CC_DLL CCAffineTransform CCAffineTransformConcat(const CCAffineTransform& t1, const CCAffineTransform& t2);

实际上是返回  t2 * t1的结果。

一般顶点转换操作:
CC_DLL CCPoint __CCPointApplyAffineTransform(const CCPoint& point, const CCAffineTransform& t);

返回 t * point的值 


以下函数:

//t * TM(tx,ty)
CC_DLL CCAffineTransform CCAffineTransformTranslate(const CCAffineTransform& t, float tx, float ty);


//Rotate around Z axis
//t*RZM(angle)
CC_DLL CCAffineTransform CCAffineTransformRotate(const CCAffineTransform& aTransform, float anAngle);


//t*SM(sx,sy)
CC_DLL CCAffineTransform CCAffineTransformScale(const CCAffineTransform& t, float sx, float sy);


矩阵相乘的顺序不同执行变换的结果也是不同的,我被这几个可恶的函数搞晕了好长时间了,哎...


ok分析 完毕,如果有错误的地方欢迎指处~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值