Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you load and display SVG graphics in three.js?

Tags:

three.js

svg

Consider, I have an SVG vector graphics file (logotype), which I want to load and display in three.js (with WebGL renderer).

What would be the recommended way to approach this?

It seems like I need to load the image and to create a geometry and a mesh from it.

I've managed to load the SVG document using the THREE.SVGLoader, but I can't find any relevant information on how to create a geometry/mesh from it further down the line.

function preload () {

  const svgLoader = new THREE.SVGLoader();

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

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

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

  });

}
like image 934
Slava Fomin II Avatar asked Oct 26 '25 04:10

Slava Fomin II


1 Answers

Texture

If you need svg only for texture purposes:

  1. Render svg image to canvas
  2. use that canvas as source of texture
  3. use texture in your scene...

Disclaimer I'm not the author of this code, I just fixed jsfiddle that I've found

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>

Mesh

If you would like to render svg as geometry I'll would suggest use of some libraries e.g. svg-mesh-3d

Example from docs of 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

Alternative options is to use blender to import svg, (optionally) tune geometry and export it to Three.js using Three.js Blender Export

like image 191
Bartosz Matuszewski Avatar answered Oct 28 '25 04:10

Bartosz Matuszewski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!