基于网格高度着色的Three.js实现方案咨询
当然可行!这在Three.js里是非常常见的高度可视化需求,完全可以实现类似附图的渐变着色效果。最优方案需要根据你的模型类型来选择,下面给你详细拆解:
核心思路
不管是连续网格还是离散的小立方体,核心逻辑都是提取模型的高度信息(通常是Y轴坐标),将高度值映射到颜色渐变区间,再把颜色应用到模型上。Three.js原生支持顶点颜色和实例化颜色两种方式,能高效实现这个需求。
最优实现方案
情况1:单个连续STL网格模型
如果你的STL是一个整体的连续网格(比如地形、雕塑类模型),最直接高效的方式是基于顶点高度计算顶点颜色,让Three.js自动插值实现平滑渐变:
- 计算高度范围:遍历模型所有顶点的Y坐标,找到最小和最大高度,用于后续归一化计算。
- 生成顶点颜色:将每个顶点的Y值归一到0-1区间,再映射到你想要的颜色渐变(比如从蓝色到红色),把颜色值存入几何体的
color属性。 - 配置材质:启用材质的
vertexColors: THREE.VertexColors,让模型使用顶点颜色渲染。
代码示例
import * as THREE from 'three'; import { STLLoader } from 'three/addons/loaders/STLLoader.js'; const scene = new THREE.Scene(); // 假设你已经设置了相机、渲染器等基础环境 const loader = new STLLoader(); loader.load('你的STL模型路径.stl', (geometry) => { // 处理顶点颜色 applyHeightColoring(geometry); // 创建支持顶点颜色的材质 const material = new THREE.MeshLambertMaterial({ vertexColors: THREE.VertexColors, side: THREE.DoubleSide // STL模型可能需要双面渲染 }); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh); }); function applyHeightColoring(geometry) { const positions = geometry.attributes.position.array; let minY = Infinity; let maxY = -Infinity; // 第一步:确定高度范围 for (let i = 0; i < positions.length; i += 3) { const y = positions[i + 1]; minY = Math.min(minY, y); maxY = Math.max(maxY, y); } const heightRange = maxY - minY; const colors = []; const color = new THREE.Color(); // 第二步:为每个顶点计算颜色 for (let i = 0; i < positions.length; i += 3) { const y = positions[i + 1]; // 归一化高度值到0-1 const normalizedHeight = (y - minY) / heightRange; // 用HSL颜色空间实现从蓝到红的渐变(可根据需求调整) color.setHSL(normalizedHeight * 0.66, 1, 0.5); // 将颜色RGB值存入数组 colors.push(color.r, color.g, color.b); } // 第三步:将颜色属性添加到几何体 geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); geometry.colorsNeedUpdate = true; }
情况2:由大量小立方体组成的体素模型
如果你的STL是由很多独立小立方体拼接而成的体素模型,推荐使用InstancedMesh来实现,它能大幅减少Draw Call,提升性能:
- 准备单个立方体的基础几何体。
- 收集所有立方体的位置信息,计算整体高度范围。
- 为每个实例设置位置和颜色:遍历所有立方体,用
setMatrixAt设置位置,setColorAt根据高度设置颜色。
代码示例
import * as THREE from 'three'; const scene = new THREE.Scene(); // 假设你已经从STL中提取了所有小立方体的位置数组cubePositions // 1. 创建基础立方体几何体和材质 const cubeGeo = new THREE.BoxGeometry(1, 1, 1); // 根据你的立方体尺寸调整 const material = new THREE.MeshLambertMaterial({ vertexColors: THREE.VertexColors }); // 2. 创建实例化网格 const instancedMesh = new THREE.InstancedMesh(cubeGeo, material, cubePositions.length); // 3. 计算高度范围 let minY = Infinity; let maxY = -Infinity; cubePositions.forEach(pos => { minY = Math.min(minY, pos.y); maxY = Math.max(maxY, pos.y); }); const heightRange = maxY - minY; const color = new THREE.Color(); const matrix = new THREE.Matrix4(); // 4. 为每个实例设置位置和颜色 cubePositions.forEach((pos, index) => { matrix.setPosition(pos.x, pos.y, pos.z); instancedMesh.setMatrixAt(index, matrix); // 计算颜色 const normalizedHeight = (pos.y - minY) / heightRange; color.setHSL(normalizedHeight * 0.66, 1, 0.5); instancedMesh.setColorAt(index, color); }); // 标记实例颜色需要更新 instancedMesh.instanceColor.needsUpdate = true; scene.add(instancedMesh);
补充说明
- 颜色渐变可以自定义:除了HSL,你也可以用RGB颜色数组做线性插值,比如
THREE.Color.lerpColors实现从0x0000ff到0xff0000的渐变。 - 如果需要更复杂的着色效果(比如高度阈值高亮),可以自定义顶点着色器,在GPU层面计算颜色,性能会更好。
内容的提问来源于stack exchange,提问作者emily
相关产品推荐
相关产品推荐

