在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,
_renderData
和InputAssembler
都是数据容器,_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);
};
原文:https://www.cnblogs.com/kundij/p/12712502.html