【Three.js】BufferGeometry 基础讲解(position、normal、color、index)

1. BufferGeometry

首先,在 three.js 中有THREE.Mesh 网格、THREE.Points 点、THREE.Line 线条等模型。其中:

  • Mesh 网格模型创建的物体是由一个个小三角形组成,如下面各图。这些小三角形又是由三个点确定,需要三个确定的位置,即确定的 xyz

  • Points 模型创建的物体是由一个个点构成,每个点都有自己的位置,Points 相当于点的集合。

  • Line 模型创建的物体是连续的线条,这些线可以理解为是按顺序把所有点连接起来。

不管是哪一种模型,它们都有一个共同点,就是都离不开点,每一个点都有确定的 x y z,BoxGeometry、SphereGeometry 帮我们封装了对这些点的操作,我们只需要告诉它们长宽高或者半径这些信息,它就会帮我创建一个默认的几何体。而 BufferGeometry 就是完全由我们自己去操作点信息的方法,我们可以通过它去设置每一个点的位置,即 position;每一个点的颜色,即 color;每一个点的法向量 normal 等。

2. position 设置点位置

1. 首先,我们将所有点的坐标存在一个类型化数组中,关于类型化数组的介绍可以查看:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Typed_arrays。如下,每一行是一个点的x y z 值,我们按顺序存储每一个点的坐标,这里我们声明了六个点。

let positions = new Float32Array([
	-10, 0, 0, // 0
	10, 0, 0, // 1
	0, 10, 0, // 2
	0, 0, 5, // 3
	0, 10, 5, // 4
	0, 0, 15 // 5
]);

2. 定义好顶点数组后,我们将顶点设置到 BufferGeometry 中,代码如下。其中,THREE.BufferAttribute(positions, 3) 中第二个参数 3 指的是数组 positions 中每三个元素构成一个点,分别表示x y z 值。

geometry = new THREE.BufferGeometry();
geometry.attributes.position = new THREE.BufferAttribute(positions, 3);

3. 设置好后,此时如果我们构建网格模型,代码如下。此时,会自动以positions 数组中三行数据,即9个元素3个点,连接构成一个三角形。依次构成三角形,上面的六个点将构成两个三角形,效果如图:

    let mesh = new THREE.Mesh(
		geometry,
		new THREE.MeshBasicMaterial({ 
			color: 0xff0000,
			side: THREE.DoubleSide 
		})
		);
	scene.add(mesh);

4. 如果使用点模型构建,则会以每3个元素创建一个点,代码、效果如下:六个点直接显示出来。

    let point = new THREE.Points(
		geometry,
		new THREE.PointsMaterial({
				color: 0x00ff00,
				size: 3
			})
		);
	scene.add(point);

5. 如果使用线模型构建,则会按照点的顺序依次连接各个点,代码、效果如下:

    let line = new THREE.Line(
		geometry,
		new THREE.LineBasicMaterial({
			color: 0x00ffff
		})
		);
	scene.add(line);

3. 设置点颜色

1. 每一个点都可以设置颜色,颜色通过 rgb 值来设置,r g b 分别取 0-1之间的值。比如如下设置颜色,其中,每一行分别为一个点的颜色,每一行的三个元素分别是颜色的 rgb 值,下面设置了六个点的颜色。

    let colors = new Float32Array([
			1, 0, 0,
			0, 1, 0,
			0, 0, 1, 
			1, 1, 0, 
			0, 1, 1, 
			1, 0, 1
		]);

2. 定义好颜色数组后,添加到 BufferGeometry 中,并且设置到材质中,举例创建一个Mesh模型如下:

    geometry.addAttribute("color", new THREE.BufferAttribute(colors, 3));

    let mesh = new THREE.Mesh(
		geometry,
		new THREE.MeshBasicMaterial({ 
			vertexColors: THREE.VertexColors, // 该设置就是使用顶点设置颜色
			side: THREE.DoubleSide 
		})
		);
	scene.add(mesh);

3. 可以看到网格、点、线设置顶点颜色后效果分别如下:

4. 设置点法向量

normal 的设置主要和光照相关,我们知道光照在物体的表面,由于光线与表面夹角角度的不一样,会导致亮度等也不一样。在 three.js 中,我们要知道一个物体的光照效果,需要知道物体表面每一个位置的法向方向,而 threejs 中的物体是由一个个点构成的,我们就需要知道每一个的法向量,这里的两个三角形法线方向分别是 z 轴和 x 轴。注意:法向量必须归一化,Vector3 中有方法可以直接调用。这里我们直接声明法向量数组:

    let normals = new Float32Array([
			0, 0, 1, 
			0, 0, 1, 
			0, 0, 1, 
			1, 0, 0, 
			1, 0, 0, 
			1, 0, 0
		]);

    geometry.addAttribute("normal", new THREE.BufferAttribute(normals, 3));

5. 设置 index

可以理解 index 为 positions 数组中的第n-1个点,如下每一行注释后面就是该点的 index 值。我们知道在 Mesh 模型中,threejs 直接按顺序没三个点一组创建一个三角形,index 就是为了帮助我们指定哪三个点构成一个三角形,并且这些点还可以重复使用。

let positions = new Float32Array([
	-10, 0, 0, // 0
	10, 0, 0, // 1
	0, 10, 0, // 2
	0, 0, 5, // 3
	0, 10, 5, // 4
	0, 0, 15 // 5
]);

如下,注意:这里用的是 Uint16Array,在这里,我们就可以通过6个点创建3个三角形,并且这些三角形的顶点都是我们自己指定的。而且,这里的 THREE.BufferAttribute(indexs, 1) 的第二个参数为 1 ,表示这里数组 indexs 中每一个元素表示一个点。

	    let indexs = new Uint16Array([
			0, 1, 2,
			3, 4, 5,
			2, 4, 5
		]);

        geometry.index = new THREE.BufferAttribute(indexs, 1);

效果如下,三个三角形:

  • 20
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要实现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。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值