使用BufferGeometry

  • 1. 序言
  • 2. 如何使用BufferGeometry
    • 2.1 创建BufferGeometry对象
    • 2.2 向BufferGeometry对象添加属性
    • 2.3 创建Mesh
  • 3. BufferGeometry使用示例
    • 3.1 绘制点
    • 3.2 绘制线
    • 3.3 绘制面
    • 3.4 绘制自定义UV贴图
  • 4. 示例代码

1. 序言

three.js 中提供了一系列绘制几何体的类,如BoxGeometry、SphereGeometry,PlaneGeometry、CircleGeometry、CylinderGeometry 等,使用这些类,可以快速创建对应的几何体,three.js同时提供了对应的 BoxBufferGeometry、SphereBufferGeometry,PlaneBufferGeometry、CircleBufferGeometry、CylinderBufferGeometry等直接使用缓存的构建几何体的 xxxBufferGeometry 类簇,这些类簇相比于 xxxGeometry 类簇,可以有效减少向 GPU 传输数据所需的开销,极大提高效率,但如果提供的这些几何都不能满足需求怎么办,这时就需要用到万能的 BufferGeometry ,通过它可以向缓存中传输几何体的顶点坐标、面索引、顶点颜色、顶点法向量、顶点UV甚至是自定义属性, 使用自定义属性和着色器材质配合使用强大到无所不能

这里顺便说说ShaderMaterial-着色器材质和RawShaderMaterial-原始着色器材质,它们都支持GLSL语言编写的shader,不同之处是ShaderMaterial会把three.js内置attributes和uniforms一起传给shader,而RawShaderMaterial 不会 向shader中传递任何内置属性

2. 如何使用BufferGeometry

2.1 创建BufferGeometry对象

创建BufferGeometry对象与创建其他THREE对象一样,非常简单,如下

const bufferGeom = new THREE.BufferGeometry();

2.2 向BufferGeometry对象添加属性

这一步其实就是初始化绘制几何体所需的顶点坐标、面索引、顶点颜色、顶点法向量、顶点UV等信息,这些属性three.js都是内置属性,属性名已定死,例如:position,color,normal,index等

这一步可向BufferGeometry对象添加任意属性,我们以position属性和index为例说明一下

  • 添加position属性
    首先通过Float32Array类创建序列化数组,示例中是每3个数构成一个点,然后使用BufferAttribute类创建于BufferGeometry对象关联的存储缓存,最后使用setAttribute方法关联缓存,示例代码如下
//初始化存放顶点信息的序列化数组
const positions = new Float32Array([-5.0, 3.0, 0.0, //point05.0, 3.0, 0.0, //point16.0, -3.0, 0.0, //point2-6.0, -3.0, 0.0 //point3
]);//设置顶点信息,第二个参数3表示三个数确定一个顶点
bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));

其他一些相关的属性color,normal等以及自定义属性的添加都可以参数以上方式

  • 添加index属性
    index 属性与其他属性添加有一些不一样,序列化数组的类型是Uint16Array,不是通过setAttribute设置属性,而是直接设置到BufferGeometry实例的index属性下,使用BufferAttribute创建缓存数据是第二个参数为1,代表一个数就是一个索引信息
const indexs = new Uint16Array([0, 1, 2,3, 0
]);//设置画面的索引
bufferGeom.index = new THREE.BufferAttribute(indexs, 1);

2.3 创建Mesh

创建mesh需要两个参数一个几何体一个材质,几何体通过上述两步创建,创建材质时,如果设置的顶点颜色属性,且需要使用自定义的也是着色,要将材质的vertexColors属性设置为 THREE.VertexColors。表示使用缓存中的颜色着色

 //创建材质const material = new THREE.MeshBasicMaterial({vertexColors: THREE.VertexColors, //使用缓存中的颜色side: THREE.DoubleSide});const mesh = new THREE.Mesh(bufferGeom, material);

3. BufferGeometry使用示例

3.1 绘制点

首先创建BufferGeometry实例,然后创建存放顶信息的序列化数组,接着设置position属性,最后创建PointsMaterial材质并使用该材质创建Points对象,就可以完成点的绘制

function drawPointByBufferGeometry() {//创建BufferGeometry实例const bufferGeom = new THREE.BufferGeometry();//初始化存放顶点信息的序列化数组const positions = new Float32Array([-5.0, 3.0, 0.0, //point05.0, 3.0, 0.0, //point16.0, -3.0, 0.0, //point2-6.0, -3.0, 0.0 //point3]);//设置顶点信息bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));//创建点材质const material = new THREE.PointsMaterial({color: 'red',size: 2});const mesh = new THREE.Points(bufferGeom, material);scene.add(mesh);
}

