孤海傲月

导航

cocos源码分析--绘制顺序LocalZOrder、GlobalZOrder、OrderOfArrival

使用规则

节点的渲染顺序跟节点的三个成员变量有关(_localZOrder、_globalZOrder、_orderOfArrival)分别对应三个设置函数setLocalZOrder、setGlobalZOrder、setOrderOfArrival。无论是_localZOrder、_globalZOrder、_orderOfArrival都是越大的越后渲染,越小的越先渲染,而且有_globalZOrder的优先级大于_localZOrder的优先级大于_orderOfArrival的优先级。所以我们判断节点间的渲染(绘制)顺序时应先对比他们的_globalZOrder值,如若相等,再对比他们的_localZOrder值,如若相等,再对比他们的_orderOfArrival值。其中,_orderOfArrival值在调用addChild函数是自动给出,一般我们不调用setOrderOfArrival函数去更改节点间的渲染(绘制)顺序。

当采用LocalZOrder作为节点渲染(绘制)顺序的判断值时,父节点的LocalZOrder不与子节点的LocalZOrder值作比较。子节点中LocalZOrder值小于0的节点作为以父节点为根节点的树的左子树的根节点,大于0的作为右子树的根节点。所以在中序遍历下,先(渲染)绘制子节点中LocalZOrder值小于0的子节点,再渲染(绘制)父节点,再渲染LocalZOrder值大于0的子节点。

代码原理

localZOrder和orderOfArrival在visit里面

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【对scene来说,执行下面代码之前,里面已经有3个modelview】
    //这个代码针对2.0的,对3.1没啥意义了
    director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);

    int i = 0;

    if(!_children.empty())
    {
        sortAllChildren();
        // draw children zOrder < 0
        for( ; i < _children.size(); i++ )
        {
            auto node = _children.at(i);

            if ( node && node->_localZOrder < 0 )
                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的时候,现在不需要这个了
     矩阵的转换都在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;
}
void Node::sortAllChildren()
{
    if( _reorderChildDirty ) {
        std::sort( std::begin(_children), std::end(_children), nodeComparisonLess );
        _reorderChildDirty = false;
    }
}
bool nodeComparisonLess(Node* n1, Node* n2)
{
    return( n1->getLocalZOrder() < n2->getLocalZOrder() ||
           ( n1->getLocalZOrder() == n2->getLocalZOrder() && n1->getOrderOfArrival() < n2->getOrderOfArrival() )
           );
}

通过排序之后,然后遍历,加入到 command命令中

globalZOrder在CCRender中进行排序,代码如下:

void RenderQueue::sort()
{
    // Don't sort _queue0, it already comes sorted
    //不对queue0的在进行排序,他们是 按照localQueue排序的
    std::sort(std::begin(_queueNegZ), std::end(_queueNegZ), compareRenderCommand);
    std::sort(std::begin(_queuePosZ), std::end(_queuePosZ), compareRenderCommand);
}

所以globalZOrder在LocalZOrder之前。

 

posted on 2018-06-19 16:45  孤海傲月  阅读(1200)  评论(0编辑  收藏  举报