cocos creator 2.4.0 渲染流程详解(四:Assembler )

全文共5000+字,分为8个章节,由本人历时一周整理而来。由于篇幅问题,将本文分为8个章节分开发布。全文 () 详细描述了cocoscreator 引擎的2.40版本中,web平台的js部分引擎的渲染流程。请将文章配合源码一起食用!

​由于我尚在学习引擎源码中,文章可能有不正确的部分,所以我会不断更新内容。如有错误或补充,请留言交流!


全部章节链接:

一:渲染流程中用到的核心类

二 : 渲染流程详解

三: RenderFlow 的运行逻辑

四: Assembler 的作用

五: ModelBatcher 数据合批

六: 材质系统

七: ForwardRender


四 Assembler 的作用

Assembler 由 RenderComponent 持有,并根据 component 的类型不同,持有不同的 Assembler 的子类,用以处理不同的顶点数据。可以先从最简单的普通2d图片的 SimpleSpriteAssembler 入手了解,了解了基础的内容,再看其他较为复杂的assembler,可以循序渐进。

4.1 RenderData 与 顶点数据格式

为了了解 Assembler的工作机制,需要首先了解下顶点数据的格式。Assembler中处理的顶点数据保存在 _renderData 中,所以了解 RenderData 的类型很重要。RenderData 的创建需要顶点数据的格式,顶点格式描述了单个数据体的组成结构。常用的顶点格式是 vfmtPosUvColor ,是 Assembler2D 默认使用的格式。代码定义如下。

var vfmtPosUvColor = new gfx.VertexFormat([ 
    // 节点的世界坐标,占2个float32 
    { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }, 
    // 节点的纹理uv坐标,占2个float32
     { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 }, 
    // 节点颜色值,占4个uint8 = 1个float32
     { name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true }, 
]);

在shader中的attribute变量定义如下,可以很容易找到与顶点格式的对应关系。

