前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Cocos Creator 2.2 的渲染流程(原生渲染)

Cocos Creator 2.2 的渲染流程(原生渲染)

作者头像
我不是码神
发布2022-07-28 15:54:33
1.5K0
发布2022-07-28 15:54:33
举报
文章被收录于专栏:流媒体技术

Cocos Creator 升级的2.2之后,渲染流程发生了比较大的变化,主要是重构了一些类,属性的位置发生了变化。为了防止日后忘记,先记录下来。

首先在engine/cocos2d/core/renderer/index.js中定义了cc.renderer对象,是一个全局对象,里面存放了一些渲染有关的类定义以及一些全局属性如device

核心的是两个属性,一个是_froward一个是_flow

_flow是一个cc.RenderFlow类(注意:不是实例),cc.RenderFlow定义在engine/cocos2d/core/renderer/render-flow.js

在初始化的过程中,会创建RenderFlow的实例,并传入_flow.init方法中

代码语言:javascript
复制
            let nativeFlow = new renderer.RenderFlow(this.device, this.scene, this._forward);
            this._flow.init(nativeFlow);
代码语言:javascript
复制
RenderFlow.init = function (batcher, forwardRenderer) {
    _batcher = batcher;
    _forward = forwardRenderer;

    flows[0] = EMPTY_FLOW;
    for (let i = 1; i < FINAL; i++) {
        flows[i] = new RenderFlow();
    }
};

注意:_batcher就是传入的RenderFlow的实例

渲染开始

入口代码在engine/cocos2d/core/renderer/index.js中的render方法:

代码语言:javascript
复制
    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();
        }
    },

然后进入

代码语言:javascript
复制
RenderFlow.render = function (scene, dt) {
    _batcher.reset();
    _batcher.walking = true;

    RenderFlow.visitRootNode(scene);

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

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

接下来会进入两个大的流程:

A--------------

RenderFlow.visitRootNode(scene);

这句将进入RenderFlow的实例里面的方法调用

在RenderFlow的实例方法中

核心的方法是_updateRenderData用于更新各级渲染对象的顶点信息等

_render方法,用于执行实际的渲染:

代码语言:javascript
复制
_proto._render = function (node) {
    let comp = node._renderComponent;
    comp._checkBacth(_batcher, node._cullingMask);
    comp._assembler.fillBuffers(comp, _batcher);
    this._next._func(node);
};

其中,_renderComponent属性是继承自RenderComponent的对象会指向自己

代码在core/components/CCRenderComponent.js

代码语言:javascript
复制
    onEnable () {
        if (this.node._renderComponent) {
            this.node._renderComponent.enabled = false;
        }
        this.node._renderComponent = this;

        this.node.on(cc.Node.EventType.SIZE_CHANGED, this._onNodeSizeDirty, this);
        this.node.on(cc.Node.EventType.ANCHOR_CHANGED, this._onNodeSizeDirty, this);

        this.node._renderFlag |= RenderFlow.FLAG_RENDER | RenderFlow.FLAG_UPDATE_RENDER_DATA | RenderFlow.FLAG_OPACITY_COLOR;
    }

然后是调用_checkBacth方法

代码语言:javascript
复制
    _checkBacth (renderer, cullingMask) {
        let material = this.sharedMaterials[0];
        if ((material && material.getHash() !== renderer.material.getHash()) || 
            renderer.cullingMask !== cullingMask) {
            renderer._flush();
    
            renderer.node = material.getDefine('CC_USE_MODEL') ? this.node : renderer._dummyNode;
            renderer.material = material;
            renderer.cullingMask = cullingMask;
        }
    }

该方法用于更新组件的材质,如果材质的hash发生变化,意味着材质更新了,就需要重新设置一些配置,即renderer._flush()

代码在core/renderer/webgl/model-batcher.js下面

代码语言:javascript
复制
    _flush () {
        let material = this.material,
            buffer = this._buffer,
            indiceCount = buffer.indiceOffset - buffer.indiceStart;
        if (!this.walking || !material || indiceCount <= 0) {
            return;
        }

        let effect = material.effect;
        if (!effect) return;
        
        // Generate ia
        let ia = this._iaPool.add();
        ia._vertexBuffer = buffer._vb;
        ia._indexBuffer = buffer._ib;
        ia._start = buffer.indiceStart;
        ia._count = indiceCount;
        
        // Generate model
        let model = this._modelPool.add();
        this._batchedModels.push(model);
        model.sortKey = this._sortKey++;
        model._cullingMask = this.cullingMask;
        model.setNode(this.node);
        model.setEffect(effect, this.customProperties);
        model.setInputAssembler(ia);
        
        this._renderScene.addModel(model);
        buffer.forwardIndiceStartToOffset();
    },

其中model.setEffect(effect, this.customProperties);这句代码进入

renderer/scene/model.js下面

代码语言:javascript
复制
  setEffect(effect, customProperties) {
    this._effect = effect;

    let defines = this._defines;
    let uniforms = this._uniforms;
    
    defines.length = 0;
    uniforms.length = 0;
    
    if (effect) {
      defines.push(effect._defines);
      uniforms.push(effect._properties);
    }

    if (customProperties) {
      defines.push(customProperties._defines);
      uniforms.push(customProperties._properties);
    }
  }

这里会将effect中的定义取出来

B--------------

_forward.render(_batcher._renderScene, dt);进入

在进入renderer/renderers/forward-renderer.js

代码语言:javascript
复制
  render (scene, dt) {
    this.reset();

    if (!CC_EDITOR) {
      this._time[0] += dt;
      this._device.setUniform('cc_time', this._time);
    }

    this._updateLights(scene);

    const canvas = this._device._gl.canvas;
    for (let i = 0; i < scene._cameras.length; ++i) {
      let view = this._requestView();
      let width = canvas.width;
      let height = canvas.height;
      let camera = scene._cameras.data[i];
      camera.extractView(view, width, height);
    }

    // render by cameras
    this._viewPools.sort((a, b) => {
      return (a._priority - b._priority);
    });

    for (let i = 0; i < this._viewPools.length; ++i) {
      let view = this._viewPools.data[i];
      this._render(view, scene);
    }
  }

然后进入renderer/core/base-renderer.js中的_render方法此处代码省略

进入后调用engine/cocos2d/core/renderer/render-flow.js 中的_drawItems然后是

engine/cocos2d/core/renderer/base-renderer.js 中的_draw

然后进入engine/cocos2d/core/renderer/gfx/device.js 中的draw

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-12-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档