Decals and React

Hello,

I’ve been stuck for days, and couldn’t figure it out.

I’m trying to put a small graphic (as in Team Badge, and player’s number at the back) onto a basketball jersey. I can’t use Texture as anything I specified will cover the whole jersey.

From this https://threejs.org/examples/#webgl_decals I believe decal is the way to go. What I don’t understand is that I need to shove a Mesh into the Constructor of DecalGeometry. What kind of mesh should I use? Not the mesh of the basketball jersey?

Is this the right step?

  1. get the upload of PNG from browser
  2. create DecalGeometry using an arbitrary Geometry (may be a square?)
  3. specify some material (I want it to be transparent)
  4. create a new mesh using the above DecalGeometry and material (I can’t figure out what values to use for the decal projector…)
  5. load the PNG into a Texture
  6. load the basketball jersey’s Mesh
  7. merge the basketball jersey’s Mesh with the new Mesh containing the DecalGeometry

Also, how do I control the size of the graphic inside the DecalGeometry? As the graphic has color, I’m not sure if the basketball jersey’s color will affect the graphic and make the graphic look broken?

Thanks a lot!

You have to apply the mesh that should receive the decal. So in your case, it’s indeed the basketball jersey.

Use the fourth parameter of DecalGeometry’s constructor. It defines the size of the decal projector which will affect the final size of the projected texture.

Very much appreciate your pointer @Mugen87 .

The red patch (nodes.MatShape_34889_Node in code) is where I want to place my Team Badge graphic.

Screenshot 2022-06-21 at 6.53.38 PM

Regarding the forth parameter, I have no idea what number to start off, as the graphic won’t show up properly at first load. Should I use 0,0,0 or 1,1,1? Or something else?

Taking your advice, I am implementing it using the code:

    let graphicMaterial;
    const texmgr = new THREE.TextureLoader();
    const abc = texmgr.load('me2.jpg', (texture) => {
        graphicMaterial = new THREE.MeshBasicMaterial({
            texture,
        });
    }, () => {} , () => {});

...

<mesh castShadow receiveShadow geometry={nodes.MatShape_34889_Node.geometry}>
        <meshBasicMaterial attach="material" map={graphicMaterial} />
</mesh>

The code compiles fine. When it runs, graphicMaterial is always undefined. IDE can break into it, run it.
Always Undefined.

Could react-three/drei 8.10.6 and react-three/fiber 7.0.26 clash with three r138?

Hence my mesh never shows the graphic me2.jpg.

So close, yet so far away.

This is crazy…

fiber is just a different way to express three, it won’t clash or depend on any particular version of threejs. could you post a simplified snippet of how you use decals vanilla? i have never used them to understand what you’re struggling with.

@drcmda thanks for your help!

I’ve prepared something in codesandbox.io.

Using a standard BoxGeometry, enabling the texture map will make the square disappear. I’m not sure if it is:

  • black in color
  • too close to see?
  • too far to see?

Cloning the code and running it locally has the same result. But all variables are properly assigned and have proper values when checked inside WebStorm.

I really hope someone can help or share some advice.

this isnt a decal?

  const texture = new THREE.TextureLoader().load("me.png");
  const decalMaterial = new THREE.MeshBasicMaterial();
  decalMaterial.map = texture;
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  sphere = new THREE.Mesh(geometry, decalMaterial);

just a textured mesh, if the texture loads or not. to me it should not load because the path is wrong. static files belong into /public.

You are right, it isn’t decalgeometry.

The reason is that I played with decalgeometry and couldn’t get it to work, so I need to get back to the very very basics of threejs.

Thx for the pointer, and I’ll try that.

Much much appreciated.

Thank you thank you @drcmda

I want to jump straight to the task I need to test, and it is to constrain the size of the Texture laid onto Mesh.

From the look of the official doc MeshBasicMaterial, Material, the variable list

I can’t figure out how to achieve this. Should I use Material.clippingPlanes, or variables in .map? Or I should use the right sized geometry first, then merge this geometry to a larger one?

tbh i would do that with real decals.

otherwise, in react terms setting a texture and stretching it looks like this:

function Foo() {
  const texture = useTexture("/me.jpg") // the file should be stored as /public/me.jpg
  texture.wrapS = texture.wrapT = THREE.RepeatWrapping
  texture.repeat.set(4, 4)
  return (
    <mesh>
      <boxGeometry />
      <meshBasicMaterial map={texture} />
    </mesh>
  )
}

@drcmda You know, I cannot express how grateful I’m for your advice. After going through countless number of methods, the texture is at least being displayed!

Instead of going through lots of hoops to get the texture to display on my object (the red square in my first post), and from your last post, I realise I don’t even need to use decalgeometry!

The reason is because I’ve already prepared the square using my 3D tool, and I simply need to lay the texture into the geometry, and that’s it (kind of)! I’m using react’s logo here.

The key is to use:
texture.wrapS and texture.wrapT

Without them, no texture will be displayed. I can just barely see the black square.

My new code is:

texture.mapping = THREE.UVMapping;
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;          // has effect
texture.rotation = 0;                     // has effect
texture.flipY  = false;                 // has effect
texture.repeat.set(1,1);                // has effect

const material = new THREE.MeshPhongMaterial( {map: texture});

Do you know where to set the size of the graphic laid in the texture? Is it in TextureLoader(), , or in Material?

Much much thx!

Would decal solve the grid of image issue?