当前位置: 首页 > news >正文

14.three官方示例+编辑器+AI快速学习webgl_buffergeometry_instancing_interleaved

本实例主要讲解内容

这个Three.js示例展示了如何结合使用索引几何体GPU实例化交错缓冲区来高效渲染大量相同模型的不同实例。通过这种技术组合,我们可以在保持较低内存占用的同时渲染数千个独立变换的对象。

核心技术包括:

  • 索引几何体的实例化渲染
  • 交错缓冲区的组织与使用
  • 实例变换矩阵的动态更新
  • 高效的GPU渲染优化

在这里插入图片描述

完整代码注释

<!DOCTYPE html>
<html lang="en">
<head><title>three.js webgl - indexed instancing (single box), interleaved buffers</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> - indexed instancing (single box), interleaved buffers<div id="notSupported" style="display:none">Sorry your graphics card + browser does not support hardware instancing</div></div><script type="importmap">{"imports": {"three": "../build/three.module.js","three/addons/": "./jsm/"}}</script><script type="module">import * as THREE from 'three';import Stats from 'three/addons/libs/stats.module.js';let container, stats;let camera, scene, renderer, mesh;const instances = 5000; // 实例数量let lastTime = 0;// 用于动画的四元数和矩阵const moveQ = new THREE.Quaternion( 0.5, 0.5, 0.5, 0.0 ).normalize();const tmpQ = new THREE.Quaternion();const tmpM = new THREE.Matrix4();const currentM = new THREE.Matrix4();init();function init() {container = document.getElementById( 'container' );// 初始化相机camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );// 初始化场景scene = new THREE.Scene();scene.background = new THREE.Color( 0x101010 );// 创建实例化几何体const geometry = new THREE.InstancedBufferGeometry();// 创建交错缓冲区(将位置和UV数据存储在一个数组中)// 每8个浮点数为一组:x,y,z,_,_,u,v,_// 这样的布局有利于内存对齐和GPU访问效率const vertexBuffer = new THREE.InterleavedBuffer( new Float32Array( [// Front- 1, 1, 1, 0, 0, 0, 0, 0,1, 1, 1, 0, 1, 0, 0, 0,- 1, - 1, 1, 0, 0, 1, 0, 0,1, - 1, 1, 0, 1, 1, 0, 0,// Back1, 1, - 1, 0, 1, 0, 0, 0,- 1, 1, - 1, 0, 0, 0, 0, 0,1, - 1, - 1, 0, 1, 1, 0, 0,- 1, - 1, - 1, 0, 0, 1, 0, 0,// Left- 1, 1, - 1, 0, 1, 1, 0, 0,- 1, 1, 1, 0, 1, 0, 0, 0,- 1, - 1, - 1, 0, 0, 1, 0, 0,- 1, - 1, 1, 0, 0, 0, 0, 0,// Right1, 1, 1, 0, 1, 0, 0, 0,1, 1, - 1, 0, 1, 1, 0, 0,1, - 1, 1, 0, 0, 0, 0, 0,1, - 1, - 1, 0, 0, 1, 0, 0,// Top- 1, 1, 1, 0, 0, 0, 0, 0,1, 1, 1, 0, 1, 0, 0, 0,- 1, 1, - 1, 0, 0, 1, 0, 0,1, 1, - 1, 0, 1, 1, 0, 0,// Bottom1, - 1, 1, 0, 1, 0, 0, 0,- 1, - 1, 1, 0, 0, 0, 0, 0,1, - 1, - 1, 0, 1, 1, 0, 0,- 1, - 1, - 1, 0, 0, 1, 0, 0] ), 8 );// 从交错缓冲区中提取位置和UV数据// 使用vertexBuffer,从偏移量0开始,每3个元素为一组作为位置数据const positions = new THREE.InterleavedBufferAttribute( vertexBuffer, 3, 0 );geometry.setAttribute( 'position', positions );// 使用vertexBuffer,从偏移量4开始,每2个元素为一组作为UV数据const uvs = new THREE.InterleavedBufferAttribute( vertexBuffer, 2, 4 );geometry.setAttribute( 'uv', uvs );// 设置索引数据(定义三角形面)const indices = new Uint16Array( [0, 2, 1,2, 3, 1,4, 6, 5,6, 7, 5,8, 10, 9,10, 11, 9,12, 14, 13,14, 15, 13,16, 17, 18,18, 17, 19,20, 21, 22,22, 21, 23] );geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) );// 创建材质const material = new THREE.MeshBasicMaterial();material.map = new THREE.TextureLoader().load( 'textures/crate.gif' );material.map.colorSpace = THREE.SRGBColorSpace;material.map.flipY = false;// 创建实例化网格mesh = new THREE.InstancedMesh( geometry, material, instances );// 为每个实例设置变换矩阵const matrix = new THREE.Matrix4();const offset = new THREE.Vector3();const orientation = new THREE.Quaternion();const scale = new THREE.Vector3( 1, 1, 1 );let x, y, z, w;for ( let i = 0; i < instances; i ++ ) {// 随机位置(在球体表面附近分布)x = Math.random() * 100 - 50;y = Math.random() * 100 - 50;z = Math.random() * 100 - 50;offset.set( x, y, z ).normalize();offset.multiplyScalar( 5 ); // 从中心向外偏移至少5个单位offset.set( x + offset.x, y + offset.y, z + offset.z );// 随机朝向x = Math.random() * 2 - 1;y = Math.random() * 2 - 1;z = Math.random() * 2 - 1;w = Math.random() * 2 - 1;orientation.set( x, y, z, w ).normalize();// 组合变换矩阵matrix.compose( offset, orientation, scale );// 设置实例矩阵mesh.setMatrixAt( i, matrix );}// 添加到场景scene.add( mesh );// 初始化渲染器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() {const time = performance.now();// 整体旋转mesh.rotation.y = time * 0.00005;// 计算增量时间const delta = ( time - lastTime ) / 5000;tmpQ.set( moveQ.x * delta, moveQ.y * delta, moveQ.z * delta, 1 ).normalize();tmpM.makeRotationFromQuaternion( tmpQ );// 更新每个实例的变换矩阵for ( let i = 0, il = instances; i < il; i ++ ) {mesh.getMatrixAt( i, currentM );currentM.multiply( tmpM ); // 应用增量旋转mesh.setMatrixAt( i, currentM );}// 标记矩阵需要更新mesh.instanceMatrix.needsUpdate = true;// 重新计算边界球体,确保视锥体剔除正确工作mesh.computeBoundingSphere();lastTime = time;// 渲染场景renderer.render( scene, camera );// 更新性能统计stats.update();}</script></body></html>

