cocos creator渲染组件源码解析

  在cocos引擎中,所有的渲染组件都是继承自 cc.RenderComponent,例如cc.Sprite,cc.Label 等。组件的 Assembler 主要负责组件数据的更新处理及填充,由于不同的渲染组件在数据内容及填充上也都不相同,所以每一个渲染组件都会对应拥有自己的 Assembler 对象,而所有的 Assembler 对象都是继承自 cc.Assembler。Material 作为资源,主要记录渲染组件的渲染状态,使用的纹理及 Shader。

一、首先分析Assembler,主要代码如下:

  

// renderCompCtor 组件类

//assembler  组件装配类

Assembler.register = function (renderCompCtor, assembler) { renderCompCtor.__assembler__ = assembler; }; Assembler.init = function (renderComp) { let renderCompCtor = renderComp.constructor; let assemblerCtor = renderCompCtor.__assembler__; while (!assemblerCtor) { renderCompCtor = renderCompCtor.$super; if (!renderCompCtor) { cc.warn(`Can not find assembler for render component : [${cc.js.getClassName(renderComp)}]`); return; } assemblerCtor = renderCompCtor.__assembler__; } if (assemblerCtor.getConstructor) { assemblerCtor = assemblerCtor.getConstructor(renderComp); } if (!renderComp._assembler || renderComp._assembler.constructor !== assemblerCtor) { let assembler = assemblerPool.get(assemblerCtor); assembler.init(renderComp); renderComp._assembler = assembler; } };

  渲染组件通过 Assembler.register注册到引擎中,比如图形渲染组件的注册代码为 Assembler.register(cc.Graphics, GraphicsAssembler),cc.Graphics为图形类,GraphicsAssembler继承自Assembler类,渲染组件持有_assembler,_assembler持有_renderData,_renderDataInputAssembler都是数据容器,_assembler是数据操作,_assembler可以创建和updateRenderData,更新verts,InputAssembler是在渲染时用到的,用于组织传入GPU的数据.

  

  在 v2.x 中,RenderFlow 会根据渲染过程中调用的频繁度划分出多个渲染状态,比如 Transform,Render,Children 等,而每个渲染状态都对应了一个函数。在 RenderFlow 的初始化过程中,会预先根据这些状态创建好对应的渲染分支,这些分支会把对应的状态依次链接在一起。例如如果一个节点在当前帧需要更新矩阵,以及需要渲染自己,那么这个节点会更新他的 flag 为node._renderFlag = RenderFlow.FLAG_TRANSFORM | RenderFlow.FLAG_RENDER。RenderFlow 在渲染这个节点的时候就会根据节点的 node._renderFlag 状态进入到 transform => render 分支,而不需要再进行多余的状态判断.

  cc.renderer对象,是一个全局对象,提供基础渲染接口的渲染器对象. 里面存放了一些渲染有关的类定义以及一些全局属性如device,InputAssembler,Pass等等, 核心的是两个属性,一个是_froward一个是_flow._flow是一个cc.RenderFlow类.在初始化的过程中,会创建RenderFlow的实例,并传入_flow.init方法中

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);
            this._forward = new ForwardRenderer(this.device, builtins);
            this._handle = new ModelBatcher(this.device, this.scene);
            this._flow.init(this._handle, this._forward);
        }
        config.addStage('shadowcast');
        config.addStage('opaque');
        config.addStage('transparent');
    },
render (ecScene, dt) {
        this.device.resetDrawCalls();
        if (ecScene) {
            // walk entity component scene to generate models
            this._flow.render(ecScene, dt);
            this.drawCalls = this.device.getDrawCalls();
        }
    },
RenderFlow.render = function (scene, dt) {
    _batcher.reset();
    _batcher.walking = true;

    RenderFlow.visitRootNode(scene);

    _batcher.terminate();
    _batcher.walking = false;

    _forward.render(_batcher._renderScene, dt);
};

  

 






猜你喜欢

转载自www.cnblogs.com/kundij/p/12712502.html