DEV Community

Cover image for Convert SVG into a 3D figure using React Three.js Fiber
Aiaru / 아야루
Aiaru / 아야루

Posted on

Convert SVG into a 3D figure using React Three.js Fiber

In this post, I will show you how to create a custom 3D figure using Three.js and integrate it into a React.js website.
Source code: github.

1. Get an SVG of the Figure

The first step is to create or download an SVG (Scalable Vector Graphics) of the shape you want to turn into a 3D object. For this example, I will create a 3D figure based on a traditional red Kazakh ornament. I downloaded the image and converted it into an SVG. You can easily convert any image into SVG format using free tools like online converters.
converting image

2. Install Dependencies

Before we begin, ensure you have created a React app and placed the downloaded SVG file in the /public folder.

We will be using Three.js Fiber, a React renderer for Three.js. It’s simple to use, especially if you're already familiar with Three.js.

Install the necessary packages with the following command:

npm install three @react-three/fiber @react-three/drei
Enter fullscreen mode Exit fullscreen mode

3. Create the 3D Figure

We’ll use the useLoader hook to load the SVG file (/oyu.svg). The SVGLoader parses the SVG and returns data that we can use to generate 3D shapes. The SVG paths are then converted into shapes, and using flatMap, we get a flat array of all shapes. Finally, by adding depth, the shape is extruded into a 3D figure.

// /src/components/Figure.js file
import React from "react";
import { useLoader } from "@react-three/fiber";
import * as THREE from "three";
import { SVGLoader } from "three/examples/jsm/loaders/SVGLoader";

const Figure = () => {
  const svgData = useLoader(SVGLoader, "/oyu.svg");

  const shapes = svgData.paths.flatMap((path) => path.toShapes(true));

  const geometry = new THREE.ExtrudeGeometry(shapes, {
    depth: 10,
  });
  geometry.center();

  return (
    <mesh geometry={geometry} scale={0.07}>
      <meshPhongMaterial attach="material" color="red" />
    </mesh>
  );
};

export default Figure;
Enter fullscreen mode Exit fullscreen mode

Play with scale and find the appropriate value for your figure. I used 0.07 because the figure was too big as an example.

Now we have the 3D figure, but we need a canvas to display it and some lighting to visualize it.

4. Create a canvas

Create a component called CustomCanvas where we will place the 3D figure. The canvas will include ambient and directional lights to illuminate the figure. Additionally, I’ve added OrbitControls to enable rotating and zooming around the 3D figure. Lights were chosen as an example, you can play with values.

<Canvas camera={{ position: [0, 0, 20] }}>
    <OrbitControls enableZoom={true} enablePan={true} />
    <ambientLight intensity={0.5} />
    <directionalLight position={[10, 10, 5]} intensity={1} />
    <Figure position={[0, 0, 0]} />
  </Canvas>
Enter fullscreen mode Exit fullscreen mode

Since we're loading the SVG, it's a good idea to wrap the canvas in Suspense, allowing users to see a loading message while the figure is being prepared. Here's the updated canvas:

// /src/components/Canvas.js file
import { Canvas } from "@react-three/fiber";
import { OrbitControls, Text } from "@react-three/drei";
import Figure from "./Figure";
import { Suspense } from "react";

const Loading = () => {
  return (
    <Text>
      Loading...
    </Text>
  );
};

const Scene = () => (
  <>
    <OrbitControls enableZoom={true} enablePan={true} />
    <ambientLight intensity={0.5} />
    <directionalLight position={[10, 10, 5]} intensity={1} />
    <Figure position={[0, 0, 0]} />
  </>
);

export const CustomCanvas = () => (
  <Canvas camera={{ position: [0, 0, 20] }}>
    <Suspense fallback={<Loading />}>
      <Scene />
    </Suspense>
  </Canvas>
);
Enter fullscreen mode Exit fullscreen mode

5. Integrate the Canvas into Your App

Now, let's include the CustomCanvas in your main App.js file.

import "./App.css";
import { CustomCanvas } from "./components/Canvas";

function App() {
  return (
    <div className="App">
      <div className="main">
        <CustomCanvas />
      </div>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Finally, add some basic styling for your canvas in App.css to ensure it takes up the full screen.

...

.main {
  height: 100vh;
  width: 100vw;
  overflow: hidden; //adjust for your needs
}
Enter fullscreen mode Exit fullscreen mode

After completing the above steps, your 3D figure should be displayed, and it will look something like this:
result

tilted result

Feel free to play with depth and customize the material as you wish! Hope it was helpful~

The source code can be found here.

Top comments (0)