Re-Scaling/Re-Sizing Particles Depending on Screen Size

I am new the three.js - apologies for a basic question about sizing particles.

I was able to follow some examples from https://threejs.org/examples/ to get a particle mesh to animate according to some math formula (sine waves) but I believe because I am using a THREE.Points(this.geometry, this.material) I am not seeing the particles scale correctly on different devices.

I have a working example here: https://codepen.io/anon/pen/xvrpeY

There are problems with seeing the particles on retina displays and mobile devices. In the end, I would like to have a varying number of particles per screen size. E.g. XS screen size = 100 x 100 particle grid. Sm size = 500 x 500, LG = 1000 x 1000, XL = 1500 x 1500 particles.

Do I need to add some material to the particle (a png image?) in order to scale the visualization properly on different screen sizes and devices?

Thanks for any help or feedback!

There are a few issues in your codepen:

  • When using THREE.Points, you have to use THREE.PointsMaterial not THREE.MeshBasicMaterial. The latter one is only intended when rendering triangles.
  • The size of points is defined by the material. Defining a buffer attribute size has no effect when rendering with THREE.PointsMaterial. The shader does not have a size vertex attribute.
  • Size is defined in pixels. It’s normal that devices with different pixel densities render points differently. You might want to use the window.devicePixelRatio when setting the size property for your material.

Updated demo (I’m not a fan of codepen so I use jsfiddle instead): https://jsfiddle.net/Lgkwso13/

Thanks for your feedback. That’s what I had suspected - I tried two other solutions:

// Option 1 - Points Material with texture (disc.png)
this.material = new THREE.PointsMaterial({
  color: 0xf9f9f9,
  map: new THREE.TextureLoader().load('https://raw.githubusercontent.com/timoxley/threejs/master/examples/textures/sprites/disc.png'),
  transparent: true,
  depthWrite: false,
  depthTest: false
});

It looks like I can adjust the different size of the animation now, but I still can’t adjust the size or color based on the location of the particle during the animation (for example: increasing the particles size when it is higher or changing its color as it moves). I also tried writing the shader myself:

// Option 2 - shaders to allow for custom attributes (i.e. sizing)
const vertexShader = `
  uniform float amplitude;
  attribute float size;

  void main() {
    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
    gl_PointSize = size * ( 300.0 / -mvPosition.z );
    gl_Position = projectionMatrix * mvPosition;
  }`;

const fragmentShader = `
  uniform vec3 color;
  uniform sampler2D texture;

  void main() {
    gl_FragColor = vec4( color , 1.0 );
    gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );
  }`;

const texture = new THREE.TextureLoader().load('https://raw.githubusercontent.com/timoxley/threejs/master/examples/textures/sprites/disc.png');
texture.anisotropy = 0;
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.NearestFilter;

this.material = new THREE.ShaderMaterial({
  uniforms: {
    amplitude: { value: 1.0 },
    color: { value: new THREE.Color(0x0076de) },
    texture: { value: texture }
  },
  vertexShader,
  fragmentShader,

  // blending: THREE.AdditiveBlending,
  depthTest: false,
  transparent: true
});

I feel like writing the shader explicitly is the correct way to vary the color and size of the particles, but I still can’t get it to work. Am I on the right track?

On first sight, it does not look wrong^^. The following example could also be a good code template for you:

https://threejs.org/examples/webgl_points_waves