17

I am trying to vary the opacity of particles as a function of their distance from a plane.

This issue describes my problem, and the answer a year ago was essentially "you can't". Opacity is apparently a parameter of a material, not an element, and hence individual particle opacity is not possible.

Has anything changed, is there any way I could achieve this? If individual particle colouring is possible, I imagine this isn't out of reach.

Cheers

WestLangley
  • 102,557
  • 10
  • 276
  • 276
user593062
  • 1,593
  • 4
  • 15
  • 24

2 Answers2

32

EDIT - This answer shows how to set per-point opacity using a custom ShaderMaterial. See https://stackoverflow.com/a/67892506/1461008 for an approach using PointsMaterial.


ParticleSystem has been renamed to PointCloud and then to Points.

Yes, you can create a Point Cloud and vary the alpha value of each particle's color dynamically.

In three.js, you can do this by setting the Point Cloud's material to be a ShaderMaterial having an attribute equal to the desired alpha value for each particle.

If ShaderMaterials, vertex shaders and fragment shaders are new to you, here is a really simple Fiddle that implements a Point Cloud with dynamic alphas: https://jsfiddle.net/9Lvrnpwc/.

EDIT: Updated fiddle

three.js r.148

WestLangley
  • 102,557
  • 10
  • 276
  • 276
  • 1
    Thanks! My current material is as follows: pMaterial = new THREE.ParticleBasicMaterial({ size: 0.2, map: THREE.ImageUtils.loadTexture( "images/particle.png" ), blending: THREE.AdditiveBlending, vertexColors: true, transparent: true, depthWrite: false, //needed? }); How can I keep the additive blending texture with this approach? – user593062 Sep 16 '12 at 12:47
  • Alpha doesn't seem to work in the example anymore. I guess something must have changed in three.js causing this? – Juho Vepsäläinen Jan 29 '13 at 12:20
  • 2
    Okay, fixed it. I just had to set "transparent: true" at ShaderMaterial. http://jsfiddle.net/yfSwK/27/ – Juho Vepsäläinen Jan 29 '13 at 12:40
  • do you know what the meaning of `gl.getProgramInfoLog() WARNING: Could not find vertex shader attribute 'position' to match BindAttributeLocation request.` in the console is? I'm also curious what this `position` is but I see from other sources it is something that THREE.js "provides". – Skylar Saveland Mar 29 '14 at 04:44
  • btw if you are setting the attributes.alpha.value from another array, its a lot quicker to use `= otherArray.slice()` than a for loop – nrob Jan 12 '15 at 17:26
  • Apart from "gl_Fragcolor" what else can I set? Where can I find the reference for these built-in variables? A quick search for gl_Fragcolor shows nothing on this reference card: https://www.khronos.org/files/opengl44-quick-reference-card.pdf – Dois Jul 14 '15 at 01:20
  • This is really great. Do you have the shader code for updating the position of the particles as well? Or if you can have any great link. – arpo Nov 17 '16 at 15:39
0

Not sure why, but proposed solution didn't work for me. I used somewhat tricky shading to make points round and blurry at edges. So the corners of points were supposed to be transparent, but they appeared black: http://jsfiddle.net/5kz64ero/1/

Relevant part of my fragment shader:

// Distance from 0.0 to 0.5 from the center of the point
float d = distance(gl_PointCoord, vec2(0.5, 0.5));

// Applying sigmoid to smoothen the edge
float opacity = 1.0 / (1.0 + exp(16.0 * (d - 0.25)));

gl_FragColor = vec4(opacity * vColor, opacity);

I figured that traditionally this is solved by depth-sorting (with farthest points coming first), and I found some evidence that some older implementations of ParticleSystem in Three contained sortParticles attribute. But it's not there anymore. And in my case sorting would really involve redoing that every time camera position changes. Instead I set depthWrite: false and it seems to solve the issue.

The result: http://jsfiddle.net/5kz64ero/6/

Ivan Yurov
  • 1,578
  • 10
  • 27
  • The downside to this approach is that the points that should render behind render in front depending on the angle. – trusktr Sep 22 '20 at 03:58