【深入瞭解cocos2d-x 3.x】UI樹(3)——UI樹的渲染機制

渲染系統是遊戲引擎裏面最重要的一個模塊之一了,如何遍歷UI樹,如何將UI合理的渲染在屏幕上,如何選擇渲染的順序,這是渲染系統最需要考慮的。其實遍歷的順序就決定了渲染的順序。

cocos2d-x的渲染函數是通過Node::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);
	
    bool visibleByCamera = isVisitableByVisitingCamera();

    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
        if (visibleByCamera)
            this->draw(renderer, _modelViewTransform, flags);

        for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
            (*it)->visit(renderer, _modelViewTransform, flags);
    }
    else if (visibleByCamera)
    {
        this->draw(renderer, _modelViewTransform, flags);
    }
}

然後可以開始一步一步分析代碼了,首先快速去掉不可見的元素,並且不繪製它的子元素。_visible的判斷就幹了這件事情。

然後判斷子節點是否爲空,子節點爲空的判斷是否在攝像機可視範圍內,只有在可視範圍內才進行繪製,如下:

    else if (visibleByCamera)
    {
        this->draw(renderer, _modelViewTransform, flags);
    }

然後重點就是子節點非空的情況了,子節點非空的時候,先將所有子節點進行排序,根據什麼排序呢?走進sortAllChildren函數看一看

void Node::sortAllChildren()
{
    if (_reorderChildDirty)
    {
        std::sort(std::begin(_children), std::end(_children), nodeComparisonLess);
        _reorderChildDirty = false;
    }
}

還要繼續深入nodeComparisonLess函數

bool nodeComparisonLess(Node* n1, Node* n2)
{
    return( n1->getLocalZOrder() < n2->getLocalZOrder() ||
           ( n1->getLocalZOrder() == n2->getLocalZOrder() && n1->getOrderOfArrival() < n2->getOrderOfArrival() )
           );
}

可以看到它是根據LocalZOrder進行排序的,當LocalZOrder相同的情況下,根據加入UI樹的順序排序。那麼LocalZOrder就是非常重要的元素了,排序好的子節點是基於LocalZOrder遞增的。接下來看看子節點是如何進行繪製的。

 // 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;
        }

首先繪製_localZOrder小於0的,然後繪製自身 最後繪製大於等於0的

// self draw
        if (visibleByCamera)
            this->draw(renderer, _modelViewTransform, flags);

        for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
            (*it)->visit(renderer, _modelViewTransform, flags);

下面是一張圖便於理解



所以UI樹的遍歷方法就是中序遍歷的深度優先算法。總結如下:

1.遍歷左邊子節點

2.遍歷根節點

3.遍歷右邊子節點


通過這樣的方法,可以保證UI的繪製順序可以通過_localZOrder 來調節,小於0的將被首先繪製,然後再繪製父節點。然後再繪製大於0的。

所以綜上所述,_localZOrder 越小的元素將會被優先繪製。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章