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

如何在Three.js中对无填充的SVG路径进行挤出建模?

问题:如何对无填充SVG路径的边框进行挤出建模?

我有如下SVG文件:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="900" height="800">
      <path d="M 650,750  L 50,750  L 100,350  L 850,50  L 850,550  L 650,750" fill="none" stroke="black" stroke-width="3"  />
</svg>

当我尝试用ExtrudeGeometry渲染它时,得到了带有填充的效果,尽管SVG路径已设置fill="none",我期望仅渲染边框,但实际并非如此。

我使用的加载代码如下:

const svgResult = loader.parse(svgTxt);
svgResult.paths.forEach((path) => {
  const shapes = SVGLoader.createShapes(path);
  shapes.forEach((shape) => {
  const geom = new THREE.ExtrudeGeometry(shape, {
          bevelEnabled: true,
          bevelSize: 14,
          bevelThickness: 5,
          bevelSegments: 15,
          depth: 20,
  });

  const mesh = new THREE.Mesh(
          geom,
          new THREE.MeshPhysicalMaterial({
            color: "white",
          })
        );
   // 省略添加到场景等代码
  });
});

解决方案

核心问题在于SVGLoader.createShapes()会把闭合的SVG路径直接转换成用于填充的Shape对象,完全忽略fill="none"属性。要实现边框的挤出建模,需要把路径当作线条轮廓处理,而不是填充区域,有两种可行方法:

方法一:使用LineGeometry实现线条立体效果(适合简单线条)

如果不需要复杂的倒角,可直接用Line2系列API创建带宽度的线条,再通过额外处理实现厚度:

const svgResult = loader.parse(svgTxt);
svgResult.paths.forEach((path) => {
  // 提取SVG路径的顶点,转换为Three.js坐标系(y轴反向)
  const points = path.getPoints().map(p => new THREE.Vector3(p.x, -p.y, 0));
  
  // 创建LineGeometry并设置顶点
  const lineGeometry = new THREE.LineGeometry();
  lineGeometry.setPositions(points.flatMap(v => [v.x, v.y, v.z]));
  
  // 创建LineMaterial,设置线条宽度
  const lineMaterial = new THREE.LineMaterial({
    color: 0xffffff,
    linewidth: 3, // 对应SVG的stroke-width
  });
  lineMaterial.resolution.set(window.innerWidth, window.innerHeight); // 必须设置分辨率以保证宽度正确

  // 创建Line2对象并添加到场景
  const lineMesh = new THREE.Line2(lineGeometry, lineMaterial);
  scene.add(lineMesh);

  // 若需要挤出厚度,可复制LineGeometry并沿z轴偏移,手动连接成面(适合简单场景)
});

方法二:将描边转为闭合Shape后挤出(支持倒角等参数)

这种方法会把SVG的线条描边转换成闭合的轮廓Shape,再用ExtrudeGeometry挤出,完美适配你原有的倒角配置:

const svgResult = loader.parse(svgTxt);
svgResult.paths.forEach((path) => {
  // 获取SVG路径的描边宽度
  const strokeWidth = path.userData.style.strokeWidth || 3;

  // 将SVG路径转换为Three.js的Path对象(注意y轴反向)
  const threePath = new THREE.Path();
  const svgPoints = path.getPoints();
  if (svgPoints.length > 0) {
    threePath.moveTo(svgPoints[0].x, -svgPoints[0].y);
    svgPoints.slice(1).forEach(p => threePath.lineTo(p.x, -p.y));
    threePath.closePath();
  }

  // 生成描边的闭合轮廓Shape数组
  const strokeShapes = threePath.getStrokeShapes(strokeWidth);

  // 对每个轮廓Shape执行挤出
  strokeShapes.forEach((shape) => {
    const geom = new THREE.ExtrudeGeometry(shape, {
      bevelEnabled: true,
      bevelSize: 14,
      bevelThickness: 5,
      bevelSegments: 15,
      depth: 20,
    });
    const mesh = new THREE.Mesh(
      geom,
      new THREE.MeshPhysicalMaterial({ color: "white" })
    );
    scene.add(mesh);
  });
});

说明:Path.getStrokeShapes()方法会根据线条宽度生成内外两条闭合路径,组合成空心的轮廓Shape,挤出后就是你需要的边框立体效果,同时支持原代码中的倒角参数。


内容的提问来源于stack exchange,提问作者Mat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 08:05:38