SVG Icons - How to 'normalise'the size/origin of different sized geometries?

I’m very new to Three. I’m using SVG based ‘icons’ in my rendering. I am successfully constructing them, however I am failing when I try to ‘normalise’ them to the same size.

I find that when I position the icons, they do not align (they are from various icon repos and of different sizes).

My issue can be seen here. [https://observablehq.com/@samantha-uk/svg-icons]
(Seems to work in Chrome & Safari but not Firefox)

I believe the meat of the problem is in _createIconGeometryFromSVGPath
I would appreciate some advice.
My goal is that when I position icons, they will sit in the same bounding space so I can align them with other mesh elements I display.

1 Like

Hi,
Neat work!
Have you tried normalizing the svg icons somehow first before bringing them into three.js?

Using THREE.Box3(), you can find the scale factor for your objects to make fit in one size.
For example, like in this topic:

I did consider using https://github.com/lukem512/normalize-svg-coords but I failed to get it working. I struggle using some libraries as I’m coding in typescript and it moans (a lot! lol) at times.

I eventually did find a solution, I just needed to call center().

  private _createIconFromSVGPath(iconName: string): three.BufferGeometry {
    const _loader = new SVGLoader();

    // Parse the svg path to three.shapes.
    const _shapes = _loader
      .parse(`<path d="${this._getIconPath(iconName)}">`)
      .paths[0].toShapes(true);

    // Extrude the shapes into 3d geometry.
    const _shapeBufferGeometry: three.BufferGeometry[] = [];
    _shapes.forEach((shape: three.Shape) => {
      _shapeBufferGeometry.push(
        new three.ExtrudeBufferGeometry(shape, {
          depth: ICON_THICKNESS,
          bevelEnabled: false,
        })
      );
    });

    // Merge the seperate elements into one for performance gain.
    const _iconGeometry = BufferGeometryUtils.mergeBufferGeometries(
      _shapeBufferGeometry,
      true
    );
    // SVG y coordinates are the inverse of normal cartesian, so correct for this using rotation.
    _iconGeometry.applyMatrix4(new three.Matrix4().makeRotationX(Math.PI));

    // Normalise the size and center point  of the icon as different sources have different sizes.
    _iconGeometry.computeBoundingSphere();
    _iconGeometry.scale(
      10 / _iconGeometry.boundingSphere!.radius,
      10 / _iconGeometry.boundingSphere!.radius,
      1
    );
    _iconGeometry.center();

    // Cache the geometry.
    this._sharedIconGeometry[iconName] = _iconGeometry;
    this._sharedIconGeometry[iconName].name = iconName;

    return _iconGeometry;
  }
1 Like