当前位置: 首页 > 工具软件 > VisIt > 使用案例 >

cocos 中每个节点的visit与draw函数

蒲勇
2023-12-01

 visit函数内会先sortAllChildren,然后调用自己的draw函数,然后遍历所有子节点递归调用字节的visit:

因为draw函数会创建渲染指令加到渲染队列中,所以先执行visit的节点会先进行绘制,

它的渲染指令在渲染队列的前面,sortAllChildren根据ZOrder,由小到大排序,ZOrder小的先绘制。

 

cocos渲染流程是从Director类的主循环mainLoop中开始:

1.调用drawScene():

//精简后的代码,方便理解
void Director::drawScene()
{
    /*此处省略一些代码
        .....
    */
    _renderer->clear();
    pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    if (_runningScene)
    {
        /*绘制当前场景,实际上不是真正绘制而是为场景内的每个节点创建渲染指令。
遍历访问场景内的节点树(visit和draw函数),初始化渲染指令加到渲染队列中。
为每个节点计算出将要传入着色器的数据:模型视图矩阵、shader对象(GLProgramState)等  
这些数据封装在渲染指令中RenderCommand        
*/
        _runningScene->render(_renderer);
    }
    //这里是真正的渲染,visitRenderQueue函数:变量渲染队列中的所有指令
    //processRenderCommand函数内处理单个指令,不同的渲染指令处理方式不同
    //能合批的合批(QUAD_COMMAND和TRIANGLES_COMMAND可以合批)
    //然后调用flush:1.发送顶点数据到opengl缓冲区 2.调用glDrawElements绘制
    //CUSTOM_COMMAND则执行自定义的渲染回调函数,一般是onDraw()函数
    _renderer->render();
    popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    // swap buffers
    if (_openGLView)
    {
        _openGLView->swapBuffers();
    }
}

2._runningScene->render(_renderer):


void Scene::render(Renderer* renderer)
{
    ...
    //计算节点相对于父节点坐标系的变换矩阵,也是当前节点相对于父节点的位移、旋转、缩放属性
    //这些属性构成一个矩阵,这个矩阵需要乘以所有父节点的变换矩阵,就可以得到这个节点在世界坐标系的变换矩阵,可以理解成相对于父节点的变换和所有父节点变换要叠加到一起
    const auto& transform = getNodeToParentTransform();
    //此处调用基类visit函数
    visit(renderer, transform, 0);
    ...
}

3.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;
    }
     .....
    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);
    }
}


void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
#if CC_USE_CULLING
    // Don't do calculate the culling if the transform was not updated
    auto visitingCamera = Camera::getVisitingCamera();
    auto defaultCamera = Camera::getDefaultCamera();
    if (visitingCamera == defaultCamera) {
        _insideBounds = ((flags & FLAGS_TRANSFORM_DIRTY)|| visitingCamera->isViewProjectionUpdated()) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
    }
    else
    {
        _insideBounds = renderer->checkVisibility(transform, _contentSize);
    }

    if(_insideBounds)
#endif
    {
        _trianglesCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, _polyInfo.triangles, transform, flags);
        renderer->addCommand(&_trianglesCommand);
    }
}

 

 类似资料: