Three.js renders unprocessed texture

With three.js, I am trying to create the scene where a plane becomes transparent as the camera moves away from it.

And I textured the plane object with the round map tile which is edited from the square image below.

complete_small
original

When I load the round image through ShaderMaterial the texture appears square like the original image.

The weird thing is it is rendered as intended when the image is loaded onto regular mesh material.

Could anyone tell me why three.js behaves this way? Also, how might I render round tile using shader while keeping its functionality to fade based on distance?

The full code is available here: tile with shader - CodeSandbox

The image data is not actually gone outside the circle, you have just set the alpha (transparent) component to zero. You need to discard transparent texels in the shader.

The simplest way to get this to work would be to use a transparent MeshBasicMaterial

const material = new THREE.MeshBasicMaterial({
  map: texture,
  transparent: true
});

Or you could use alpha test

const material = new THREE.MeshBasicMaterial({
  map: texture,
  alphaTest: 0.5
});

This will discard all texels with alpha < 0.5. To implement this in your own shader is easy, just add

if (texture.a < 0.5) discard;

Actually you don’t even have to do that, just using the texture directly in your fragment shader will already discard transparent pixels (as long as you set transparent: true on the shader material):

void main() {
  vec4 textureCol = texture2D(u_texture, vUv);

  gl_FragColor = textureCol;
}

However, it looks like you also want to work with the transparency inside the fragment shader. So you could do something like this:

void main() {
  vec4 textureCol = texture2D(u_texture, vUv);
   if (textureCol.a < 0.01) discard; // Start by discarding any transparent texels
   
   textureCol.a = .... // now you can do what you like with the non-transparent texels
  gl_FragColor = textureCol;
}
1 Like

Also answered on SO

1 Like