如何用Three.js基于3D点(x,y,z)绘制非平面几何曲面?解决Shape平面化问题
问题根源分析
你遇到的核心问题很明确:THREE.Shape是专门用于2D路径的工具,它只会处理点的X/Y坐标,完全忽略Z轴值。哪怕你传入的是Vector3类型的点,它也会自动把Z轴丢弃,将所有点投影到XY平面上,所以最后生成的ShapeGeometry必然是平面的,不可能呈现3D曲面效果。
解决方案:双轨放样构建3D曲面
既然你已经有两条平行的闭合3D曲线(closedSpline和closedSpline1),我们可以通过双轨放样的方式,手动构建连接两条曲线的3D曲面。具体思路是:遍历两条曲线上的对应点,将每一组相邻的四个点(两条曲线上的当前点和下一个点)组成四边形(拆分为两个三角形),最终生成完整的网格几何体。
修改后的代码片段如下:
// 替换原来的track构建代码 const points0 = closedSpline.getPoints(100); const points1 = closedSpline1.getPoints(100); // 创建自定义几何体 const trackGeometry = new THREE.BufferGeometry(); const vertices = []; const indices = []; // 遍历每个分段,构建四边形面 for (let i = 0; i < points0.length; i++) { // 获取当前和下一个点(闭合曲线要处理首尾连接) const p0 = points0[i]; const p1 = points1[i]; const p2 = points0[(i + 1) % points0.length]; const p3 = points1[(i + 1) % points1.length]; // 将四个点的坐标加入顶点数组 vertices.push(p0.x, p0.y, p0.z); vertices.push(p1.x, p1.y, p1.z); vertices.push(p2.x, p2.y, p2.z); vertices.push(p3.x, p3.y, p3.z); // 添加两个三角形的索引(组成一个四边形) const baseIdx = i * 4; indices.push(baseIdx, baseIdx + 1, baseIdx + 2); indices.push(baseIdx + 2, baseIdx + 1, baseIdx + 3); } // 设置几何体属性 trackGeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); trackGeometry.setIndex(indices); trackGeometry.computeVertexNormals(); // 计算法向量,让光照正常生效 // 创建网格并添加到场景 const trackMaterial = new THREE.MeshLambertMaterial({ color: "yellow", side: THREE.DoubleSide }); const track = new THREE.Mesh(trackGeometry, trackMaterial); scene.add(track);
关键细节说明
- 确保两条曲线的采样点数一致(这里都是100),这样点才能一一对应,生成的曲面才会平滑。
- 使用
(i + 1) % points0.length处理闭合曲线的首尾连接,避免最后一段出现缺口。 - 调用
computeVertexNormals()非常重要,它会自动计算每个顶点的法向量,让MeshLambertMaterial的光照效果正确呈现曲面的起伏。 - 如果想要更平滑的曲面,可以适当提高采样点数(比如把100改成200),但会增加性能开销。
内容的提问来源于stack exchange,提问作者GAURANG KORANT
相关产品推荐
相关产品推荐

