Trying to get transparent color from png to be the color of the material

Good day.

I do have a .png with transparency, when I load as a texture in a mesh the transparent parts are transparent. My problem goes I need the transparent parts to be the color of the material and not transparent.

I was thinking a shader could help with that, since I’m already using a shader to merge two separate images into one for the material in another instance, but the problem I have now is, I want to use MeshLambertMaterial to fuse the color with the image and having some lights applied to the model, but I have no idea where to start replacing code using onBeforeCompile to get the result I need.

Please help :frowning:

1 Like

Wouldn’t simply setting transparent: false in the material help in this case :thinking: ? You can handle it with shaders ofc, but is it necessary at all.

If you don’t need alpha blending, it’s actually better to set the alphaTest property of the material to 0.5 in order to create an alpha cutout.

1 Like

Thanks, but then, how I get the color I gave to the material instead of been just transparent?

Um, your fiddle does not seem to work. According to the browser console, you can’t load the asset via the current URL.

I’m sorry for taking this long, here’s fixed: https://jsfiddle.net/dx32ba15/

Thanks

I did some digging around the code for the ShaderChunks and I dicovered the shader chunk for alphaTest: three.js/alphatest_fragment.glsl.js at 9694de0fb9d9e45f36b2943642d534365e6d5965 · mrdoob/three.js · GitHub

#ifdef ALPHATEST
      if ( diffuseColor.a < ALPHATEST ) discard;
#endif

I guess my question would be something among the lines of: How I can, instead of discard that pixel, give it alpha 1 and color white (Or the color of the material)? Because if I go diffuseColor.a = 1, the console.log at jsfiddle go kinda crazy. :frowning:

How about using two boxes? A complete white one and the other one with your texture:

By defining renderOrder, you can ensure that the textured box is always rendered after the white one.

Thanks a lot, but I found out how to do it eventually

new THREE.MeshPhongMaterial({
        map: texture,
        alphaTest: 0.7,
        color: 0xbbbbbb,
        specular: 0x000005,
        reflectivity: 0.3,
        side: THREE.DoubleSide, 
        onBeforeCompile: shader => {
            shader.fragmentShader = shader.fragmentShader.replace('#include <alphatest_fragment>', `
                if ( diffuseColor.a < ALPHATEST ) diffuseColor = vec4(vec3(0.733,0.733,0.733), 1.0);
            `);
        }
    });

The problem I have right now though, is the fact that vec3 should be what I assigned in color, but for the moment this works for me.

Thanks again

1 Like

Seems like a simple built-in option would be nice because drawing an extra mesh is a whole new GPU call and double the processing, and using alphaTest can leave sharp edges between the texture and non-texture areas (instead of a smooth gradient).

I have same issue, I used this code but not working for me.

const customMaterialPatch_3 = new THREE.MeshStandardMaterial({
color: 0xbbbbbb,
map: texturePatch,
side: THREE.DoubleSide,
alphaTest: 0.5,
needUpdate: true,
onBeforeCompile: shader => {
shader.fragmentShader = shader.fragmentShader.replace(’#include <alphatest_fragment>’, #ifdef ALPHATEST if ( diffuseColor.a > ALPHATEST ) diffuseColor = vec4(vec3(0,1,0.33), 1.0); #endif );
}

  });

Quotes and ALPHATEST to alphaTest.

const customMaterialPatch_3 = new THREE.MeshStandardMaterial({
color: 0xbbbbbb,
map: texturePatch,
side: THREE.DoubleSide,
alphaTest: 0.5,
needUpdate: true,
onBeforeCompile: shader => {
shader.fragmentShader = shader.fragmentShader.replace(
"#include <alphatest_fragment>",
"if ( diffuseColor.a > alphaTest ) diffuseColor = vec4(vec3(0,1,0.33), 1.0);");
}
});
1 Like

Thanks a lot Chaser,

I am willing to change my sleeve color to red in png transparent area, and logo to default color. I am sure there will be a easy way but I am new in this

my code for texture:
texturePatch = new THREE.TextureLoader().load(
./…/…/assets/img/3d/1/patch-01.png,
function (t) {
t.flipY = false;
}
);

Material code:
const customMaterialPatch_3 = new THREE.MeshStandardMaterial({
color: 0xe10912,
map: texturePatch,
side: THREE.DoubleSide,
alphaTest: 0.9,
needUpdate: true,
onBeforeCompile: shader => {
shader.fragmentShader = shader.fragmentShader.replace(
#include <alphatest_fragment>’,
‘if ( diffuseColor.a > alphaTest ) diffuseColor = vec4(vec3(0,1,0.33), 1.0);’
);
},
});

i dont know english very good.
'if ( diffuseColor.a < 0.9 ) diffuseColor = vec4(vec3(1,0,0), 1.0);'
image

1 Like

Thanks a Lot Chaser, it works for me :slight_smile:

1 Like