Fighting with decal z-fighting: I have found a solution but I cannot understand how to implement it

I’m making a tool that also places a logo on some 3D models by mouse click. I have no jurisdiction on the models that will be provided, I have just a sample to work with.
I’ve found that decal is the way to go, but I experienced an unexpected problem: z-fighting.
I imagine decal should be not so problematic as there are few complains about this issue but in my case it is making me lose lots of hours. I’ve tried the most common solutions (renderOrder, renderDepth …) but with no sensible result. This is how it looks (wireframe to show how the same logo should look)

The solution that worked for me is to move the decal mesh up of a 0.001, up… from the surface, so with a known surface orientation it works and I know it can be a good solution.

So my idea was this (the code is derived from the threejs decal example, but with only 1 decal mesh)

        this.position.copy(this.intersection.point);        
        const normalOffset = this.intersection.normal.clone();
        normalOffset.multiplyScalar(0.01);       
        this.position.add(normalOffset);
        const material = this.decalMaterial.clone();
        
        if (this.currentDecal) {
            this.viewer.currentModel.remove(this.currentDecal);
        }

        this.currentDecal = new THREE.Mesh(
            new DecalGeometry(this.intersection.mesh.object, this.position, this.orientation, this.size), 
            material
        );
       this.viewer.currentModel.attach(this.currentDecal);

then I save the position x,y,z in order to recreate the decal when the model is loaded in the products viewer but it doesn’t work even if doing something like this it works.

      // this.currentDecal.position.y+=0.001;
       this.currentDecal.position.z+=0.001;
        this.viewer.currentModel.attach(this.currentDecal);

So I think the intersection normal is not normal to the decal mesh, I made some trials with localToWorld and worldToLocal but there must be something I don’t understand…

You can fix this with material.polygonOffset.

material:
polygonOffset: true,
polygonOffsetFactor: -0.1,
polygonOffsetUnits: 4.0

Thank you, I already tried the most common solutions, also changing the near and far values of the camera etc… I don’t know why, but they all didn’t help, probably because the models are very small and the far value of the camera is 8, so I imagine precision space may not always be enough.

The only working solution that worked for me is the little offset from the surface I cannot make dependent on the orientation of the decal mesh

I understood…
this.position.add(normalOffset) is wrong as this just offsets the position given to new DecalGeometry to create the mesh :smiling_face:

So I ended up to collect also the normal in my data structure and add it (reduced) to the DecalGeometry generated mesh position.