绘制效果如下:

3.2 绘制线

  • 创建BufferGeometry实例
    使用 new THREE.BufferGeometry() 创建bufferGeom实例
  • 设置position,color,index属性
    position,color属性设置与之前的一样,请注意设置index属性时,index序列化数组的值为0, 1, 2, 3, 0 最终还要回到原点否则最后一条线无法绘制
  • 创建Mesh
    这里使用LineBasicMaterial创建材质,同样将材质的vertexColors属性设置为 THREE.VertexColors。表示使用缓存中的颜色着色,并使用Line创建线
function drawLineByBufferGeometry() {//创建BufferGeometry实例const bufferGeom = new THREE.BufferGeometry();//初始化存放顶点信息的序列化数组const positions = new Float32Array([-5.0, 3.0, 0.0, //point05.0, 3.0, 0.0, //point16.0, -3.0, 0.0, //point2-6.0, -3.0, 0.0 //point3]);//设置顶点信息bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));//初始化存放颜色信息的序列化数组const colors = new Float32Array([1.0, 0.0, 0.0,0.0, 1.0, 0.0,0.0, 0.0, 1.0,0.0, 0.5, 0.5]);//设置颜色信息bufferGeom.setAttribute('color', new THREE.BufferAttribute(colors, 3));const indexs = new Uint16Array([0, 1, 2,3, 0]);//设置画面的索引bufferGeom.index = new THREE.BufferAttribute(indexs, 1);//创建材质const material = new THREE.LineBasicMaterial({vertexColors: THREE.VertexColors, //使用缓存中的颜色side: THREE.DoubleSide});const mesh = new THREE.Line(bufferGeom, material);scene.add(mesh);
}


绘制的结果如上如,会发现绘制的线和使用WebGL绘制线一样。会根据顶点颜色作插值计算

3.3 绘制面

  • 创建BufferGeometry实例
    使用 new THREE.BufferGeometry() 创建bufferGeom实例
  • 设置position,color,index属性
    position,color属性设置与之前的一样,需要注意的是设置index属性时,index序列化数组的值为0, 1, 2, 0, 2, 3 表示使用索引为0,1,2的点绘制一个三角面和使用索引为0,2,3的点绘制另一个三角面
  • 创建Mesh
    使用MeshBasicMaterial创建材质,也需要将材质的vertexColors属性设置为 THREE.VertexColors。表示使用缓存中的颜色着色,然后创建Mesh对象
function drawPlaneByBufferGeometry() {//创建BufferGeometry实例const bufferGeom = new THREE.BufferGeometry();//初始化存放顶点信息的序列化数组const positions = new Float32Array([-5.0, 3.0, 0.0, //point05.0, 3.0, 0.0, //point16.0, -3.0, 0.0, //point2-6.0, -3.0, 0.0 //point3]);//设置顶点信息bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));//初始化存放颜色信息的序列化数组const colors = new Float32Array([1.0, 0.0, 0.0,0.0, 1.0, 0.0,0.0, 0.0, 1.0,0.0, 0.5, 0.5]);//设置颜色信息bufferGeom.setAttribute('color', new THREE.BufferAttribute(colors, 3));const indexs = new Uint16Array([0, 1, 2,0, 2, 3]);//设置画面的索引bufferGeom.index = new THREE.BufferAttribute(indexs, 1);//创建材质const material = new THREE.MeshBasicMaterial({vertexColors: THREE.VertexColors, //使用缓存中的颜色side: THREE.DoubleSide});const mesh = new THREE.Mesh(bufferGeom, material);scene.add(mesh);
}


绘制结果如上图,绘制了一个梯形,颜色同样根据顶点颜色进行了线性插值

3.4 绘制自定义UV贴图

其他的步骤与绘制面一样,不同的是需要添加uv属性,添加uv属性前先来捋一下uv坐标与顶点坐标的关系

上图是uv坐标与梯形顶点坐标的关系图,只需要按这个顺添加uv属性即可,需要注意的数uv坐标是一个Vector2类型,设置的时候需要注意,创建BufferAttribute时第二个参数为2,具体实现代码如下:

