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

news2025/7/19 12:33:47

本实例主要讲解内容

这个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/
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2374679.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入掌握CSS定位:构建精密布局的核心技术

一、定位的定义 定位&#xff08;Positioning&#xff09;是CSS中用于控制元素在网页中的具体位置的一种机制。通过定位&#xff0c;可以将元素放置在页面的任意位置&#xff0c;并控制其与其他元素的层叠关系。 二、定位的特点与作用 自由摆放位置&#xff1a; 允许元素摆放…

Go语言多线程爬虫与代理IP反爬

有个朋友想用Go语言编写一个多线程爬虫&#xff0c;并且使用代理IP来应对反爬措施。多线程在Go中通常是通过goroutine实现的&#xff0c;所以应该使用goroutine来并发处理多个网页的抓取。然后&#xff0c;代理IP的话&#xff0c;可能需要一个代理池&#xff0c;从中随机选择代…

node.js 实战——express图片保存到本地或服务器(七牛云、腾讯云、阿里云)

本地 ✅ 使用formidable 读取表单内容 npm i formidable ✅ 使用mime-types 获取图片后缀 npm install mime-types✅ js 中提交form表单 document.getElementById(uploadForm).addEventListener(submit, function(e){e.preventDefault();const blob preview._blob;if(!blob)…

Shadertoy着色器移植到Three.js经验总结

Shadertoy是一个流行的在线平台&#xff0c;用于创建和分享WebGL片段着色器。里面有很多令人惊叹的画面&#xff0c;甚至3D场景。本人也移植了几个ShaderToy上的着色器。本文将详细介绍移植过程中需要注意的关键点。 1. 基本结构差异 想要移植ShaderToy的shader到three.js&am…

电脑端音乐播放器推荐:提升你的听歌体验!

在快节奏的职场环境中&#xff0c;许多上班族都喜欢用音乐为工作时光增添色彩。今天要分享的这款音乐工具&#xff0c;或许能为你的办公时光带来意想不到的惊喜。 一、软件介绍-澎湃 澎湃音乐看似是个普通的播放器&#xff0c;实则藏着强大的资源整合能力。左侧功能栏清晰陈列着…

VIC-2D 7.0 为平面样件机械试验提供全视野位移及应变数据软件

The VIC-2D系统是一个完全集成的解决方案&#xff0c;它基于优化的相关算法为平面试样的力学测试提供非接触、全场的二维位移和应变数据&#xff0c;可测量关注区域内的每个像素子集的面内位移&#xff0c;并通过多种张量选项计算全场应变。The VIC-2D 系统可测量超过 2000%变形…

一周学完计算机网络之三:1、数据链路层概述

简单的概述 数据链路层是计算机网络体系结构中的第二层&#xff0c;它在物理层提供的基本服务基础上&#xff0c;负责将数据从一个节点可靠地传输到相邻节点。可以将其想象成一个负责在两个相邻的网络设备之间进行数据 “搬运” 和 “整理” 的 “快递中转站”。 几个重要概念…

单片机-STM32部分:13-1、蜂鸣器

飞书文档https://x509p6c8to.feishu.cn/wiki/V8rpwIlYIiEuXLkUljTcXWiKnSc 一、应用场景 大部分的电子产品、家电&#xff08;风扇、空调、电水壶&#xff09;都会有蜂鸣器&#xff0c;用于提示设备的工作状态 二、原理 蜂鸣器是一种将电信号转换为声音信号的器件&#xff0…

动态IP技术赋能业务创新:解锁企业数字化转型新维度

在数字经济高速发展的今天&#xff0c;IP地址已不再是简单的网络标识符&#xff0c;而是演变为支撑企业数字化转型的核心基础设施之一。动态IP技术凭借其灵活、高效、安全的特性&#xff0c;正在重塑传统业务模式&#xff0c;催生出诸多创新应用场景。本文将深入剖析动态IP的技…

TDengine 在金融领域的应用

简介 金融行业正处于数据处理能力革新的关键时期。随着市场数据量的爆炸式增长和复杂性的日益加深&#xff0c;金融机构面临着寻找能够高效处理大规模、高频次以及多样化时序数据的大数据处理系统的迫切需求。这一选择将成为金融机构提高数据处理效率、优化交易响应时间、提高…

OSCP - Hack The Box - Sau

主要知识点 CVE-2023-27163漏洞利用systemd提权 具体步骤 执行nmap扫描&#xff0c;可以先看一下55555端口 Nmap scan report for 10.10.11.224 Host is up (0.58s latency). Not shown: 65531 closed tcp ports (reset) PORT STATE SERVICE VERSION 22/tcp o…

QT6 源(93)篇三:阅读与注释共用体类 QVariant 及其源代码,本类支持比较运算符 ==、!=。

&#xff08;9&#xff09; 本类支持比较运算符 、! &#xff1a; 可见&#xff0c; QString 类型里可存储多个 unicode 字符&#xff0c;即使只存储一个 unicode 字符也不等于 QChar。 &#xff08;10&#xff09;本源代码来自于头文件 qvariant . h &#xff1a; #ifndef Q…

Maven私服搭建与登录全攻略

目录 1.背景2.简介3.安装4.启动总结参考文献 1.背景 回顾下maven的构建流程&#xff0c;如果没有私服&#xff0c;我们所需的所有jar包都需要通过maven的中央仓库或者第三方的maven仓库下载到本地&#xff0c;当一个公司或者一个团队所有人都重复的从maven仓库下载jar包&#…

力扣210(拓扑排序)

210. 课程表 II - 力扣&#xff08;LeetCode&#xff09; 这是一道拓扑排序的模板题。简单来说&#xff0c;给出一个有向图&#xff0c;把这个有向图转成线性的排序就叫拓扑排序。如果有向图中有环就没有办法进行拓扑排序了。因此&#xff0c;拓扑排序也是图论中判断有向无环图…

C++ asio网络编程(5)简单异步echo服务器

上一篇文章:C asio网络编程(4)异步读写操作及注意事项 文章目录 前言一、Session类1.代码2.代码详解3.实现Session类1.构造函数2.handle_read3.介绍一下boost的封装函数和api4.handle_write 二、Server类1.代码2.代码思路详解 三、客户端四、运行截图与流程图 前言 提示&…

【机器人】复现 UniGoal 具身导航 | 通用零样本目标导航 CVPR 2025

UniGoal的提出了一个通用的零样本目标导航框架&#xff0c;能够统一处理多种类型的导航任务。 支持 对象类别导航、实例图像目标导航和文本目标导航&#xff0c;而无需针对特定任务进行训练或微调。 本文分享UniGoal复现和模型推理的过程&#xff5e; 查找沙发&#xff0c;模…

spring中的@PropertySource注解详解

一、核心功能与作用 PropertySource是Spring框架中用于加载外部配置文件的核心注解&#xff0c;主要作用是将属性文件&#xff08;如.properties、.yml&#xff09;的键值对加载到Spring的Environment环境中&#xff0c;实现配置与代码的解耦。其核心价值包括&#xff1a; 外部…

二极管钳位电路——Multisim电路仿真

目录 二极管钳位电路 2.1 二极管正向钳位电路 二极管压降测试 2.1.1 二极管正向钳位电路图 2.1.2 二极管正向钳位工作原理 2.2 二极管负向钳位电路 2.2.1 二极管负向钳位电路图 2.2.2 二极管负向钳位工作原理 二极管正向反向钳位仿真电路实验结果 2.3 二极管顶部钳位…

suricata增加单元测试编译失败

一、环境 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.5 LTS Release: 22.04 Codename: jammysuricata: suricata7.0.5 IDE: vscode 二、背景 在suricata中开发了某个功能后&#xff0c;增加unittest时&#xff0c;…

高并发场景下的BI架构设计:衡石分布式查询引擎与缓存分级策略

在电商大促、金融交易时段或IoT实时监控场景中&#xff0c;企业BI系统常面临瞬时万级并发查询的冲击——运营团队需要实时追踪GMV波动&#xff0c;风控部门需秒级响应欺诈检测&#xff0c;产线监控需毫秒级反馈设备状态。传统单体架构的BI系统在此类场景下极易崩溃&#xff0c;…