交错缓冲区技术解析

什么是交错缓冲区

交错缓冲区(Interleaved Buffer)是一种将不同类型的顶点数据(如位置、法线、UV坐标)存储在一个连续内存块中的技术。与将每种属性存储在单独的数组中相比,交错缓冲区有以下优势:

  1. 内存访问优化:GPU可以更高效地访问连续内存
  2. 缓存友好:减少内存碎片,提高缓存命中率
  3. 带宽利用率:减少内存带宽需求

在Three.js中,我们使用InterleavedBufferInterleavedBufferAttribute来创建和管理交错缓冲区。

交错缓冲区的实现

本示例中,我们创建了一个交错缓冲区,每8个浮点数为一组:

// 每8个浮点数为一组:x,y,z,_,_,u,v,_
// 这样的布局有利于内存对齐和GPU访问效率
const vertexBuffer = new THREE.InterleavedBuffer( new Float32Array( [...]), 8 );// 从交错缓冲区中提取位置和UV数据
const positions = new THREE.InterleavedBufferAttribute( vertexBuffer, 3, 0 ); // 从偏移0开始,每3个元素
const uvs = new THREE.InterleavedBufferAttribute( vertexBuffer, 2, 4 ); // 从偏移4开始,每2个元素

这种布局确保了数据在内存中是连续的,并且每个属性的起始位置和步长都被正确定义。

索引几何体的实例化渲染

本示例结合了索引几何体和实例化渲染两种技术:

  1. 索引几何体:通过索引数组定义三角形面,减少顶点数据冗余
  2. GPU实例化:在单次绘制调用中渲染多个实例,每个实例可以有不同的变换矩阵

通过InstancedMesh类,我们可以轻松实现这两种技术的结合:

// 创建实例化网格
mesh = new THREE.InstancedMesh( geometry, material, instances );// 为每个实例设置变换矩阵
for ( let i = 0; i < instances; i ++ ) {// 计算位置、旋转和缩放...matrix.compose( offset, orientation, scale );mesh.setMatrixAt( i, matrix );
}
性能优化与应用场景

交错缓冲区和实例化渲染特别适合以下场景:

  1. 大型场景:如城市、森林、粒子系统等
  2. 程序化生成内容:如地形、建筑等
  3. 数据可视化:如点云、3D图表等
  4. 游戏开发:大量相同模型的高效渲染

性能优化建议:

  1. 交错布局设计:合理安排数据布局,考虑内存对齐(通常4字节对齐)
  2. 批量更新:尽量批量更新实例数据,减少渲染状态切换
  3. 视锥体剔除:实现视锥体剔除,避免渲染不可见的实例
  4. LOD技术:对远处的实例使用简化模型或广告牌

在实际应用中,交错缓冲区和实例化渲染可以显著提高渲染性能,但也需要根据具体场景进行权衡和优化。

相关文章:

  • Spark,hadoop 集群的常用命令
  • http接口性能优化方案
  • 01-centos离线升级至almalinux
  • 键盘RGB矩阵与LED指示灯(理论部分)
  • 【Game】Powerful——Hero Trial(11)
  • RNN(循环神经网络)原理与结构
  • DeepPrep:深度学习提升神经影像预处理
  • 自主添加删除开机启动项
  • JVM对象分配与程序崩溃排查
  • C语言:深入理解指针(3)
  • 黑马k8s(四)
  • 面试篇:Spring MVC
  • 木马查杀篇—Opcode提取
  • C++ 与 Go、Rust、C#:基于实践场景的语言特性对比
  • Megatron系列——流水线并行
  • GPU SIMT架构的极限压榨:PTX汇编指令级并行优化实践
  • Ubuntu网络部署LNMP环境
  • 【笔试训练】给一个数组构建二叉树|从前序遍历与中序遍历构建二叉树|二叉树中的最大路径和
  • 用生活例子通俗理解 Python OOP 四大特性
  • 【2025最新】Vm虚拟机中直接使用Ubuntu 免安装过程直接使用教程与下载
  • 印称印巴军事行动总指挥同意将局势降级
  • 在地球另一端的交流,架起2万公里间更多共赢的桥梁
  • 洞天寻隐·学林纪丨玉洞桃源:仇英青绿山水画中的洞天与身体
  • 全国首例在沪完成,这项近视治疗手术不到10秒
  • 哥伦比亚总统称将在访华期间签署“一带一路”倡议意向书,外交部回应
  • 安顺市原副市长、市公安局原局长顾长华任贵州省民委副主任