Search code examples
javascriptthree.jspoint-cloudsparticlesblending

Additive blending mode destroying colour in point material Three.js, is there a better way?


I'm trying to add a map to a point material that has a coloured texture in Three.js. I've tried using additive blending and the map attribute to achieve a rounded point as opposed to a square one but it nukes the colour of the texture and blends it with the white colour of the point. I'm wondering if there's a better way to blend the two so I can keep the particle shape but also the colour of the texture?

This is what the point looks like This is particle.png

let pointShape = new THREE.TextureLoader().load("./models/particle.png");
   
    m = new THREE.PointsMaterial({
      
      size: pointSize,
      map: pointShape,
      blending: THREE.AdditiveBlending,
      depthTest: false,
      opacity: 0.9,
      onBeforeCompile: shader => {
        shader.uniforms.tex = {value: new THREE.TextureLoader().load("./textures/earthlores.jpg")};
        shader.vertexShader = `
          varying vec2 vUv;
          ${shader.vertexShader}
        `.replace(
          `#include <begin_vertex>`,
          `#include <begin_vertex>
            vUv = uv;
          `
        );
        //console.log(shader.vertexShader);
        shader.fragmentShader = `
          uniform sampler2D tex;
          varying vec2 vUv;
          ${shader.fragmentShader}
        `.replace(
          `vec4 diffuseColor = vec4( diffuse, opacity );`,
          `
          vec3 col = texture2D(tex, vUv).rgb;
          col *= diffuse;
          vec4 diffuseColor = vec4( col, opacity );`
        );
        //console.log(shader.fragmentShader);
      }
    });
This is the code that applies the texture and particle to the point material.

The result of this code makes this washed-out, colour deprived globe. Globe but bad

Commenting out additive blending results in the correct colour but not the right point shape.

colour correct but shape of points is bad

Will I have to edit my blending mode using custom blending, change the shader or is there another way I'm entirely missing? I've tried the other blend modes and they don't seem to work, I'm not sure how to utilise custom blending correctly either so please explain it to me like an idiot when it comes to that haha I'd love to learn.

Any help is appreciated, thanks!


Solution

  • Ok turns out I've figured a solution out using custom blending. Using the add equation and alpha-factor as source/destination (linear interpolation), the two have been added together without adding the destination colour to the source colour. This has created lovely rounded points using the texture provided.

     m = new THREE.PointsMaterial({
          
          size: pointSize,
          map: pointShape,
          blending: THREE.CustomBlending,
          blendEquation: THREE.AddEquation,
          blendSrc: THREE.SrcAlphaFactor,
          blendDst:THREE.OneMinusSrcAlphaFactor,
          depthTest: false
          });

    Delicious circular points: enter image description here