cocos 源码阅读(二:RenderFlow 渲染流)

从CCDirector.js中的mainLoop我们了解到 renderer.render是实际参与渲染的方法:顺着线索我们找到了RenderFlow这个类:下面是我整理的部分关键的方法和属性:

cocos 源码阅读(二:RenderFlow 渲染流)

首先看一下initWebGL方法:

initWebGL (canvas, opts) {
        require('./webgl/assemblers');
        const ModelBatcher = require('./webgl/model-batcher');

        this.Texture2D = gfx.Texture2D;
        this.canvas = canvas;
        this._flow = cc.RenderFlow;
        
        if (CC_JSB && CC_NATIVERENDERER) {
            // native codes will create an instance of Device, so just use the global instance.
            this.device = gfx.Device.getInstance();
            this.scene = new renderer.Scene();
            let builtins = _initBuiltins(this.device);
            this._forward = new renderer.ForwardRenderer(this.device, builtins);
            let nativeFlow = new renderer.RenderFlow(this.device, this.scene, this._forward);
            this._flow.init(nativeFlow);
        }
        else {
            let Scene = require('../../renderer/scene/scene');
            let ForwardRenderer = require('../../renderer/renderers/forward-renderer');
            this.device = new gfx.Device(canvas, opts);
            this.scene = new Scene();
            let builtins = _initBuiltins(this.device);
            // 前向渲染对象负责将view视图通过device渲染都屏幕上
            this._forward = new ForwardRenderer(this.device, builtins);
            // 渲染前批处理,优化性能,降低drawcall
            this._handle = new ModelBatcher(this.device, this.scene);
            // 初始化渲染流对象依赖 前向渲染对象和批处理
            this._flow.init(this._handle, this._forward);

            console.log(`scene is `,this.scene,' and device is ',this.device,' and _flow is ',this._flow,' and _handle is ',this._handle);
        }
    },

再来看看主角方法render(scene,dt):

render (ecScene, dt) {
        /** 重置drawcall */
        this.device.resetDrawCalls();
        if (ecScene) {
            // walk entity component scene to generate models
            /** 调用渲染静态函数 */
            this._flow.render(ecScene, dt);
            this.drawCalls = this.device.getDrawCalls();
        }
    },

 继续跟进看看render: 下一节着重看看这个前向渲染 _forward

RenderFlow.render = function (rootNode, dt) {
    _batcher.reset();
    _batcher.walking = true;

    /** 递归遍历根节点 */
    RenderFlow.visitRootNode(rootNode);

    _batcher.terminate();
    _batcher.walking = false;
    // 将batcher中的渲染数据渲染到屏幕 _forward渲染数据需要用到合批的渲染数据两个类有相互依赖的关系
    _forward.render(_batcher._renderScene, dt);
};

看看渲染流的init静态方法:

RenderFlow.init = function (batcher, forwardRenderer) {
    _batcher = batcher;
    _forward = forwardRenderer;
    
    // 这里flows是一个包含了1025个RenderFlow对象,而每一个对象又是一个渲染链表对象
    flows[0] = EMPTY_FLOW;
    for (let i = 1; i < FINAL; i++) {
        flows[i] = new RenderFlow();
    }
};

 看看init方法:渲染流真正执行_func的时候会调用它,是根据节点的渲染标识进行创建的

function init (node) {
    // 拿到节点的渲染标识
    let flag = node._renderFlag;
    // 根据节点身上的渲染标识进行创建渲染流
    let r = flows[flag] = getFlow(flag);
    // 执行对应的渲染流函数
    r._func(node);
}

看看getFlow函数,就是在这里创建了渲染流链表:

function getFlow (flag) {
    let flow = null;
    let tFlag = FINAL;
    while (tFlag > 0) {
        if (tFlag & flag)
            // 创建渲染流 将上一个flow传入构成一个链
            flow = createFlow(tFlag, flow);
        tFlag = tFlag >> 1;
    }
    return flow;
}

每一次createFlow都会将当前的flow置为头节点

function createFlow (flag, next) {
    let flow = new RenderFlow();
    // 将当前创建的渲染流置于链表的头部
    flow._next = next || EMPTY_FLOW;

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

上一篇:打开Cocos Creator 编辑器,报错property uuid of null


下一篇:Cocos Creator 3D后期效果解决方案-KylinsPostEffects