function drawPlaneByBufferGeometryUV() {//创建BufferGeometry实例const bufferGeom = new THREE.BufferGeometry();//初始化存放顶点信息的序列化数组const positions = new Float32Array([-5.0, 3.0, 0.0, //point05.0, 3.0, 0.0, //point16.0, -3.0, 0.0, //point2-6.0, -3.0, 0.0, //point3]);//设置顶点信息bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));//初始化存放颜色信息的序列化数组const colors = new Float32Array([0.5, 0.3, 0.6,0.5, 0.3, 0.6,0.5, 0.3, 0.6,0.5, 0.3, 0.6,]);//设置颜色信息bufferGeom.setAttribute('color', new THREE.BufferAttribute(colors, 3));const indexs = new Uint16Array([0, 1, 2,0, 2, 3,4, 5, 6,4, 6, 7]);//设置画面的索引bufferGeom.index = new THREE.BufferAttribute(indexs, 1);const uvs = new Uint16Array([0, 1,1, 1,1, 0,0, 0,]);//设置UVbufferGeom.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));const planetTexture = new THREE.TextureLoader().load("../assets/textures/test.png");//创建材质const material = new THREE.MeshBasicMaterial({map: planetTexture,vertexColors: THREE.VertexColors, //使用缓存中的颜色side: THREE.DoubleSide});const mesh = new THREE.Mesh(bufferGeom, material);scene.add(mesh);
}


上图为代码执行结果,可以看到狗狗贴图被正确加载到梯形上了

4. 示例代码

