Search code examples
three.jsglslshaderwebglfragment-shader

How To Customize Alpha Transparency in Augmented Fragment Shader of Three.js Material?


I'm extending the THREE.MeshStandardMaterial with onBeforeCompile to adjust some details of the shader. I got the vertex shader working fine, but I'm having trouble figuring out how to set the alpha/transparency on the fragment shader.

Here's the material definition:

const material1 = new THREE.MeshStandardMaterial({
    onBeforeCompile: (shader) => {
        shader.uniforms.time = { value: 0 };

        shader.fragmentShader = shaderData.fragment;

        shader.vertexShader = 'uniform float time;\n'
            + 'varying vec3 vPosition;\n'
            + shader.vertexShader;
        shader.vertexShader = shader.vertexShader.replace(
            '#include <begin_vertex>',
            shaderData.vertex
        );
        material1.userData.shader = shader;
    },
});

The particulars of that aren't too important, but you can see that I'm entirely replacing the fragment shader (temporarily, for troubleshooting).

All I did was copy the built-in fragment shader and started customizing it. For testing, I have something like this:

// Dozens of includes.
void main () {
    // Dozens more includes.
    gl_FragColor.a = 0.1;
}

By my logic, that should paint the pixel at 10% transparency. However, that's not what happens. The color does change, but it's not really blending in with the background:

Here is what the rendering looks with that line commented out:

Original rendering

And here is what it looks like with the line intact (supposedly 10% transparency):

Supposedly transparent

The color is decidedly different, but it's not really what I'd expect from 10% transparency. In fact, I can change it from "0.1" to "0.01" and it looks pretty much the same (it vanishes entirely at "0.001").

Is there some other mechanism that's controlling how this alpha transparency works?

For context, the rest of the fragment shader is here (this is the built-in fragment shader that I am attempting to customize): https://github.com/mrdoob/three.js/blob/master/src/renderers/shaders/ShaderLib/meshphysical.glsl.js#L62

EDIT: I created a simple demo here: https://codepen.io/min-width/pen/abxgXjx?editors=0010

You can rotate the box by dragging your mouse. Search the code for "//TODO: Check this out."

You'll see it's trying to adjust the opacity, but that it doesn't work as expected.

The end goal is to use an equation to adjust the opacity, but for now I'm just trying to get a fixed value working.


Solution

  • Just needed to add transparent: true to the material:

    return new THREE.MeshStandardMaterial({
        transparent: true,
        onBeforeCompile: (shader) => {
            shader.fragmentShader = getMyFragShader();
            shader.vertexShader = getMyVertShader();
        },
    });
    

    Thanks to the commenter who pointed this out!