creator源码阅读系列之第三篇

简介: creator源码阅读系列之第三篇

creator源码阅读系列之第一篇源码总览


creator源码阅读系列之第二篇渲染


今天我们继续上一篇讲渲染源码


四. 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

相关文章
|
6月前
CocosCreator 面试题(十六)Cocos Creator 节点池的基本原理是什么?如何使用?
CocosCreator 面试题(十六)Cocos Creator 节点池的基本原理是什么?如何使用?
398 0
|
4月前
|
设计模式 Java 测试技术
《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
【7月更文挑战第12天】在本文中,作者宏哥介绍了如何在不使用PageFactory的情况下,用Java和Selenium实现Page Object Model (POM)。文章通过一个百度首页登录的实战例子来说明。首先,创建了一个名为`BaiduHomePage1`的页面对象类,其中包含了页面元素的定位和相关操作方法。接着,创建了测试类`TestWithPOM1`,在测试类中初始化WebDriver,设置驱动路径,最大化窗口,并调用页面对象类的方法进行登录操作。这样,测试脚本保持简洁,遵循了POM模式的高可读性和可维护性原则。
46 2
|
图形学 索引 内存技术
creator源码阅读系列之第三篇(2)
creator源码阅读系列之第三篇
115 0
|
Web App开发 设计模式 JavaScript
creator源码阅读系列之第一篇源码总览
creator源码阅读系列之第一篇源码总览
|
异构计算 索引 容器
creator源码阅读系列第二篇之渲染
creator源码阅读系列第二篇之渲染
155 0
|
Java Shell 开发工具
Spring源码阅读 之 搭建源码阅读环境(IDEA)
Spring源码阅读 之 搭建源码阅读环境(IDEA)
154 0
Spring源码阅读 之 搭建源码阅读环境(IDEA)
|
SQL 算法 中间件
sqlalchemy源码阅读-下篇
SQLAlchemy是Python SQL工具箱和ORM框架,它为应用程序开发人员提供了全面而灵活的SQL功能。它提供了一整套企业级持久化方案,旨在高效,高性能地访问数据库,并符合Pythonic之禅。项目代码量比较大,接近200个文件,7万行代码, 我们一起来挑战一下。
423 1
sqlalchemy源码阅读-下篇
|
SQL 安全 关系型数据库
SQLAlchemy源码阅读-上篇
SQLAlchemy是Python SQL工具箱和ORM框架,它为应用程序开发人员提供了全面而灵活的SQL功能。它提供了一整套企业级持久化方案,旨在高效,高性能地访问数据库,并符合简单的Pythonic哲学。项目代码量比较大,接近200个文件,7万行代码, 我们一起来挑战一下。 作者:游戏不存在 链接:https://juejin.cn/post/6951945198322581518 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
316 2
SQLAlchemy源码阅读-上篇
|
存储 缓存 JSON
tinydb 源码阅读
TinyDB是一个小型,简单易用,面向文档的数据库;代码仅1800行,纯python编写。TinyDB项目大小刚好,学习它可以了解NOSQL数据库的实现。
435 0
tinydb 源码阅读
|
IDE 测试技术 API
聊聊我的源码阅读方法
本次代码阅读的项目来自 500lines 的子项目 web-server。 500 Lines or Less不仅是一个项目,也是一本同名书,有源码,也有文字介绍。这个项目由多个独立的章节组成,每个章节由领域大牛试图用 500 行或者更少(500 or less)的代码,让读者了解一个功能或需求的简单实现。
160 0
聊聊我的源码阅读方法