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 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):
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;
}