<!DOCTYPE html><html><head><title>使用BufferGeometry</title><script type="text/javascript" src="../three/build/three.js"></script><script type="text/javascript" src="../three/examples/js/controls/OrbitControls.js"></script><script type="text/javascript" src="../three/examples/js/libs/stats.min.js"></script><style>body {margin: 0;overflow: hidden;}</style>
</head><body><div id="Stats-output"></div><div id="WebGL-output"></div><script type="text/javascript">var scene, camera, renderer, arrowLineTexture, flowingLineTexture, stats, controls, clock;function initScene() {scene = new THREE.Scene();//用一张图加载为纹理作为场景背景scene.background = new THREE.TextureLoader().load("../assets/textures/starry-deep-outer-space-galaxy.jpg");}function initCamera() {camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);camera.position.set(20, 30, 50);camera.lookAt(new THREE.Vector3(0, 0, 0));}function initLight() {//添加环境光const ambientLight = new THREE.AmbientLight(0x0c0c0c);scene.add(ambientLight);const directionalLight = new THREE.DirectionalLight('#fff')directionalLight.position.set(30, 30, 30).normalize()scene.add(directionalLight)//添加聚光灯const spotLight = new THREE.SpotLight(0xffffff);spotLight.position.set(-40, 60, -10);spotLight.castShadow = true;scene.add(spotLight);}function initModel() {//drawPointByBufferGeometry();//drawLineByBufferGeometry();//drawPlaneByBufferGeometry();drawPlaneByBufferGeometryUV();initPlane();}function drawPlaneByBufferGeometryUV() {//创建BufferGeometry实例const bufferGeom = new THREE.BufferGeometry();//初始化存放顶点信息的序列化数组const positions = new Float32Array([-5.0, 3.0, 0.0, //point05.0, 3.0, 0.0, //point16.0, -3.0, 0.0, //point2-6.0, -3.0, 0.0, //point3]);//设置顶点信息bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));//初始化存放颜色信息的序列化数组const colors = new Float32Array([0.5, 0.3, 0.6,0.5, 0.3, 0.6,0.5, 0.3, 0.6,0.5, 0.3, 0.6,]);//设置颜色信息bufferGeom.setAttribute('color', new THREE.BufferAttribute(colors, 3));const indexs = new Uint16Array([0, 1, 2,0, 2, 3,4, 5, 6,4, 6, 7]);//设置画面的索引bufferGeom.index = new THREE.BufferAttribute(indexs, 1);const uvs = new Uint16Array([0, 1,1, 1,1, 0,0, 0,]);//设置UVbufferGeom.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));const planetTexture = new THREE.TextureLoader().load("../assets/textures/test.png");//创建材质const material = new THREE.MeshBasicMaterial({map: planetTexture,vertexColors: THREE.VertexColors, //使用缓存中的颜色side: THREE.DoubleSide});const mesh = new THREE.Mesh(bufferGeom, material);scene.add(mesh);}function drawPointByBufferGeometry() {//创建BufferGeometry实例const bufferGeom = new THREE.BufferGeometry();//初始化存放顶点信息的序列化数组const positions = new Float32Array([-5.0, 3.0, 0.0, //point05.0, 3.0, 0.0, //point16.0, -3.0, 0.0, //point2-6.0, -3.0, 0.0 //point3]);//设置顶点信息bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));//创建点材质const material = new THREE.PointsMaterial({color: 'red',size: 2});const mesh = new THREE.Points(bufferGeom, material);scene.add(mesh);}function drawLineByBufferGeometry() {//创建BufferGeometry实例const bufferGeom = new THREE.BufferGeometry();//初始化存放顶点信息的序列化数组const positions = new Float32Array([-5.0, 3.0, 0.0, //point05.0, 3.0, 0.0, //point16.0, -3.0, 0.0, //point2-6.0, -3.0, 0.0 //point3]);//设置顶点信息bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));//初始化存放颜色信息的序列化数组const colors = new Float32Array([1.0, 0.0, 0.0,0.0, 1.0, 0.0,0.0, 0.0, 1.0,0.0, 0.5, 0.5]);//设置颜色信息bufferGeom.setAttribute('color', new THREE.BufferAttribute(colors, 3));const indexs = new Uint16Array([0, 1, 2,3, 0]);//设置画面的索引bufferGeom.index = new THREE.BufferAttribute(indexs, 1);//创建材质const material = new THREE.LineBasicMaterial({vertexColors: THREE.VertexColors, //使用缓存中的颜色side: THREE.DoubleSide});const mesh = new THREE.Line(bufferGeom, material);scene.add(mesh);}function drawPlaneByBufferGeometry() {//创建BufferGeometry实例const bufferGeom = new THREE.BufferGeometry();//初始化存放顶点信息的序列化数组const positions = new Float32Array([-5.0, 3.0, 0.0, //point05.0, 3.0, 0.0, //point16.0, -3.0, 0.0, //point2-6.0, -3.0, 0.0 //point3]);//设置顶点信息bufferGeom.setAttribute('position', new THREE.BufferAttribute(positions, 3));//初始化存放颜色信息的序列化数组const colors = new Float32Array([1.0, 0.0, 0.0,0.0, 1.0, 0.0,0.0, 0.0, 1.0,0.0, 0.5, 0.5]);//设置颜色信息bufferGeom.setAttribute('color', new THREE.BufferAttribute(colors, 3));const indexs = new Uint16Array([0, 1, 2,0, 2, 3]);//设置画面的索引bufferGeom.index = new THREE.BufferAttribute(indexs, 1);//创建材质const material = new THREE.MeshBasicMaterial({vertexColors: THREE.VertexColors, //使用缓存中的颜色side: THREE.DoubleSide});const mesh = new THREE.Mesh(bufferGeom, material);scene.add(mesh);}//创建底面function initPlane() {const planeGeometry = new THREE.PlaneGeometry(50, 50, 1, 1); //创建一个平面几何对象//材质const planeMaterial = new THREE.MeshLambertMaterial({color: 0x080631,transparent: true,opacity: 0.8});const plane = new THREE.Mesh(planeGeometry, planeMaterial);//设置平面位置plane.rotation.x = -0.5 * Math.PI;plane.position.set(0, -4, 0);//平面添加到场景中scene.add(plane);}//初始化渲染器function initRender() {renderer = new THREE.WebGLRenderer({antialias: true,alpha: true});renderer.setClearColor(0x111111, 1); //设置背景颜色renderer.setSize(window.innerWidth, window.innerHeight);//renderer.shadowMap.enabled = true; //显示阴影document.getElementById("WebGL-output").appendChild(renderer.domElement);}//初始化轨道控制器function initControls() {clock = new THREE.Clock(); //创建THREE.Clock对象,用于计算上次调用经过的时间controls = new THREE.OrbitControls(camera, renderer.domElement);//controls.autoRotate = true; //是否自动旋转}//性能监控function initStats() {stats = new Stats();stats.setMode(0); //0: fps, 1: msdocument.getElementById("Stats-output").appendChild(stats.domElement);}function render() {const delta = clock.getDelta(); //获取自上次调用的时间差controls.update(delta); //控制器更新stats.update();requestAnimationFrame(render);renderer.render(scene, camera);}//页面初始化function init() {initScene();initCamera();initLight();initModel();initRender();initStats();initControls();render();}window.onload = init;</script>
</body></html>

三维空间中绘制点、线、面、UV贴图,万能的BufferGeometry(three.js实战4)相关推荐

  1. matlab在二维平面和三维空间中绘制圆形

    matlab在二维平面和三维空间中绘制圆形 二维平面绘制圆形 方法1: x = 10;y = 10;%圆心 r = 5; %半径 rectangle('Position',[x-r,y-r,2*r,2 ...

  2. c++中用opengl的gl函数在三维空间中绘制圆形和画球体

    c++中用opengl的gl函数在三维空间中绘制圆形和球体 绘制圆形原理: 画圆形的原理如下图,画一个圆形就相当于切蛋糕一样,将一个圆形切成很多个扇形,而扇形可以用三角形类似表示,所以我们可以将绘制圆 ...

  3. Threejs中 Blender建模的问题 ------ uv贴图中修改贴图的方向和uv贴图材质重复不起作用

    修改贴图的方向(只有一个面) 数字键盘/来在3D视图中控制视野中选中对象的显示切换 首先确保添加了uv的数据,不然会在最终的显示材质时有问题 直接在Blender建模,添加材质,添加纹理 在three ...

  4. 中绘制折线_啥是折线图?啥时候用?怎么用呢?这里全都有,满足你的味蕾

    大家好: 今天为大家带来图表选项下的折线图内容讲解,话不多说,开始今天的理论讲述和案例操作. 折线图常用来显示某一事项随时间变化的趋势,比如一周内步数的变化.公司各月份的产值变化等:也可用来表示有一种 ...

  5. C4D建模教程篇之在AI中绘制样条线至C4D挤压

    前言:但凡表面是平整的形状,都可以在AI或者PS里做成样条线,放进C4D,挤压形成.必须是封闭路径,必须是路径不能是面. 原创不易,如需转载,请附上本文链接,谢谢支持 https://editor.c ...

  6. 中绘制折线_统计图之折线图的结构和制作过程

    统计图(statisticalgraph)是用点.线.面等各种几何图形来形象化表达统计数据.它将研究对象的特征.内部构成.相互关系.对比情况.频数分布等情况形象而生动地表达出来,更直观地反映出事物间的 ...

  7. html怎么绘制飞线,绘制飞线,echarts迁徙图原理

    其实是在元素上绘制了一条线,然后利用canvas 的createLinearGradient函数不断移动线段的样式位置来实现. 因此首先绘制线段 ctx.beginPath(); ctx.moveTo ...

  8. osg画线_在OpenSceneGraph中绘制OpenCascade的曲面

    在OpenSceneGraph中绘制OpenCascade的曲面 Draw OpenCascade Geometry Surfaces in OpenSceneGraph 摘要Abstract:本文对 ...

  9. matlab 画 矩阵点,在MATLAB中绘制矩阵中点之间的线

    3 个答案: 答案 0 :(得分:1) 这适用于我的数据结构: data = [ 0, 0, 1, 0;... 1, 0, 1, 1;... 1, 1, 0, 1;... 0, 1, 0, 0 ... ...

最新文章

  1. 新增的querySelector、querySelectorAll测试
  2. Java中sc在哪里关闭_node 中设置的session,在javasc 怎么获取
  3. 关于H3C路由配置VLAN的问题
  4. c语言wb和wb 区别,C语言文件 w+与wb+区别
  5. Laravel5.2目录结构及composer.json文件解析
  6. as cast float server sql_面试常考!SQL行转列和列转行
  7. 第二阶段冲刺 NO.2
  8. 移动互联网将向“全真互联网”升级
  9. 机器学习基础:朴素贝叶斯(Machine Learning Fundamentals: Naive Bayes)
  10. java 8 排序_java8——排序
  11. 锁的等级:方法锁、对象锁、类锁。
  12. 滴滴打车CTO张博:生死战役,技术和时间赛跑
  13. 微信小程序 关于头像上传,showActionSheet,chooseImage,uploadFile
  14. VScode代码格式化及语法检测
  15. android 9.0 app应用安装白名单
  16. 绕过限制低价购买和增删低价购买逻辑漏洞
  17. win10计算机怎么拨号上网,宽带拨号,教您win10系统宽带拨号上网的教程
  18. 微软ATC的笔试面试经历
  19. Required string parameter ‘XXX‘ is not present
  20. 新能源系统仿真测试解决方案

热门文章

  1. 做视频剪辑工作赚钱吗?
  2. argo workflow 部署
  3. FOT再次上涨,中国市场需求不断上升,牛市真来了?
  4. Elastic Search创建文档和更新文档
  5. iOS 程序 main 函数之前发生了什么
  6. 淘宝api是什么19970108019
  7. java开发最新获取抖音无水印视频和背景音乐
  8. edge浏览器下载插件出现Download interrupted
  9. 阿贝不变量等三个重要公式的推导
  10. 甘肃阿克塞百余只“岩壁精灵”雪中觅食