ThreeJS:几何体相关(BufferGeometry)

使用 BufferGeometry 可以有效减少向 GPU 传输几何体相关数据所需的开销
可以自定义顶点位置, 面片索引, 法向量, 颜色值
ThreeJS:几何体相关(BufferGeometry)文章插图
作者:随遇丿而安
出处:
1. BufferGeometry使用初体验在之前的学习中, 我是已经了解到建立一个3d场景, 不知道屏幕前的你是否有了解到, threejs需要做的有, 第一: 渲染器renderer; 第二: 场景Scene; 第三, 光源Light; 第四, 物质有点线面三个部分.
在实际的开发过程中, 自己创建几何体这种情况很少见, 大部分情况是载入已有的模型, 对模型进行操作, 导入的模型可能很大, 这个时候就需要优化, 优化可以从几何体入手, 也可以从材质入手, 但是优化主要针对的就是几何体, 占内存的也是几何体而不是材质, 因此了解几何体是非常有必要的, 几何体英文( geometry ).
对于Threejs, 官方说明, 使用buffergeometry能够有效减少向GPU传输几何体相关数据所需要的开销, 同时, 用户可以自定义集合体的顶点位置, 名片索引, 法向量, 颜色值
下面创建一个简单的buffergeometry吧
// 顶点个数var particles = 500000;var geometry = new THREE.BufferGeometry();// 每个顶点位置let positions = [];// 颜色值var colors = [];// 临时颜色类型var color = new THREE.Color();var n = 1000, n2 = n / 2; for ( var i = 0; i < particles; i ++ ) { // positions, 形成一个长方体, x, y, z的范围都是从-500到500, 形成的长方体的长宽高都为500 var x = Math.random() * n - n2; var y = Math.random() * n - n2; var z = Math.random() * n - n2; positions.push( x, y, z ); // colors, 设置颜色, 同理, 从0到1 var vx = ( x / n ) + 0.5; var vy = ( y / n ) + 0.5; var vz = ( z / n ) + 0.5; color.setRGB( vx, vy, vz ); colors.push( color.r, color.g, color.b );}// 设置位置信息geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );// 设置颜色信息geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );// 计算边界球体geometry.computeBoundingSphere();// 创建物资var material = new THREE.PointsMaterial( { size: 15, vertexColors: true } );// 创建点云points = new THREE.Points( geometry, material );scene.add( points );效果如下图所示
ThreeJS:几何体相关(BufferGeometry)文章插图
下面对代码进行简单的分析, 并进行汇总
代码主要分为三步

  1. 创建所有点的位置数组, 每三个值形成x, y, z确定三维世界点的坐标对应positions = [],positions.push()
  2. 创建所有点的颜色数组, 每三个值形成r, g, b确定三维世界点的颜色colors = []colors.push()
  3. 将位置数组和颜色数组导入到集合体中geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
根据代码, 将建好的点云加入场景中, 就有效果了, 完整代码附在文章末尾处
2. 简单压缩几何体的方法threejs给我们提供了一些可以直接引用的方法降低GPU渲染几何体的开销, 这里展示官方给的3种类型的代码
里面第一行代码是用于计算mesh在GPU中所占内存
// 计算这个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' );3. 创建由点到线的几何体var geometry = new THREE.BufferGeometry();var material = new THREE.LineBasicMaterial( { vertexColors: true, morphTargets: true } );var positions = [];var colors = [];for ( var i = 0; i < segments; i ++ ) { var x = Math.random() * r - r / 2; var y = Math.random() * r - r / 2; var z = Math.random() * r - r / 2; // positions positions.push( x, y, z ); // colors colors.push( ( x / r ) + 0.5 ); colors.push( ( y / r ) + 0.5 ); colors.push( ( z / r ) + 0.5 );}geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );geometry.computeBoundingSphere();line = new THREE.Line( geometry, material );scene.add( line );效果图如下
ThreeJS:几何体相关(BufferGeometry)文章插图
是不是觉得这个代码与第一章节的代码十分类似呢, 实际上就是完全一样的代码
不同点在于
  1. 线几何体的 material 是THREE.LineBasicMaterial
  2. 创建线几何体mesh使用的是 THREE.Line, 而点云使用的是THREE.Points