0x1 总体介绍
Graphics中各种图形的渲染是通过许多小的三角形的渲染拼接组成的,Mesh的过程是把需要渲染的图形划分成许多小三角形的过程.
Escher中的mesh过程需要把Rectangle, Circle, Ring, Sphere等形状的显示对象划分成小三角形,然后把小三角形的数据通过Vulkan API来驱动GPU显示.
下图是escher中mesh相关类的类图
下面简单介绍一下这些类
Mesh创建过程中,
MeshBuilder根据MeshSpec的设置生成对应的Mesh.
Mesh的vertex/index数据保存到CommandBuffer中,
Mesh渲染过程中,
对应的PageRenderer生成对应的Object,每一个Object都有对应的Mesh,这些Object挂接到Model下面.
然后根据Model中包含的Mesh生成ModelDisplayList,然后遍历这个ModelDisplayList,把Mesh中的vertex/index数据传入CommandBuffer中,从而让GPU渲染的时候能够访问到这些数据.
0x2 各种shape的mesh过程
0x21 MeshBuilder介绍
MeshBuilder提供接口把vertex data和index data保存起来.
其中保存的数据结构如下,
vertex_stagingbuffer保存vertex数据,index_stagingbuffer保存index数据.
vertex_stagingbuffer和index_stagingbuffer的内存空间是通过GpuUploader::Writer来分配的.
|
|
下面是其提供设置vertex data和index data的接口.
注意下面的接口都返回 *this, 这是为了链式表达式的需要.
|
|
然后调用Build()接口生成mesh对象.
0x22 SimpleRectangle
下面是生成SimpleRectangle的mesh的代码,SimpleRectangle是普通的非圆角Rectangle.
从这个代码中可以看到,该mesh过程会生成4个vertex数据,生成6个index数据(因为是2个三角形).
|
|
前面的mesh过程计算好了一个通用的SimpleRectangle的mesh信息,
具体要显示Rectangle的时候根据具体的显示位置(top_left_position.x/y/z)和显示的大小(size.x/y)来绘制Rectangle.
指定显示的位置可以理解为平移,指定显示的大小可以理解为缩放.
这个平移/缩放过程通过设置transform矩阵来实现,在shader代码中把这个矩阵和通用SimpleRectangle的vertex坐标相乘.
transform矩阵的设置过程如下
|
|
0x23 Rectangle
下面的代码生成普通Rectangle的Mesh,
下面函数的参数中,
subdivisions指定Rectangle的拆分数,
size指定Rectangle的大小,
top_left指定左上角的坐标,
生成mesh的时候把Rectangle分成(subdivisions*2-1)个小矩形,指定这些小矩形的vertex/index设置.
这个普通Rectangle的mesh和SimpleRectangle的mesh不同之处在于普通Rectangle的mesh是每一个Rectangle生成一个,不具有SimpleRectangle的mesh的通用性. 另外普通Rectangle的mesh会包括更多的小三角形.
|
|
0x24 Circle
下面分析circle的mesh是如何生成的.
下面函数的参数中,
subdivisions指定Circle的拆分数目,
center指定Circle的中心点坐标.
radius指定Circle的半径大小.
生成mesh的时候是把Circle分成(subdivisions*4)个小扇形,然后计算这些小扇形的vertex/index设置.
|
|
前面的mesh过程计算好了一个通用的Circle的mesh信息,
和SimpleRectangle的情况类似,具体绘制Circle的时候根据具体的显示位置(center_position.x/y/z)和显示的大小(radius)来绘制Circle.
指定显示的位置可以理解为平移,指定显示的大小可以理解为缩放.
这个平移/缩放过程也是通过设置transform矩阵来实现,在shader代码中把这个矩阵和通用Circle的vertex坐标相乘.
|
|
0x25 RoundRectangle
下面分析生成圆角Rectangle的mesh的代码.
该过程把圆角矩形mesh成三角形,其中的顶点分布如下图所示,
其中每个圆角部分被拆分成8个小扇形.
0 ~ 12 顶点是中间部分的矩形对应的顶点.
13 ~ 19 顶点是左上角部分的圆角对应的顶点.
20 ~ 26 顶点是右上角部分的圆角对应的顶点.
27 ~ 33 顶点是右下角部分的圆角对应的顶点.
34 ~ 40 顶点是左下角部分的圆角对应的顶点.
NewRoundedRect是总的入口函数,其中会调用GenerateRoundedRectIndices()来根据顶点来构造三角形,调用GenerateRoundedRectVertexUVs()生成纹理坐标,最后调用GenerateRoundedRectVertexPositionsFromUVs()来生成顶点坐标.
|
|
下面的代码是构造圆角Rectangle中的三角形的过程,indices中保存的是把这些顶点拼接成三角形的顶点索引.
|
|
下面函数计算这些点(0 ~ 40)对应的纹理(uv)坐标.
|
|
下面函数计算这些点(0 ~ 40)对应的顶点坐标,根据对应的纹理坐标来计算得到.
|
|
0x26 Sphere
下面是构造Sphere的mesh的代码.
|
|
0x27 Ring
下面分析Ring的mesh是如何生成的, Ring是由内圈和外圈包含的区域组成, 内圈区域内是透明的, 实际上Ring的mesh没有包括内圈,也就是说渲染的时候不会去绘制内圈区域, 所以mesh生成的绘制区域只需要包括内圈和外圈组成的区域,mesh的过程也就是把内圈和外圈之间的区域拆分成许多小三角形.
下面函数的参数中,
subdivisions指定Ring的拆分数.
center指定Circle的中心点坐标.
outer_radius指定Ring的外圈半径.
inner_radius指定Ring的内圈半径.
生成mesh的时候把Ring分成(subdivisions*4)个小扇形,这些小扇形会和Ring的内圈和外圈相交,
指定相交点的vertex值,然后把这些vertex组成的triangle,vertex的index值指定给mesh的index.
|
|