【BufferAttribute】2021-r126版three.js中BufferGeometry类的使用学习

【BufferGeometry】2021-r126版three.js中BufferGeometry类的使用学习


刚开始接触three.js,记录在这里免得自己忘记,欢迎萌新交流,以及跪求大佬指点!

【写在最前面提醒自己和其他萌新:常见的网课大多很老了,目前发现还是看官方文档+结合官方给出的实例源码来自己琢磨更好些!网课可作为参考,一些代码的写法可能已经不适用了。】

我的理解是,BufferGeometry是自由度最高的创建几何/几何体的方式,以前似乎有Geometry,但我在目前版本r126的官方文档(https://threejs.org/)里已经找不到了,两者的区别是,buffer版会把GPU计算后的数据存放在缓冲区后进行展示,后续修改时,可以减少GPU的计算,进而提升性能。

看一个我自己写的入门小例子,先放图,其中蓝色线条为世界坐标轴,坐标轴交点是0,0,0,threejs中右和上为x,y轴的正向,垂直屏幕向用户为z轴的正向。该图片中摄像机的位置为左侧靠上。
在这里插入图片描述
上图从左至右是三种不同的展示方式,分别是点,线,面。
使用过封装好的模型(例如BoxGeometry)的话,应该知道,一个模型是由几何,材质,展示方式组成的,一般这样写:

var geometry = new THREE.BoxGeometry( 1, 1, 1 );//几何
var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );//材质
var cube = new THREE.Mesh( geometry, material );//展示
scene.add( cube );//添加到场景里

BufferGeometry自定义的仅仅是几何的部分,后面都是一样的。几何需要设置的包括点,点的颜色,法向量,用点的索引表示的面片等,法向量是跟光线有关的,先跳过,现在只看点,颜色,面片。

首先new一个空的几何出来,然后创建顶点组,可以看到这里用的是Float32Array来创建的,这是因为在js里,number类型默认的是64位浮点型,太大了,所以用32位来储存。ArrayBuffer数组有好多种类,目前我看到的webGL源码基本都是用的Float32,那姑且就都用这个了吧(对了,我试了下,BufferAttribute不支持64位)。

创建一个这样的数组可以像下面代码里这样写,即:new Float32Array([]),这是把普通数组转换成Float32Array数组,一个数字占4个字节,这种写法只能传入固定已知的数组,不能var a = [];new Float32Array(a);这样是不行的。

搞懂Float32Array后,可以看到一共有8行,每行3个数字,这代表8个顶点,每一行从左至右的顺序是该点的x,y,z值,这些点的索引顺序是从上至下的,以0为开头,后面会用到这个索引。

在创建完点集后,通过setAttribute可以设置节点属性,BufferAttribute中的3意思是每个点由3个数组成。

			const geometry_zdy = new THREE.BufferGeometry();
			const vertices_zdy = new Float32Array( [
				-8.0, 8,  40.0,//0
				 -38.0, 8,  40.0,//1
				-8.0, 8,  0.0,//2
				 -38.0, 8,  0.0,//3
				 -8.0, 38,  0.0,//4
				  -38.0, 38,  0.0,//5
				-8.0, 38,  40.0,//6
				 -38.0, 38,  40.0,//7		
			] );
			geometry_zdy.setAttribute( 'position', new THREE.BufferAttribute( vertices_zdy, 3 ) );

接下来设置顶点的颜色,注意threejs里的颜色不能用0~255的rgb来表示,要么用16进制,要么用0-1的rgb数值。
8x3是8个点x3个rbg数的意思,(vertices_zdy[i++]+50)/100是顶点间颜色的过渡,其中除以100是为了归一化到0-1内,这个值应该是模型两个点之间,在x,y,z轴上距离的最大值,说人话就是,比如如果你画了个正方体,且宽度是100,那么就可以除以100,这是为了满足r,g,b三个值必须在0-1内的需求。

其次,显然,r,g,b三个值缓慢增加或减少,即可展示出颜色的缓慢变化,因此,用顶点的x,y,z值来辅助计算rgb(代码中vertices_zdy[i++]的用意),即可达到相近点颜色也相近,且缓慢过渡的效果(是点不是线/面)。
创建完顶点颜色集后,一样设置属性即可,这里要注意的是,由于colors_zdy是变量,所以不能用new Float32Array([]),这里改成直接在设置属性时,指明Float32BufferAttribute。

			var i=0;		
			const colors_zdy = [];
			while(i<8*3){
				colors_zdy.push((vertices_zdy[i++]+50)/100);
			}
			geometry_zdy.setAttribute( 'color', new THREE.Float32BufferAttribute( colors_zdy, 3 ) );

然后创建面片,setIndex是通过顶点索引来指定三角形面片的,正方体一面是两个三角形,所以绘制了4个面(上文图片最右侧,只画了四面)是要8个三角形,一行一个。

