0

I have a Three.js Points object that contains data to display a bunch of points in the 3D space. I want to dynamically make some points invisible, but not sure how.

The material is a PointsMaterial. xyz data is stored in pointsObj.geometry.attributes.position.array and color data is stored in pointsObj.geometry.attributes.color.array, but I'm not sure if it's possible to alter things like alpha value or visibility of individual points (I can make all the points invisible, but this is different)

Does anyone know if this is possible?

Peter
  • 33
  • 6
  • Three.js doesn't support individual sizes or individual opacities for the default `PointsMaterial`. But it could be achieved if you make your custom `ShaderMaterial`. So the answer depends... are you comfortable writing shader code? – M - Jan 31 '23 at 17:42
  • See https://stackoverflow.com/a/12344288/1461008 and https://stackoverflow.com/a/67892506/1461008 – WestLangley Jan 31 '23 at 20:47

1 Answers1

0

Every point must have color.array, you can modify directly.

var colors = pointsObj.geometry.attributes.color.array;

for (var i = 0; i < colors.length; i += 4) {
  if (shouldPointBeInvisible(i)) { //<-- not implemented
    colors[i + 3] = 0; // Set alpha value to 0 to make the point invisible
  }
}

pointsObj.geometry.attributes.color.needsUpdate = true;

-- Here with a shader material maybe:

var material = new THREE.ShaderMaterial({
  uniforms: {
    visibility: { value: 1.0 }
  },
  vertexShader: `
    uniform float visibility;
    varying vec3 vColor;
    
    void main() {
      vColor = color;
      vColor.a *= visibility;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    varying vec3 vColor;
    
    void main() {
      gl_FragColor = vec4(vColor, 1.0);
    }
  `
});

pointsObj.material = material;

...

if (shouldPointBeInvisible(i)) {
  pointsObj.material.uniforms.visibility.value = 0.0;
} else {
  pointsObj.material.uniforms.visibility.value = 1.0;
}

-- And another solution with PointsMaterial:

var material = new THREE.PointsMaterial({
size: 1,
transparent: true,
opacity: 1.0,
uniforms: {
visibility: { value: 1.0 }
},
vertexShader: `
uniform float visibility;
varying vec3 vColor;
oid main() {
  vColor = color;
  vColor.a *= visibility;
  gl_PointSize = size;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

, fragmentShader: varying vec3 vColor;
`
});

pointsObj.material = material;

...

if (shouldPointBeInvisible(i)) {
pointsObj.material.uniforms.visibility.value = 0.0;
} else {
pointsObj.material.uniforms.visibility.value = 1.0;
}
  • I think the `color` attribute is a vec3 type without alpha. So when modifying `colors[i + 3]`, you’re simply changing the red channel of the subsequent vertex. – M - Jan 31 '23 at 15:46
  • I ve edited my answer with a shader material, maybe it will works for u ! – Christophe Van Beneden Jan 31 '23 at 16:18
  • @ChristopheVanBeneden thank you! Is there a way to do this with a PointsMaterial instead of ShaderMaterial? I'm not sure how to use AlphaMap or if that's even useful here – Peter Jan 31 '23 at 17:06
  • @Peter I'd be wary of following any of these suggestions. `vColor` is a vec3, so `vColor.a` is invalid. The answer with `PointsMaterial` also wouldn't work because that material doesn't accept any of `uniforms`, `vertexShader`, or `fragmentShader` properties. Finally, `visibility` is a `uniform`, so it would apply to every point equally, which is exactly the problem you're trying to solve. I'm not sure where Christophe is getting these answers from. – M - Jan 31 '23 at 17:49