0
votes

I use ShaderMaterial to create point cloud with attribute based size and opacity. I also need to texture map. The problem is that texture is rendered without transparency. Looks like each texture pixel color is blended somehow with background color (white in this case); How to avoid this this?

enter image description here

I use svg texture:

<div id="circle-texture" style="width: 0; height: 0; display: none">
    <svg width="32" height="32" xmlns="http://www.w3.org/2000/svg" version="1.1">
        <circle cx="16" cy="16" r="13" stroke="none" fill="white" fill-opacity="1" />        
    </svg>    
</div>

Here is my fragment shader:

<script type="x-shader/x-fragment" id="point-cloud-fragment-shader">

...  

uniform sampler2D texture;   

varying vec3 vColor;

varying float vOpacity;   

#include <clipping_planes_pars_fragment>

void main() {

    #include <clipping_planes_fragment>

    vec3 outgoingLight = vec3( 0.0 );

    vec4 diffuseColor = vec4( diffuse, vOpacity );  

    if (enableTexture) {            
        vec4 mapTexel = texture2D( texture, gl_PointCoord );            
        diffuseColor *= mapTexelToLinear( mapTexel );
    }

    diffuseColor.rgb *= vColor;

    outgoingLight = diffuseColor.rgb;
    gl_FragColor = vec4( outgoingLight, diffuseColor.a );
}

Discarding fixes if:

if ( gl_FragColor.a < 0.001 ) discard;

But is it possible without discarding? (with custom blending or something else) I've played with custom blending but without success so far.

enter image description here

1
Discarding fragments in the shader is definitely a valid approach since it's the same what three.js does when configuring Material.alphaTest. Can you please demonstrate your progress of work as a live example that shows your custom blending?Mugen87
@Mugen87 Thanks but why the discard condition works (alpha exists and it is small), but I don't see any transparency (alpha output) without discard?SalientBrain
Have you set the transparent property of your shader material to true?Mugen87
@Mugen87 Yes, sureSalientBrain
@SalientBrain Try material.depthWrite = false and points.renderOrder = 999;WestLangley

1 Answers

0
votes

The setup that works when dealing with partially-transparent point-clouds is to turn transparent: true, depthTest: false and a blending mode if necessary. Additive or multiplicative blending look nice, depending on your use-case, and it removes the need to sort the depth of your sprites, since blending removes the need to place a color "in front" of the other:

const spriteMat = new THREE.ShaderMaterial({
    uniforms: {
        // List of uniforms
    },
    vertexShader: spriteVert,
    fragmentShader: spriteFrag,
    blending: THREE.AdditiveBlending,
    depthTest: false,
    transparent: true
});

Turning transparent: true respects the alpha channel in your fragment shader, so you'll no longer need to discard pixels.