ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2021-10-14 16:00:24  阅读:185  来源: 互联网

标签:cocos 渲染 flow RenderFlow 源码 let func ._ device


从CCDirector.js中的mainLoop我们了解到 renderer.render是实际参与渲染的方法:顺着线索我们找到了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,渲染,flow,RenderFlow,源码,let,func,._,device
来源: https://blog.csdn.net/lck8989/article/details/120765452

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有