Best Way to Render Images (& Text) on Model? (Textures, Decals, etc.)

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:

  1. create a canvas
  2. turn that canvas into an image (using toDataURL)
  3. turn the image into a texture (using @react-three/drei’s useTexture hook)
  4. 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, the polygonOffsetFactor will be set automatically and parent mesh’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!

here are some examples to compare notes

and yes, i would definitively use drei/decal + drei/rendertexture + drei/text

ps, we made a shirt configurator a while ago, releasing it today or else it would just catch dust:

1 Like

Thank you @drcmda

Especially the shirt is really useful since that’s quite close to what I’m trying to build myself.

I studied all the links you posted, but still feel like the Decals in all the samples are more or less the same as they are in my own code, except that they’re not working in my case.

If anyone wants to have a look, I uploaded some of my code to CodeSandbox to replicate the issue there: Hoodie-Decal-Issue - CodeSandbox

Would it be possible to add more than one decal (user selected image) into the Tshirt?

As many as you can fit

yes
by multi material