Cocos场景遍历与渲染

Cocos场景遍历与渲染

声明:本文主要分析cocos2d-x-3.12的代码,该部分代码在后续版本有一些变化

场景遍历

Cocos在绘制场景时,会遍历当前运行的场景runningScene场景中的所有元素,遍历完成后会生成一个OpenGL绘制命令的队列,然后调用Renderer::render()函数绘制所有元素。遍历场景的调用栈如下。

 

Node::visit函数

voidNode::visit(Renderer* renderer, constMat4 &parentTransform, uint32_tparentFlags)
{
    // quick return if not visible. children won't be drawn.
    if (!_visible)
    {
        return;
    }
 
    uint32_tflags = processParentFlags(parentTransform, parentFlags);
 
    // IMPORTANT:
    // To ease the migration to v3.0, we still support theMat4 stack,
    // but it is deprecated and your code should not rely onit
    _director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    _director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
    
    boolvisibleByCamera = isVisitableByVisitingCamera();
 
    inti = 0;
 
    if(!_children.empty())
    {
        sortAllChildren();
        // draw children zOrder < 0
        for( ; i < _children.size(); i++ )
        {
            autonode = _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(autoit=_children.cbegin()+i; it!=_children.cend(); ++it)
            (*it)->visit(renderer, _modelViewTransform, flags);
    }
    elseif (visibleByCamera)
    {
        this->draw(renderer, _modelViewTransform, flags);
    }
 
    _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
    // FIX ME: Why need to set _orderOfArrival to 0??
    // Please refer tohttps://github.com/cocos2d/cocos2d-x/pull/6920
    // reset for next frame
    // _orderOfArrival = 0;
}



该函数主要步骤:

1.      判断几点是否可见,如果不可见则直接退出。所以如果节点不可见,则子节点也不可见。

2.      判断元素是否有孩子节点,

如果没有则调用Node::draw函数生成绘制命令。

如果存在子节点,则会先对所有子节点排序,然后先遍历_localZOrder小于0的子节点,在调用自己的draw函数,最后遍历localZOrder大于等于0的节点。

所以如果localZOrder的值小于0,则会绘制在父节点的下面,如果localZOrder大于等于0,则会绘制在父节点的上面。

 

子节点排序

排序函数

voidNode::sortAllChildren()
{
    if (_reorderChildDirty)//只有当子节点有改变时才会排序
    {
        std::sort(std::begin(_children), std::end(_children), nodeComparisonLess);
        _reorderChildDirty = false;
    }
}

排序比较方式

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

排序会先比较localZOrder的值,小值排在前面。如果localZOrder的值相等,则会比较OrderOfArrival的值。OrderOfArrival是节点插入父节点的顺序,越先插入的节点值会更小,后插入的节点值会更大。所以localZOrder相等时后插入的节点会显示在先插入节点的前面。

 

OrderOfArrival的生成

Node::addChild函数内部会让子节点调用setOrderOfArrival(s_globalOrderOfArrival++)函数

s_globalOrderOfArrival是一个全局共享的值,起始为0,每次调用addChild,该值都会增加,越后面调用值越大。

 

场景绘制

 

Scene::render函数中,调用visit函数遍历完节点生成所有节点的绘制命令后,会调用renderer->render()函数,在Renderer::render函数内部,会先对绘制命令进行排序,依据Node::_globalZOrder的值从小到达排序,然后再将命令传给OpenGL绘制图像。具体流程如下:

因为OpenGL执行绘制命令,会根据接的的globalZOrder排序,所以globalZOrder也可以控制节点的层级。且globalZOrder是调整节点在整个场景中的层级。

 

节点层级的控制

影响节点层级一共有三个值globalZOrderlocalZOrderorderOfArrival,都是值越大越靠前。三个值的对层级影响的优先顺序为globalZOrderlocalZOrderorderOfArrival。当globalZOrder的值大时,则会忽略localZOrderorderOfArrivalglobalZOrder值大则排在前面。

 

 

orderOfArrival

orderOfArrival是节点添加到父节点时会被设置,child->setOrderOfArrival(s_globalOrderOfArrival++)。所有节点的orderOfArriva都是通过s_globalOrderOfArrival值累加得到的。s_globalOrderOfArrivalNode节点的一个静态变量,初始值为1intNode::s_globalOrderOfArrival = 1;)。每次有调用addChild函数,则该值会加1,所以所有节点的该值都不一样。

 

localZOrder

localZOrder在节点的构造函数中设置为0,默认值为0。可以通过函数

voidNode::_setLocalZOrder(intz)设置

localZOrderorderOfArrival都只是在遍历子节点时排序使用,排序比较时会先比价LocalZOrder的值,如过不相等则返回相应的比较结果,如果相等则会比较orderOfArrival的值。因为两个值都只是用在子节点排序上,所以localZOrderorderOfArrival只会影响子节点之间的排序,所以如果两个节点的父节点不同则无法通过localZOrderorderOfArrival控制层级。

 

对于子节点和父节点的遍历顺序:

LocalZOrder小于0的子节点à父节点à LocalZOrder大于等于0的子节点。

所以LocalZOrder小于0会绘制在父节点下面。

 

globalZOrder

globalZOrder在节点的构造函数中设置为0,默认值为0globalZOrder可以通过函数voidNode::setGlobalZOrder(floatglobalZOrder)设置。

globalZOrder是在场景绘制命令生成后,会根据globalZOrder对节点的绘制命令排序。所以globalZOrder是对场景全局节点的层级进行控制的,不管节点的父节点是谁,只要globalZOrder的值大,则绘制会更靠前。globalZOrder只是控制一个场景的节点,不可跨场景。

 

层级控制流程

 

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Cocos Creator ,你可以使用自定义材质来实现顶点着色渲染。顶点着色渲染是一种在渲染管线对模型的每个顶点进行颜色计算的技术,通过改变顶点的颜色来实现特定效果。下面是一个简单的示例代码: ```javascript // 在节点上添加一个脚本组件 VertexColor.js cc.Class({ extends: cc.Component, properties: { color: cc.Color.WHITE, // 自定义颜色 }, // 在渲染组件的 updateMaterial 方法设置材质的属性 updateMaterial: function() { var material = this.getComponent(cc.RenderComponent).getMaterial(0); // 获取渲染组件的材质 material.setProperty('u_color', this.color); // 设置自定义颜色属性 }, // 在 onLoad 方法注册 updateMaterial 方法到渲染组件的 updateMaterial 方法 onLoad: function() { this.getComponent(cc.RenderComponent).updateMaterial = this.updateMaterial.bind(this); }, }); ``` 在上述代码,我们假设节点上有一个渲染组件(如 Sprite、Mesh 等),我们通过自定义脚本组件 `VertexColor.js` 来实现顶点着色渲染。脚本组件定义了一个 `color` 属性,用于设置自定义颜色。在 `updateMaterial` 方法,我们获取渲染组件的材质,并设置自定义颜色属性。最后,在 `onLoad` 方法将 `updateMaterial` 方法注册到渲染组件的 `updateMaterial` 方法,以便在每帧更新时调用。 然后,你可以在 Cocos Creator 编辑器将该脚本组件 `VertexColor.js` 添加到需要进行顶点着色渲染的节点上。在脚本组件的属性面板,可以设置自定义的颜色值。 需要注意的是,顶点着色渲染需要使用支持顶点着色的材质和渲染组件,例如使用自定义的 Shader 或在材质设置相应的 Uniform 属性等。具体的实现方式和效果可以根据你的需求和场景进行自定义调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值