Drawing a decal shows a UV seam

https://playground.babylonjs.com/#N10DXG#156 (Click on mesh to draw decals)

In threeJS, I used to resolve this issue by changing the sampling mode on the texture and in BabylonJS I thought it was texture.updateSamplingMode but that is not yielding any result unfortunately.

I’ve tried both RenderTargetTexture and the Texture sampling mode and still nothing.


the UV layout is a bit shattered. If you do it in 2 islands - outer hull and bottom, so the seams dont run over the surface, would that resolve the issue?
Best. WErner

It is split up deliberately to show this issue.

Not all UVs are joined together, especially for tiling, but in this case its an example to show the problem that occurs.

I see ;), sry for that missunderstanding.
We are in the mids of using decals, maybe I will learn something or experience the same issue.
Thx! Werner

The PG is throwing an error:

You have discontinuities in your uv map:

This shows the (u,v) coordinates of each pixel. If possible, you can use a mesh decal, which does not depend on (u,v) coordinates.

@carolhmj You should re-click on “start”, as there are some downloads that may not be ready the first time you browse the PG.

1 Like

If you test it out and try to draw the decal you can see there are seams, this occurs whenever the UVs are split into islands. It’s standard stuff.

I’ve been using this decal system now for 9 months and this is the only major setback on it. The other options (mesh decal) are not good unfortunately.

Usually you fix this with sampling mode and it only occurs when the UV is set up like this.

Does ThreeJS has a texture decal mode? Last time I looked, they only had mesh decal.
If they have texture decal mode, it would be interesting to know what they are doing in that case, because in my understanding it’s the discontinuity in uv space that leads to this rendering artifact.

You can improve things a little bit by setting the “nearest” sampling mode to the decal texture, but it won’t completely fix it:

1 Like

No I don’t think ThreeJS has a decal system like BabylonJS.

BabylonJS is a much more advanced engine with all these great features. What Three does have is a way to fix the seams on textures where the UVs on the mesh are separate islands.

Its either an issue on the decal texture itself, or the MeshUVSpaceRenderer, or the RenderTargetTexture or the albedoTexture the decal ends up in on the material.

I created another Playground build with an updated model that includes a baseColour texture.

The results conclude that the seams shown are actually the texture underneath the decal?

Decals have an alpha=0 background, so you will see the diffuse texture when there’s no decal color:


For me, the problem is when generating the decal texture, because we render in uv space. When there’s a discontinuity, we will render either in one island or in another one, but not in both. We would probably need to render some king of “thickness” to be sure that when the texture is read we get the right color (but I don’t know how that could be done).

1 Like

Do the standard textures include this 1 pixel UV seam “thickness” already? or are they handled in another way, but there must be something in the usual texture function that corrects the UV seams, surely?

Could it be possible to update the shader to fix this bug?

Also here is the threejs splatter decal example.


I don’t know how to do that, but maybe someone else will be able to find a way.

This example is using DecalGeometry, which is creating a new mesh.

Couldnt you just repeat the pixels when it comes to the UV edge.
Isnt this kind of the same task as for a “render to texture”. In content tools there is this “seam” option which can be defined sometimes to overfill the edges.

No, because we don’t know we are at an edge when we generate the decal texture. Maybe this post will help to understand better how this process works:

1 Like

So it should be possible with the meshUVSpaceRenderer Shader somehow.


precision highp float;

attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;

uniform mat4 projMatrix;

varying vec2 vDecalTC;




void main(void) {
    vec3 positionUpdated = position;
    vec3 normalUpdated = normal;



    vec4 worldPos = finalWorld * vec4(positionUpdated, 1.0);

    mat3 normWorldSM = mat3(finalWorld);

    vec3 vNormalW;

    #if defined(INSTANCES) && defined(THIN_INSTANCES)
        vNormalW = normalUpdated / vec3(dot(normWorldSM[0], normWorldSM[0]), dot(normWorldSM[1], normWorldSM[1]), dot(normWorldSM[2], normWorldSM[2]));
        vNormalW = normalize(normWorldSM * vNormalW);
            normWorldSM = transposeMat3(inverseMat3(normWorldSM));

        vNormalW = normalize(normWorldSM * normalUpdated);

    vec3 normalView = normalize((projMatrix * vec4(vNormalW, 0.0)).xyz);

    vec3 decalTC = (projMatrix * worldPos).xyz;
    vDecalTC = decalTC.xy;

    gl_Position = vec4(uv * 2.0 - 1.0, normalView.z > 0.0 ? 2. : decalTC.z, 1.0);


varying vec2 vDecalTC;

uniform sampler2D textureSampler;

void main(void) {
    if (vDecalTC.x < 0. || vDecalTC.x > 1. || vDecalTC.y < 0. || vDecalTC.y > 1.) {

    gl_FragColor = texture2D(textureSampler, vDecalTC);

This might also be relevant:

sounds quite nice but I am wondering how much it could bleed on other island ?

Also, it’s quite heavy because you have to make a new render pass and have another texture for the mask (having one texture per mesh that can receive a decal is already the main drawback of the technique)…