Abdullah Nadeem
Posted on August 17, 2023
In this article, we will learn how to add a picture as a texture to a 3D object in a React application. We will use @react-three/fiber
to accomplish this feat.
We will be assuming you already have a basic understanding of React and a new React application set up.
Step 1: Install Required Packages
Let's install the dependencies first. Run the following command in your terminal (make sure you are in the root directory of your project):
npm install three @react-three/fiber @react-three/drei
Here, three is the base library that react-three-fiber uses to create and render the 3D scene. @react-three/drei is a helper library for react-three-fiber that provides a set of reusable components and functions.
Step 2: Setup the Canvas
Now, import the Canvas
from @react-three/fiber in your React component.
import { Canvas } from '@react-three/fiber';
Use the Canvas inside return like so:
const ShapeCanvas = () => {
return (
<Canvas frameloop="demand">
</Canvas>
);
};
The frameloop
prop set to demand
is telling react-three-fiber to only re-render when state changes occur.
Step 3: Render a 3D Shape
Let's make another component and name it Shape
. We will use this to render a 3D model and use it inside our Canvas
.
We first use the Float
component from @react-three/drei to give our model a floating effect. Import Float
like so:
import { Float } from '@react-three/drei';
Inside the return
statement, write:
<Float speed={1.75} rotationIntensity={1} floatIntensity={2}></Float>
speed
refers to the animation speed.rotationIntensity
is the XYZ rotation intensity.floatIntensity
is the Up/Down float intensity.
We'll now use a mesh
component which is a low-level react-three-fiber component used to create and manipulate 3D objects. Inside Float
, write:
<mesh castShadow receiveShadow scale={1.75}></mesh>
We have allowed the mesh to cast and receive shadows and set its scale according to our use case.
A mesh
is usually composed of a geometry and a material. So let's add these inside our mesh
.
We will use an icosahedron
geometry as our shape to render. Inside mesh
, write:
<icosahedronGeometry args={[1, 1]} />
The icosahedron is a polyhedron with 20 identical equilateral triangular faces. The args={[1, 1]} prop specifies the radius and detail of the icosahedron.
Now, add a material inside mesh
like so:
<meshStandardMaterial color="#fff8eb" polygonOffset polygonOffsetFactor={-5} flatShading />
color
is used to specify a color for the material that will be used on our geometry.polygonOffset
andpolygonOffsetFactor
properties are used to avoid an artifact known as z-fighting, where two faces occupy the same space and create a flickering effect.flatShading
set to true means that the material will have a sharp and flat look instead of the default smooth one.
The Shape
component now looks like this:
const Shape = () => {
return (
<Float speed={1.75} rotationIntensity={1} floatIntensity={2}>
<mesh castShadow receiveShadow scale={1.75}>
<icosahedronGeometry args={[1, 1]} />
<meshStandardMaterial color="#fff8eb" polygonOffset polygonOffsetFactor={-5} flatShading />
</mesh>
</Float>
);
};
Now use this in ShapeCanvas
:
const ShapeCanvas = () => {
return (
<Canvas frameloop="demand">
<Shape />
</Canvas>
);
};
Right now, we can see a dark shape in our browser:
Does this mean we did something wrong? Not really! We just need to add some lights to the scene to see our 3D shape clearly. So let's do that.
There are multiple options for us to add lights in a scene which you can explore here.
For now, we will use ambientLight
and directionalLight
. Write the following lines above the mesh
.
<ambientLight intensity={0.25} />
<directionalLight position={[0, 0, 0.05]} />
We have adjusted the intensity
and position
props for the lights according to our need. Our 3D shape now looks like this:
Step 4: Add an Image as Texture to the Shape
To use an image as texture on our shape, we will use the useTexture
hook from @react-three/drei
. This hook is used to load one or several textures asynchronously. A texture, in this context, is essentially an image that gets mapped onto the surface of a 3D model. We use the hook as follows:
const [texture] = useTexture([threejs]);
threejs
is just an svg
that can be imported in our component.
We now use Decal
from @react-three/drei to map the texture onto our model.
<Decal position={[0, 0, 1]} rotation={[2 * Math.PI, 0, 6.25]} scale={1} map={texture} flatShading />
position
determines where the decal is located relative to the origin of the object it's applied to.rotation
determines the rotation of the decal around the x, y, and z axes in radians.scale
determines the size of the decal.map
specifies the texture/image to be used as the decal.flatShading
does the same thing it does to ourmaterial
as explained before.
Our Shape
component now looks like this:
import { Decal, Float, useTexture } from '@react-three/drei';
import { threejs } from '../../assets';
const Shape = () => {
const [texture] = useTexture([threejs]);
return (
<Float speed={1.75} rotationIntensity={1} floatIntensity={2}>
<ambientLight intensity={0.25} />
<directionalLight position={[0, 0, 0.05]} />
<mesh castShadow receiveShadow scale={1.75}>
<icosahedronGeometry args={[1, 1]} />
<meshStandardMaterial color="#fff8eb" polygonOffset polygonOffsetFactor={-5} flatShading />
<Decal position={[0, 0, 1]} rotation={[2 * Math.PI, 0, 6.25]} scale={1} map={texture} flatShading />
</mesh>
</Float>
);
};
And that's all we need to add an image as a texture to our 3D object.
Step 5: Adding Interactivity
We can finally add some interactivity to make it more fun by using OrbitControls
from @react-three/drei. In the ShapeCanvas
component, import OrbitControls
from @react-three/drei
and use it like this:
const ShapeCanvas = () => {
return (
<Canvas frameloop="demand">
<OrbitControls enableZoom={false} enablePan={false} />
<Shape />
</Canvas>
);
};
This will disable the zooming and panning of our 3D shape but will allow us to rotate it using our cursor.
Conclusion
In this article, we dove deep into integrating 3D objects within a React application using @react-three/fiber
. We started from setting up a basic 3D canvas, progressing to rendering a 3D shape, and finally applying a textured image onto it. By adding the OrbitControls, we also introduced a layer of interactivity, letting users rotate the object. The combination of React with 3D holds vast potential, setting the stage for richer web interactions and experiences and @react-three/fiber
is just the right place to start for you.
Posted on August 17, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.