cocos creator 2.4.0 渲染流程详解(三:Ren

2020-08-08  本文已影响0人  vectorZ

全文共5000+字,分为8个章节,由本人历时一周整理而来。由于篇幅问题,将本文分为8个章节分开发布。全文 () 详细描述了cocoscreator 引擎的2.40版本中,web平台的js部分引擎的渲染流程。请将文章配合源码一起食用!

​由于我尚在学习引擎源码中,文章可能有不正确的部分,所以我会不断更新内容。如有错误或补充,请留言交流!


全部章节链接:

一:渲染流程中用到的核心类

二 : 渲染流程详解

三: RenderFlow 的运行逻辑

四: Assembler 的作用

五: ModelBatcher 数据合批

六: 材质系统

七: ForwardRender


三 RenderFlow 的运行逻辑

RenderFlow : 渲染流,用以遍历场景下所有节点,根据每个节点的_renderFlag , 处理节点的位置,颜色,透明度,更新并渲染。

3.1 性能优化

在v1.x版本中,每次渲染都会进行很多动态判断,需要去判断每个节点是否需要更新位置矩阵,是否需要渲染,在这些过程中会有很多无用分支判断,消耗性能。
所以在v2.x版本中,RenderFlow根据渲染过程中调用的频繁度划分出多个渲染状态,比如 Transform,Render,Children 等,而每个渲染状态都对应了一个函数。在 RenderFlow 的初始化过程中,会预先根据这些状态创建好对应的渲染分支,这些分支会把对应的状态依次链接在一起。在渲染前会更新该节点的_renderFlag ,在渲染该节点时就可以直接根据 _renderFlag的值,进行相应分支的处理,不用进行多余的状态判断。
例如一个节点在当前帧需要更新矩阵,以及需要渲染自己,那么这个节点会更新他的 flag 为
node._renderFlag = RenderFlow.FLAG_TRANSFORM | RenderFlow.FLAG_RENDER。

更加详细的内容可见文末的相关链接中 : RenderFlow的性能优化.

3.2 RenderFlow 内的链式方法的创建与调用

RenderFlow中根据 _renderFlag 获取渲染流的代码如下:

function getFlow (flag) {
    let flow = null;
    let tFlag = FINAL;
    while (tFlag > 0) {
        if (tFlag & flag)// 如果flag标识匹配,则添加新的渲染流
            flow = createFlow(tFlag, flow);// 需要把上一步创建flow传入,作为子流
        tFlag = tFlag >> 1;// 标志右移一位
    }
    return flow;
}

createFlow() 中会根据flag创建对应的渲染流,并加入链中,代码如下:

function createFlow (flag, next) {
    let flow = new RenderFlow();
    flow._next = next || EMPTY_FLOW;// 将本次创建的flow加入链表首部
    // 根据不同的flag设置不同的处理方法
    switch (flag) {
        case DONOTHING: flow._func = flow._doNothing; break;
        case BREAK_FLOW: flow._func = flow._doNothing; break;
        case LOCAL_TRANSFORM: flow._func = flow._localTransform; break;
        case WORLD_TRANSFORM: flow._func = flow._worldTransform; break;
        case OPACITY: flow._func = flow._opacity; break;
        case COLOR: flow._func = flow._color; break;
        case UPDATE_RENDER_DATA: flow._func = flow._updateRenderData; break;
        case RENDER: flow._func = flow._render; break;
        case CHILDREN: flow._func = flow._children; break;
        case POST_RENDER: flow._func = flow._postRender; break;
    }
    return flow;
}

RenderFlow是根据node节点上的_renderFlag 来进行不同的渲染流程,所以当node节点上的位置,颜色,透明度等参数改变后,需要同步修改_renderFlag。这样在渲染时会去根据flag处理对应的流程。

3.3 详解 RenderFlow 的不同操作

RenderFlow根据 _renderFlag 创建了链式渲染流,但各个不同的FLAG对应的方法,都做了些什么,下面会详细说明。

_proto._render = function (node) {
    let comp = node._renderComponent;
    comp._checkBacth(_batcher, node._cullingMask);
    comp._assembler.fillBuffers(comp, _batcher);
    this._next._func(node);
};

调用 RenderComponent 的 _checkBacth 检测合批。
调用 Assembler 的 fillBuffers 填充数据。

相关链接

  1. 自定义渲染https://docs.cocos.com/creator/manual/zh/advanced-topics/custom-render.html#%E8%87%AA%E5%AE%9A%E4%B9%89-assembler

  2. RenderFlow的性能优化http://docs.cocos.com/creator/manual/zh/advanced-topics/render-flow.html#

  3. 自定义渲染合批之自定义顶点格式https://forum.cocos.org/t/demo/95087

  4. 自定义RenderFlow,处理背包等场景下drawcall过多:https://forum.cocos.org/t/ui/80026

  5. 材质系统https://docs.cocos.com/creator3d/manual/zh/material-system/overview.html

上一篇 下一篇

猜你喜欢

热点阅读