16.three官方示例+编辑器+AI快速学习webgl_buffergeometry_lines_indexed
本实例主要讲解内容
这个Three.js示例展示了如何使用**索引几何体(Indexed Geometry)**创建复杂的分形线条图案。通过递归算法生成科赫雪花(Koch Snowflake)曲线,并利用索引缓冲区优化顶点数据存储,实现高效的线条渲染。
核心技术包括:
- 索引几何体的创建与应用
- 递归算法生成复杂分形图案
- 顶点颜色的使用
- 高效线条渲染技术
完整代码注释
<!DOCTYPE html>
<html lang="en"><head><title>three.js webgl - buffergeometry - lines - indexed</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 - indexed</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;let parent_node;init();function init() {container = document.getElementById( 'container' );// 初始化相机camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 10000 );camera.position.z = 9000;// 初始化场景scene = new THREE.Scene();// 创建几何体和材质const geometry = new THREE.BufferGeometry();// 使用顶点颜色的线材质const material = new THREE.LineBasicMaterial( { vertexColors: true } );// 存储索引、位置和颜色数据const indices = [];const positions = [];const colors = [];let next_positions_index = 0;// 分形迭代次数const iteration_count = 4;// 旋转角度(用于科赫曲线)const rangle = 60 * Math.PI / 180.0;// 添加顶点到几何体function add_vertex( v ) {positions.push( v.x, v.y, v.z );// 为每个顶点设置随机颜色(偏蓝色调)colors.push( Math.random() * 0.5 + 0.5, Math.random() * 0.5 + 0.5, 1 );return next_positions_index ++;}// 科赫曲线递归生成函数function snowflake_iteration( p0, p4, depth ) {// 递归终止条件if ( -- depth < 0 ) {// p0已经添加,获取其索引const i = next_positions_index - 1;// 添加p4顶点add_vertex( p4 );// 添加一条从p0到p4的线indices.push( i, i + 1 );return;}// 计算线段的1/3和2/3点const v = p4.clone().sub( p0 );const v_tier = v.clone().multiplyScalar( 1 / 3 );const p1 = p0.clone().add( v_tier );// 计算向外凸起的点p2const angle = Math.atan2( v.y, v.x ) + rangle;const length = v_tier.length();const p2 = p1.clone();p2.x += Math.cos( angle ) * length;p2.y += Math.sin( angle ) * length;// 计算线段的2/3点const p3 = p0.clone().add( v_tier ).add( v_tier );// 递归处理四个子线段snowflake_iteration( p0, p1, depth );snowflake_iteration( p1, p2, depth );snowflake_iteration( p2, p3, depth );snowflake_iteration( p3, p4, depth );}// 生成雪花图案function snowflake( points, loop, x_offset ) {for ( let iteration = 0; iteration != iteration_count; iteration ++ ) {// 添加起始顶点add_vertex( points[ 0 ] );// 处理所有线段for ( let p_index = 0, p_count = points.length - 1; p_index != p_count; p_index ++ ) {snowflake_iteration( points[ p_index ], points[ p_index + 1 ], iteration );}// 如果是闭合图形,连接最后一个点和第一个点if ( loop ) snowflake_iteration( points[ points.length - 1 ], points[ 0 ], iteration );// 为下一次迭代平移输入曲线for ( let p_index = 0, p_count = points.length; p_index != p_count; p_index ++ ) {points[ p_index ].x += x_offset;}}}// 生成不同形状的科赫曲线let y = 0;// 线段科赫曲线snowflake([new THREE.Vector3( 0, y, 0 ),new THREE.Vector3( 500, y, 0 )],false, 600);y += 600;// 三角形科赫雪花snowflake([new THREE.Vector3( 0, y, 0 ),new THREE.Vector3( 250, y + 400, 0 ),new THREE.Vector3( 500, y, 0 )],true, 600);y += 600;// 矩形科赫雪花snowflake([new THREE.Vector3( 0, y, 0 ),new THREE.Vector3( 500, y, 0 ),new THREE.Vector3( 500, y + 500, 0 ),new THREE.Vector3( 0, y + 500, 0 )],true, 600);y += 1000;// 星形科赫曲线snowflake([new THREE.Vector3( 250, y, 0 ),new THREE.Vector3( 500, y, 0 ),new THREE.Vector3( 250, y, 0 ),new THREE.Vector3( 250, y + 250, 0 ),new THREE.Vector3( 250, y, 0 ),new THREE.Vector3( 0, y, 0 ),new THREE.Vector3( 250, y, 0 ),new THREE.Vector3( 250, y - 250, 0 ),new THREE.Vector3( 250, y, 0 )],false, 600);// 设置几何体的索引和属性geometry.setIndex( indices );geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );geometry.computeBoundingSphere();// 创建线段对象const lineSegments = new THREE.LineSegments( geometry, material );lineSegments.position.x -= 1200;lineSegments.position.y -= 1200;// 创建父对象parent_node = new THREE.Object3D();parent_node.add( lineSegments );// 添加到场景scene.add( parent_node );// 初始化渲染器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 = Date.now() * 0.001;// 旋转整个场景parent_node.rotation.z = time * 0.5;// 渲染场景renderer.render( scene, camera );// 更新性能统计stats.update();}</script></body>
</html>
索引几何体技术解析
什么是索引几何体
索引几何体(Indexed Geometry)是一种优化的顶点数据存储方式,它将共享的顶点只存储一次,通过索引数组来引用这些顶点。与非索引几何体相比,索引几何体有以下优势:
- 减少内存占用:对于有大量共享顶点的模型,可显著减少顶点数据量
- 提高渲染效率:减少GPU需要处理的顶点数量
- 简化模型数据:使模型数据结构更加清晰
在Three.js中,我们通过geometry.setIndex()
方法来设置索引数据。
科赫雪花算法
科赫雪花是一种经典的分形曲线,其构造方法如下:
- 基本线段:从一条线段开始
- 分割线段:将线段分成三等份
- 替换中间段:将中间的三分之一线段替换为一个等边三角形的两条边
- 递归处理:对新生成的每条线段重复上述过程
本示例中的递归函数snowflake_iteration
实现了这一过程:
function snowflake_iteration( p0, p4, depth ) {// 递归终止条件if ( -- depth < 0 ) {// 添加线段return;}// 计算线段的1/3和2/3点// 计算向外凸起的点p2// 递归处理四个子线段
}
顶点颜色的使用
本示例使用了顶点颜色来为线条添加变化:
- 材质设置:使用
LineBasicMaterial
并启用vertexColors: true
- 顶点颜色数据:为每个顶点设置RGB颜色值
- 插值效果:GPU会自动在两个顶点之间进行颜色插值
// 设置材质
const material = new THREE.LineBasicMaterial( { vertexColors: true } );// 添加顶点时设置颜色
function add_vertex( v ) {positions.push( v.x, v.y, v.z );colors.push( Math.random() * 0.5 + 0.5, Math.random() * 0.5 + 0.5, 1 );return next_positions_index ++;
}
性能优化与应用场景
索引几何体特别适合以下场景:
- 复杂网格模型:如角色模型、建筑模型等
- 共享顶点的几何体:如平面、立方体等
- 大量重复图案:如本示例中的分形图案
性能优化建议:
- 合并几何体:对于静态场景,考虑将多个几何体合并为一个以减少绘制调用
- 使用BufferGeometry:相比普通Geometry,BufferGeometry性能更高
- 优化索引数据:合理安排顶点顺序,提高缓存命中率
- 控制递归深度:如本示例中的迭代次数,过深的递归会导致顶点数量爆炸式增长
索引几何体是Three.js中一项重要的优化技术,在处理复杂模型和大量线条时能带来显著的性能提升。