CCProgram vs %{ 
precision highp float; 
#include <cc-global> 
#include <cc-local> 
  // 对应vfmtPosUvColor结构里的3个字段 
  // 注意这里a_position是vec3类型,但是vfmtPosUvColor对其自定义了2个float长度。 
  // 所以a_position.z = 0 
  in vec3 a_position; // gfx.ATTR_POSITION 
  in vec2 a_uv0; // gfx.ATTR_UV0 
  in vec4 a_color; // gfx.ATTR_COLOR 
  void main () {   // ...   }
}%

再看下 Assembler2D 中定义的数据与顶点格式的关系。

cc.js.addon(Assembler2D.prototype, { 
// vfmtPosUvColor 中,单个数据节点占5个float32,为2+2+1. 
floatsPerVert: 5, 
// 顶点数量:一个四边形4个顶点 
verticesCount: 4, 
// 顶点索引数量:一个四边形按照对角拆分成2个三角形,2*3 = 6个顶点索引 
indicesCount: 6, 
// uv值的索引偏移量:位置坐标占2个float,所以uv的值的下标从2开始算 
uvOffset: 2, 
// color值的索引偏移量:位置2个float,uv2个float,color的值的下标从4开始算 
colorOffset: 4, 
});

顶点数据的结构具象化表示出来如图:

顶点数据的结构

了解到顶点数据的格式后,更新数据时需要将各种数据填入对应的位置就可以了。

updateVerts 方法: 更新顶点数据,填充 pos.x 和 pos.y。

updateUVs 方法: 更新uv数据,填充 uv.x 和 uv.y。

updateColor 方法: 更新颜色数据,填充color。

4.2 updateVerts 更新顶点数据

在 SimpleSpriteAssembler 的 udpateVerts 方法里,会计算出纹理中上下左右四个边距距离中心的距离,数据长度为4个。

在 SlicedAssembler 的 udpateVerts 方法里,会计算出纹理中上下左右四个边距离距离中心的长度,加上九宫格需要的可拉伸的上下左右的四个长度,数据长度为8个。

其他的Assembler也一样。。。

具体计算时,会涉及到纹理的尺寸与偏移量,节点的大小和缩放量。计算过程可以看各个assembler 中的 udpateVerts 的方法实现。

4.3 updateUVs 更新uv数据

updateUVs (sprite) {  
 let uv = sprite._spriteFrame.uv;  
 let uvOffset = this.uvOffset;      
 let floatsPerVert = this.floatsPerVert;      
 let verts = this._renderData.vDatas[0];        
 for (let i = 0; i < 4; i++) {         
        let srcOffset = i * 2;        
        let dstOffset = floatsPerVert * i + uvOffset;   
        verts[dstOffset] = uv[srcOffset];        
        verts[dstOffset + 1] = uv[srcOffset + 1];    
    }    
}

源码位于 cocos2d\core\renderer\webgl\assemblers\sprite\2d\simple.js 。主要内容是将 cc.SpriteFrame 里的 uv 数据复制到 RenderData.vDatas 里。每张图片4个顶点,每个顶点2个float值(x, y)。

可以看到 SimpleSpriteAssembler 的 updateUvs 方法只是将图片的 uv 未经处理,全部保存下来。如果是未合图的图片,那么获取的uv值就是[0, 1, 1, 1, 0, 0, 1, 0], 代表左上,右上,左下,右下4个顶点。所以图片渲染出来会是完整的原图。那么如果我们想要自定义渲染图片的一部分,就可以在该方法内自定义了。如何自定义可以参考 SlicedAssembler 九宫格填充,TiledAssembler 平铺填充等其他的图片填充格式。

4.4 updateColor 更新颜色数据

updateColor (comp, color) {         
  let uintVerts = this._renderData.uintVDatas[0];         
  if (!uintVerts) return;         
  color = color != null ? color : comp.node.color._val;         
  let floatsPerVert = this.floatsPerVert;         
  let colorOffset = this.colorOffset;         
  for (let i = colorOffset, l = uintVerts.length; i < l; i += floatsPerVert) {             
    uintVerts[i] = color;         
  }     
}

代码位于 cocos2d\core\renderer\assembler-2d.js。将 cc.Node 的 color 属性的值填充到 RenderData.uintVDatas 中。

Tips:RenderData 的 uintVDatas 和 vDatas 指向同一片缓存区域,只是2个代表不同的数据视图,uinitVDatas 以 uinit8 为单元访问,vDatas 以 float32 为单元访问。

4.5 顶点索引数据

上面主要描述了 RenderData 里的 vDatas 的定义格式和填充方式,而 renderData.iDatas 代表的顶点索引数据也需要填入数据。

为什么需要顶点索引数据?因为GPU渲染需要的数据其实是一个个三角形的元片,所以单张矩形图片,需要被切割成2个三角形,这样的话关于顶点的数据数量,就变成了6个。为了减少数据冗余,每个顶点的数据只有一份,但是每个三角形的顶点可以用对应的索引来获取。

顶点索引规则
initQuadIndices(indices) { 
// 6个一组(对应1个四边形)生成索引数据 
let count = indices.length / 6; 
for (let i = 0, idx = 0; i < count; i++) {
    let vertextID = i * 4; 
    indices[idx++] = vertextID; 
    indices[idx++] = vertextID+1; 
    indices[idx++] = vertextID+2; 
    indices[idx++] = vertextID+1; 
    indices[idx++] = vertextID+3;
    indices[idx++] = vertextID+2;
  }
}

源码位于 cocos2d\core\renderer\webgl\render-data.js 。

相关链接

  1. 自定义渲染https://docs.cocos.com/creator/manual/zh/advanced-topics/custom-render.html#%E8%87%AA%E5%AE%9A%E4%B9%89-assembler

  2. RenderFlow的性能优化http://docs.cocos.com/creator/manual/zh/advanced-topics/render-flow.html#

  3. 自定义渲染合批之自定义顶点格式https://forum.cocos.org/t/demo/95087

  4. 自定义RenderFlow,处理背包等场景下drawcall过多:https://forum.cocos.org/t/ui/80026

  5. 材质系统https://docs.cocos.com/creator3d/manual/zh/material-system/overview.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,561评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,218评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,162评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,470评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,550评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,806评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,951评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,712评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,166评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,510评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,643评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,306评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,930评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,745评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,983评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,351评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,509评论 2 348

推荐阅读更多精彩内容