三维空间中绘制点、线、面、UV贴图,万能的BufferGeometry(three.js实战4)
使用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)相关推荐
- matlab在二维平面和三维空间中绘制圆形
matlab在二维平面和三维空间中绘制圆形 二维平面绘制圆形 方法1: x = 10;y = 10;%圆心 r = 5; %半径 rectangle('Position',[x-r,y-r,2*r,2 ...
- c++中用opengl的gl函数在三维空间中绘制圆形和画球体
c++中用opengl的gl函数在三维空间中绘制圆形和球体 绘制圆形原理: 画圆形的原理如下图,画一个圆形就相当于切蛋糕一样,将一个圆形切成很多个扇形,而扇形可以用三角形类似表示,所以我们可以将绘制圆 ...
- Threejs中 Blender建模的问题 ------ uv贴图中修改贴图的方向和uv贴图材质重复不起作用
修改贴图的方向(只有一个面) 数字键盘/来在3D视图中控制视野中选中对象的显示切换 首先确保添加了uv的数据,不然会在最终的显示材质时有问题 直接在Blender建模,添加材质,添加纹理 在three ...
- 中绘制折线_啥是折线图?啥时候用?怎么用呢?这里全都有,满足你的味蕾
大家好: 今天为大家带来图表选项下的折线图内容讲解,话不多说,开始今天的理论讲述和案例操作. 折线图常用来显示某一事项随时间变化的趋势,比如一周内步数的变化.公司各月份的产值变化等:也可用来表示有一种 ...
- C4D建模教程篇之在AI中绘制样条线至C4D挤压
前言:但凡表面是平整的形状,都可以在AI或者PS里做成样条线,放进C4D,挤压形成.必须是封闭路径,必须是路径不能是面. 原创不易,如需转载,请附上本文链接,谢谢支持 https://editor.c ...
- 中绘制折线_统计图之折线图的结构和制作过程
统计图(statisticalgraph)是用点.线.面等各种几何图形来形象化表达统计数据.它将研究对象的特征.内部构成.相互关系.对比情况.频数分布等情况形象而生动地表达出来,更直观地反映出事物间的 ...
- html怎么绘制飞线,绘制飞线,echarts迁徙图原理
其实是在元素上绘制了一条线,然后利用canvas 的createLinearGradient函数不断移动线段的样式位置来实现. 因此首先绘制线段 ctx.beginPath(); ctx.moveTo ...
- osg画线_在OpenSceneGraph中绘制OpenCascade的曲面
在OpenSceneGraph中绘制OpenCascade的曲面 Draw OpenCascade Geometry Surfaces in OpenSceneGraph 摘要Abstract:本文对 ...
- matlab 画 矩阵点,在MATLAB中绘制矩阵中点之间的线
3 个答案: 答案 0 :(得分:1) 这适用于我的数据结构: data = [ 0, 0, 1, 0;... 1, 0, 1, 1;... 1, 1, 0, 1;... 0, 1, 0, 0 ... ...
最新文章
- 新增的querySelector、querySelectorAll测试
- Java中sc在哪里关闭_node 中设置的session,在javasc 怎么获取
- 关于H3C路由配置VLAN的问题
- c语言wb和wb 区别,C语言文件 w+与wb+区别
- Laravel5.2目录结构及composer.json文件解析
- as cast float server sql_面试常考!SQL行转列和列转行
- 第二阶段冲刺 NO.2
- 移动互联网将向“全真互联网”升级
- 机器学习基础:朴素贝叶斯(Machine Learning Fundamentals: Naive Bayes)
- java 8 排序_java8——排序
- 锁的等级:方法锁、对象锁、类锁。
- 滴滴打车CTO张博:生死战役,技术和时间赛跑
- 微信小程序 关于头像上传,showActionSheet,chooseImage,uploadFile
- VScode代码格式化及语法检测
- android 9.0 app应用安装白名单
- 绕过限制低价购买和增删低价购买逻辑漏洞
- win10计算机怎么拨号上网,宽带拨号,教您win10系统宽带拨号上网的教程
- 微软ATC的笔试面试经历
- Required string parameter ‘XXX‘ is not present
- 新能源系统仿真测试解决方案