如何在three.js中加载和显示SVG图形?

3
考虑一下,我有一个SVG矢量图形文件(标志),我想在three.js中加载和显示它(使用WebGL渲染器)。
应该如何处理呢?
看起来我需要加载图像,并从中创建几何体和网格。
我已经成功使用THREE.SVGLoader加载了SVG文档,但是我找不到任何相关信息来进一步创建几何体/网格。
function preload () {

  const svgLoader = new THREE.SVGLoader();

  svgLoader.load('images/logo.svg', svgDocument => {

    // @todo: create a geometry/mesh from svgDocument?

    // @todo: scene.add(logoMesh);

  });

}

@prisoner849 这个例子手动解析SVG路径。这是一种非常低级的方法。应该有更简单的方法。我使用three.js来避免首先进行这样的低级编程。 - Slava Fomin II
嗯...把transformSVGPath(pathStr)函数放在一个单独的脚本中并从那里使用真的很难吗?该函数返回THREE.ShapePath(),可以通过.toShapes()方法将其转换为THREE.Shape()数组,然后使用这些形状与THREE.ShapeGeometry()。非常简单。没有必要提到低级编程。 - prisoner849
@prisoner849,我想借用这个问题,因为您似乎有一些见解。我按照您所描述的做了所有事情,但是我不知道如何将ShapePath转换为LineSegment或类似物,因为我们的SVG实际上只是一个轮廓而不是实心图像。有什么想法吗? - xDreamCoding
@xDreamCoding 您可以在SO上创建另一个问题,或者在此处提供更多详细信息和一些实时代码示例(jsfiddle、codepen等):) - prisoner849
@prisoner849 [完成](https://discourse.threejs.org/t/simplest-method-of-displaying-an-svg-path-in-webglrenderer/)感谢您的任何帮助。 - xDreamCoding
显示剩余3条评论
1个回答

1

纹理

如果您只需要SVG作为纹理:

  1. 将SVG图像渲染到画布上
  2. 使用该画布作为纹理的来源
  3. 在场景中使用纹理...

免责声明:我不是这段代码的作者,我只是修复了我发现的jsfiddle

window.onload = () => {
  var mesh;
  var scene = new THREE.Scene();

  var camera = new THREE.PerspectiveCamera(50, 500 / 400, 0.1, 1000);
  camera.position.z = 10;

  var renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(500, 400);
  document.body.appendChild(renderer.domElement);

  var svg = document.getElementById("svgContainer").querySelector("svg");
  var svgData = (new XMLSerializer()).serializeToString(svg);

  var canvas = document.createElement("canvas");
  var svgSize = svg.getBoundingClientRect();
  canvas.width = svgSize.width;
  canvas.height = svgSize.height;
  var ctx = canvas.getContext("2d");

  var img = document.createElement("img");
  img.setAttribute("src", "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(svgData))) );

  img.onload = function() {
    ctx.drawImage(img, 0, 0);

    var texture = new THREE.Texture(canvas);
    texture.needsUpdate = true;

    var geometry = new THREE.SphereGeometry(3, 50, 50, 0, Math.PI * 2, 0, Math.PI * 2);
    var material = new THREE.MeshBasicMaterial({ map: texture });
    material.map.minFilter = THREE.LinearFilter;
    mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);
  };

  var render = function () {
      requestAnimationFrame(render);
      mesh.rotation.y += 0.01;
      renderer.render(scene, camera);
  };

  render();
}
<script src="https://threejs.org/build/three.min.js"></script>

<div id="svgContainer" style="width: 222px; height: 222px;">
  <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1">
    <rect width="200" height="200" fill="lime" stroke-width="4" stroke="pink" />
    <circle cx="125" cy="125" r="75" fill="orange" />
    <polyline points="50,150 50,200 200,200 200,100" stroke="red" stroke-width="4" fill="none" />
    <line x1="50" y1="50" x2="200" y2="200" stroke="blue" stroke-width="4" />
  </svg>
</div>

网格

如果您想将SVG渲染为几何图形,我建议使用一些库,例如svg-mesh-3d

来自svg-mesh-3d文档的示例:

    var loadSvg = require('load-svg')
    var parsePath = require('extract-svg-path').parse
    var svgMesh3d = require('svg-mesh-3d')

    loadSvg('svg/logo.svg', function (err, svg) {
      if (err) throw err

      var svgPath = parsePath(svg)
      var mesh = svgMesh3d(svgPath, {
        delaunay: false,
        scale: 4
      })
    })

Blender

另一个选项是使用Blender导入SVG文件,(可选)调整几何形状,并使用Three.js Blender Export将其导出到Three.js中。


谢谢您的回答。我想使用SVG作为网格。我尝试跟随svg-mesh-3d示例,但是svgMesh3d()返回的网格不正确。例如,它没有position属性,因此我无法设置其位置,当我将其添加到场景中时,它不会显示。我该如何为它分配材料? - Slava Fomin II
svg-mesh-3d 生成所谓的“单纯复合体”(simplicial complex),可以通过 three-simplicial-complex 将其转换为 Three.js 网格。关于为什么网格上的位置最佳,建议提出一个新问题。 - Bartosz Matuszewski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接