【注意,如果这里不创建面片的话,则按照定点数组来绘制面,如上面代码中指示顶点为8个,从第一个点开始,每3个会被认为是一个面,所以如果注释掉setIndex这一段,可以看到只绘制了两个三角形,所以,也可以用顶点数组来绘制面。】

			geometry_zdy.setIndex( [
				0, 3, 1, 
				0, 3, 2, 
				4, 0, 2, 
				4, 0, 6, 	
				5, 6, 4,  
				5, 6, 7, 
				1,5, 3, 
				1, 5, 7
			] );

到这里顶点,顶点颜色,面都设置完毕了,开始绘制3种不同的展示,这里就到了材质和展示,而不是BufferGeometry的部分了。
THREE.PointsMaterial可以设置点材质,相应的,Line,Mesh是线和面,其中,vertexColors可以设置一个具体的颜色值,也可以用THREE.VertexColors来表示按照顶点颜色来绘制,此外,size是顶点的大小。
用vertexColors: THREE.VertexColors这个写法可以很方便的实现一个渐变的效果,就像图片中所示。

要特别注意的是,mesh中指定按照顶点颜色来绘制,是要用 vertexColors : true来表示的,不是vertexColors: THREE.VertexColors。

此外要注意的是,默认是单面绘制的!所以,如果保持默认,则顶点的顺序很重要,正向的顺序可以看到绘制结果,逆向就啥也木有了,因此最好在mesh的材质里声明双向绘制side: THREE.DoubleSide。

			const material_zdy =  new THREE.PointsMaterial( { size: 1, vertexColors: THREE.VertexColors } );
			const material_zdy2 = new THREE.LineBasicMaterial({
			      vertexColors: THREE.VertexColors//以顶点颜色为准
			});
			var material_zdy3 = new THREE.MeshBasicMaterial({
			    vertexColors : true,
			    side: THREE.DoubleSide
			});

最后是创建一个物体,分别是点,线,或者面,可以理解为不同的展示方式,它们使用的都是同一个几何框架,但材质不一样。之后将他们分别添加到场景中,即可看到文章中图片的效果。

			const mesh_zdy = new THREE.Points( geometry_zdy, material_zdy );
			const mesh_zdy2 = new THREE.Line( geometry_zdy, material_zdy2 );
			const mesh_zdy3 = new THREE.Mesh(geometry_zdy, material_zdy3);
			
			scene.add(mesh_zdy3);
			scene.add(mesh_zdy2);
			scene.add(mesh_zdy);

最后,我在部分教程中看到,以前似乎存在THREE.Face3来创建面片的方法,以及这些创建出的面片需要放在几何的faces数组中,但我看了下源码,在BufferGeometry的构造函数中没有找到faces,可能是已经没有了吧,没有用过之前的版本,不敢乱说,权当做提醒。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现3D火焰效果,可以使用BufferGeometry和ShaderMaterial来创建一个自定义的火焰材质。下面是一个简单的实现步骤: 1. 创建一个BufferGeometry对象,并设置顶点、索引和UV坐标数据。这些数据可以通过编写一个简单的函数来生成。 ``` function createFireGeometry() { const geometry = new THREE.BufferGeometry(); const vertices = []; const indices = []; const uvs = []; // Generate vertices and indices // ... geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); geometry.setIndex(indices); geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2)); return geometry; } ``` 2. 创建一个自定义的ShaderMaterial,并设置uniform变量。这些变量将用于控制火焰的外观和动画。在这个例子,我们设置了时间、颜色、火焰高度、火焰密度和火焰速度等变量。 ``` const fireMaterial = new THREE.ShaderMaterial({ uniforms: { time: { value: 0 }, color: { value: new THREE.Color('#ff5500') }, flameHeight: { value: 1.5 }, flameDensity: { value: 1.0 }, flameSpeed: { value: 1.0 }, noiseTexture: { value: noiseTexture }, }, vertexShader: ` // Vertex shader code `, fragmentShader: ` // Fragment shader code `, }); ``` 3. 编写着色器代码,实现火焰效果。着色器代码包括顶点着色器和片段着色器。顶点着色器用于将顶点位置转换为屏幕空间坐标,并将一些变量传递给片段着色器。片段着色器用于计算像素颜色,以实现火焰效果。 ``` // Vertex shader code attribute vec3 position; attribute vec2 uv; uniform float time; uniform float flameHeight; uniform float flameDensity; uniform float flameSpeed; varying vec2 vUv; varying float vDistortion; void main() { // Vertex shader code } // Fragment shader code uniform vec3 color; uniform sampler2D noiseTexture; void main() { // Fragment shader code } ``` 4. 将BufferGeometry和ShaderMaterial组合到一个Mesh对象,并将其添加到场景。 ``` const fireGeometry = createFireGeometry(); const fireMesh = new THREE.Mesh(fireGeometry, fireMaterial); scene.add(fireMesh); ``` 5. 在渲染循环更新uniform变量,以实现动画效果。 ``` function animate() { requestAnimationFrame(animate); const time = performance.now() / 1000; fireMaterial.uniforms.time.value = time; renderer.render(scene, camera); } ``` 6. 完成。现在可以看到一个简单的3D火焰效果了。 完整的代码示例可以参考这里:https://codepen.io/zadvorsky/pen/xxKXxYp。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值