17.three官方示例+编辑器+AI快速学习webgl_buffergeometry_lines

发布于:2025-05-14 ⋅ 阅读:(17) ⋅ 点赞:(0)

本实例主要讲解内容

这个Three.js示例展示了如何使用BufferGeometry创建大量线段,并通过**变形目标(Morph Targets)**实现动态变形效果。通过随机生成的点云数据,结合顶点颜色和变形动画,创建出一个视觉效果丰富的3D线条场景。

核心技术包括:

  • BufferGeometry的高效使用
  • 顶点颜色的应用
  • 变形目标动画技术
  • 动态场景性能优化

在这里插入图片描述

完整代码注释

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - buffergeometry - lines</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>
	<body>

		<div id="container"></div>
		<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - buffergeometry - lines</div>

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three';

			import { Timer } from 'three/addons/misc/Timer.js';
			import Stats from 'three/addons/libs/stats.module.js';

			let container, stats, timer;

			let camera, scene, renderer;

			let line;

			// 线段数量
			const segments = 10000;
			// 范围半径
			const r = 800;
			// 动画时间变量
			let t = 0;

			init();

			function init() {

				container = document.getElementById( 'container' );

				// 初始化相机
				camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 4000 );
				camera.position.z = 2750;

				// 初始化场景
				scene = new THREE.Scene();

				// 初始化计时器
				timer = new Timer();
				timer.connect( document );

				// 创建几何体和材质
				const geometry = new THREE.BufferGeometry();
				// 使用顶点颜色的线材质
				const material = new THREE.LineBasicMaterial( { vertexColors: true } );

				// 存储位置和颜色数据
				const positions = [];
				const colors = [];

				// 生成随机点云数据
				for ( let i = 0; i < segments; i ++ ) {

					// 随机位置
					const x = Math.random() * r - r / 2;
					const y = Math.random() * r - r / 2;
					const z = Math.random() * r - r / 2;

					// 添加位置数据
					positions.push( x, y, z );

					// 添加颜色数据(基于位置归一化)
					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 ) );
				
				// 生成变形目标
				generateMorphTargets( geometry );

				// 计算边界球体,用于视锥体剔除
				geometry.computeBoundingSphere();

				// 创建线条对象
				line = new THREE.Line( geometry, material );
				scene.add( line );

				// 初始化渲染器
				renderer = new THREE.WebGLRenderer();
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.setAnimationLoop( animate );

				container.appendChild( renderer.domElement );

				// 添加性能统计
				stats = new Stats();
				container.appendChild( stats.dom );

				// 窗口大小变化事件监听
				window.addEventListener( 'resize', onWindowResize );

			}

			// 窗口大小变化处理函数
			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			// 动画循环
			function animate() {

				// 更新计时器
				timer.update();

				// 获取时间增量和总时间
				const delta = timer.getDelta();
				const time = timer.getElapsed();

				// 旋转整个线条对象
				line.rotation.x = time * 0.25;
				line.rotation.y = time * 0.5;

				// 更新变形目标影响因子
				t += delta * 0.5;
				line.morphTargetInfluences[ 0 ] = Math.abs( Math.sin( t ) );

				// 渲染场景
				renderer.render( scene, camera );

				// 更新性能统计
				stats.update();

			}

			// 生成变形目标
			function generateMorphTargets( geometry ) {

				// 存储变形目标的位置数据
				const data = [];

				// 生成随机目标位置
				for ( let i = 0; i < segments; i ++ ) {

					const x = Math.random() * r - r / 2;
					const y = Math.random() * r - r / 2;
					const z = Math.random() * r - r / 2;

					data.push( x, y, z );

				}

				// 创建变形目标属性
				const morphTarget = new THREE.Float32BufferAttribute( data, 3 );
				morphTarget.name = 'target1';

				// 设置几何体的变形目标
				geometry.morphAttributes.position = [ morphTarget ];

			}

		</script>

	</body>
</html>

BufferGeometry与变形目标技术解析

BufferGeometry的优势

BufferGeometry是Three.js中最高效的几何体表示方式,相比普通Geometry,它有以下优势:

  1. 内存效率高:以连续数组形式存储顶点数据,更接近GPU原生格式
  2. 渲染速度快:减少CPU-GPU数据传输开销
  3. 支持大规模场景:能够处理数百万个顶点
  4. 灵活的数据组织:可以自定义顶点属性

在本示例中,我们使用BufferGeometry存储顶点位置和颜色数据:

const geometry = new THREE.BufferGeometry();

// 创建位置和颜色数据数组
const positions = [];
const colors = [];

// 填充数据...

// 设置几何体属性
geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
变形目标动画

变形目标(Morph Targets)是一种基于顶点的动画技术,通过在不同顶点位置之间插值实现平滑变形效果。主要步骤包括:

  1. 定义基础几何体:原始顶点位置
  2. 定义变形目标:一个或多个目标顶点位置
  3. 控制影响因子:通过影响因子控制变形程度(0.0-1.0)

在本示例中,我们实现了一个变形目标:

// 生成变形目标数据
function generateMorphTargets( geometry ) {
  const data = [];
  // 生成随机目标位置...
  
  // 创建变形目标属性
  const morphTarget = new THREE.Float32BufferAttribute( data, 3 );
  morphTarget.name = 'target1';
  
  // 设置几何体的变形目标
  geometry.morphAttributes.position = [ morphTarget ];
}

// 在动画循环中控制变形程度
line.morphTargetInfluences[ 0 ] = Math.abs( Math.sin( t ) );
顶点颜色应用

顶点颜色允许为每个顶点指定不同的颜色,GPU会自动在顶点之间进行插值,产生平滑的渐变效果。使用顶点颜色的步骤:

  1. 材质设置:在材质中启用vertexColors
  2. 提供颜色数据:为每个顶点提供RGB颜色值

在本示例中:

// 创建启用顶点颜色的材质
const material = new THREE.LineBasicMaterial( { vertexColors: true } );

// 为每个顶点生成颜色数据(基于位置)
colors.push( ( x / r ) + 0.5 );
colors.push( ( y / r ) + 0.5 );
colors.push( ( z / r ) + 0.5 );

// 设置几何体的颜色属性
geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
性能优化与应用场景

对于大规模线条渲染的性能优化建议:

  1. 使用BufferGeometry:相比普通Geometry,性能提升显著
  2. 合并几何体:如果可能,将多个线条合并为一个
  3. 合理使用变形目标:每个变形目标都会增加内存使用
  4. 控制顶点数量:过多顶点会导致性能下降
  5. 视锥体剔除:确保几何体有正确的边界球体

这种技术适合以下场景:

  • 数据可视化(点云、网络图等)
  • 粒子系统
  • 动态线条艺术
  • 模拟流体、烟雾等效果

通过结合BufferGeometry、顶点颜色和变形目标,我们可以创建出视觉效果丰富且性能高效的动态线条场景。
交流学习: Three.js 场景编辑器 (Vue3 + TypeScript
实现)
https://threelab.cn/threejs-edit/
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到