You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:04:54