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.
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
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;
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>
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>
);
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;
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
}
After completing the above steps, your 3D figure should be displayed, and it will look something like this:
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)