Hi everyone!
I’m working on an app that lets users design their own hoodies.
For this we have 3D models of different cuts that users can select from and customise (i.e. they don’t change the actual cut, just embellish the model).
The app is React-based (Next.js) and uses React Three Fiber
to render the model (glb
).
The Problem
I am a bit stuck when it comes to allowing the user to place text and images on the model.
First Approach: Textures
My initial approach was to:
- create a canvas
- turn that canvas into an image (using
toDataURL
) - turn the image into a texture (using
@react-three/drei
’suseTexture
hook) - pass the texture to the Model component and apply it as a (normal) map
Here is an example of what this looks like:
(Note that the beige part of the canvas is part of the texture. I’m uploading an image of a red square onto a beige background which is the hoodie’s color. The strange way the image flows on the model is probably due to the model’s mapping. Our designer is looking into it at the moment.)
But this is not very intuitive and doesn’t scale very well. The problems compound if the user wants to upload multiple images.
Second Approach: Decals
Next I tried to solve the problem with decals.
For this I set up the following component:
import { Decal } from '@react-three/drei'
const Embroidery = ({ imageTexture }) => {
return (
<Decal
scale={0.25}
debug
map={imageTexture}
position={[0, 0, -0.1]}
/>
)
}
export default Embroidery
For testing purposes I pass the smile face emoji from the decal example linked in the React Three Fiber
documentation to the useTexture
hook and pass that as my imageTexture
prop.
Then pass this component as a child to my model:
<mesh
castShadow
receiveShadow
geometry={nodes['Hoodie-Boxy'].geometry}
material={materials.Knit}
position={[0.01, 1.26, 0]}
rotation={[0, 3.05, 0]}
material-map={props.print}
material-roughnessMap={props.texture}
>
{props.embroidery}
</mesh>
But the decal only shows up as a semi-transparent yellow blob:
I tried several things to fix this, including:
- changing the position (in the decal)
- numerous changes in the material’s properties (though, to be honest, much of this was guessing)
- I tried the different syntaxes in the
drei
documentation, but this didn’t make much of a difference and I ended up with the above syntax for simplicity’s sake (if I understood everything correctly, thepolygonOffsetFactor
will be set automatically and parentmesh
’s surface will be used by default)
Now, after a few days of trying this (and several weeks trying to get the first approach to work) I’m somewhat at a loss as to how to proceed here. In my research on decals, I noticed that there seem to be instances where rendering on uneven surfaces can cause problems and I was wondering whether the hoodie’s surface might just be too uneven to render a decal on in principal, so I’m not even sure anymore if using decals is the right approach here.
Are there any obvious mistakes I made or am I maybe going into the wrong direction with this? Any input would be highly appreciated.
Thank you!