Better

Ethan的博客,欢迎访问交流

Geometry and BufferGeometry in Three.js

近期对前端依赖进行更新,Three.js 在 r125 版本中最终决定废弃了 Geometry,从而导致代码需要同步进行修改,了解下两者的区别和各自优劣势吧。顺便了解下 obj 文件内容格式,因为和 BufferGeometry 很像。

Geometry VS BufferGeometry

Geometry

  • 本意是对 BufferGeometry 的用户友好替代
    • 利用 Vector3 或 Color 存储了几何体相关的 attributes
    • 比 BufferGeometry 更容易读写,但运行效率不如有类型的队列
  • colors:顶点 colors 队列,与顶点数量和顺序保持一致
  • faces:faces 队列,描述每个顶点之间如何组成模型面的面队列
  • faceVertexUvs:面的 UV 层的队列,该队列用于将纹理和几何信息进行映射
  • vertices:顶点的队列,保存了模型中每个顶点的位置信息

BufferGeometry

  • 顶点信息 attributes.position:存储每个顶点的坐标
  • 法向量信息 attributes.normal:参与光照计算,存储每个顶点的法向量
  • 颜色信息 attributes.color:存储每个点的颜色值
  • 纹理坐标 attributes.uv:贴图
  • 面片索引 index:允许顶点在多个三角面片见可以重用

面几何体

面几何体需要法向量信息,已知三个点, 求出两条边的方向向量, 这两个方向向量做叉乘, 结果变为由三个点构成的三角形的法向量

 // 求法向量, 首先设置三角形的三个顶点
 pA.set( ax, ay, az );
 pB.set( bx, by, bz );
 pC.set( cx, cy, cz );
 // 求出两个方向向量
 cb.subVectors( pC, pB );
 ab.subVectors( pA, pB );
 // 叉积, 求法向量
 cb.cross( ab );
 // 单位化这个法向量
 cb.normalize();

 var nx = cb.x;
 var ny = cb.y;
 var nz = cb.z;

 // 添加法向量到法向量数组中
 // 三角形的三个顶点的法向量相同, 因此复制三份
 normals.push( nx, ny, nz );
 normals.push( nx, ny, nz );
 normals.push( nx, ny, nz );

工具函数

工具函数

// 计算这个 mesh 在 gpu 中所占内存
BufferGeometryUtils.estimateBytesUsed(mesh.geometry) + " bytes"

// 使用 DefaultUVEncoding 降低内存数
GeometryCompressionUtils.compressUvs(mesh);

// 使用 QuantizePosEncoding 降低内存数
GeometryCompressionUtils.compressPositions(mesh);

// 使用 NormEncodingMethods 降低内存数
// ["None", "DEFAULT", "OCT1Byte", "OCT2Byte", "ANGLES"]
GeometryCompressionUtils.compressNormals(mesh, 'None');

obj 文件

obj 文件内容如下

  • v:表示顶点,即组成图的点
  • vt:纹理坐标,其值为 u、v、w
  • vn:顶点法向量,其值为 x、y、z,这个法向量表示顶点的朝向。比如由三个顶点组成一个面,面由两个朝向,向里或向外,可以通过顶点的朝向来确定面的朝向。而且这三个顶点的法向量是一样的
  • f:表示一个面,由三个 v/vt/vn 的索引形式组成。比如 obj 文件中 f 5/15/7 4/14/6 6/16/8 ,表示由第 5、第 4、第 6 这三个顶点组成了一个三角平面,平面的纹理由第 15、第 14、第 16 这三个纹理坐标形成,这个平面的朝向是第 7、第 6、第 8 这三个顶点的法向量求平均值

补充说明

  • 顶点的个数与顶点法向量的个数一样多。
  • 顶点的个数不一定与纹理坐标的个数一样多,因为有可能很多顶点公用一个纹理坐标的像素。
  • 面索引的个数也与其余数据数量无关。
  • 最终每个三角面的颜色,是由构成这个三角面的三个顶点进行插值计算


留言