Point sprite rendering issues

I’m currently working an a project which will visualize data on browser by rendering excessive amounts of animated stroked circles. I started evaluating 3D libraries and ended up trying to create a proof of concept application with three.js. It is capable of animating and rendering up to 150 000 point sprites at 60 fps on my 1440p monitor. Everything looks great until you start looking at the details. It has two rendering issues:

  1. It creates strange horizontal lines even when you turn animation off

  2. When you turn the camera, transparent areas of overlapping point sprites will show the background instead of underlying point sprites

    • ht tps://imgur.com/a/NcIwX (remove the space, this platform limits links to 2 for new users)

Here is the proof of concept application: https://jsfiddle.net/tcpvfbsd/1/

var renderer, scene, camera, controls;
var points;
var stats;
var controls;

var worldWidth = 200;
var worldRadius = worldWidth / 2;
var patchSize = 10;
var pointsAmount = 100000;

function init() {
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x1d252d);

  camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
  camera.position.set(0, worldWidth * 1.5, 0);

  controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.minDistance = 100;
  controls.maxDistance = 1100;

  scene.add(new THREE.GridHelper(2 * worldRadius, 2 * worldWidth / patchSize, 0x444444, 0x444444));



  var geometry = new THREE.BufferGeometry();
  var positions = new Float32Array(pointsAmount * 3);
  var rotations = new Float32Array(pointsAmount * 1);

  for (var i = 0; i < pointsAmount; i++) {

    positions[i] = 0;
    positions[i + 1] = 0;
    positions[i + 2] = 0;
    rotations[i] = 2 * Math.PI * Math.random();

  }

  controls = new function() {
    this.speed = 10;
    this.amount = 10;
  };

  var gui = new dat.GUI();
  gui.add(controls, 'speed', 0, 100);
  //gui.add(controls, 'amount', 0, 10000).step(1);;

  geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
  geometry.addAttribute('rotation', new THREE.BufferAttribute(rotations, 1));

  var loader = new THREE.TextureLoader();
  loader.load('//i.imgur.com/AmQQnZc.png', function(texture) {
    var material = new THREE.PointsMaterial({
      size: 5,
      transparent: true,
      map: texture

    });

    points = new THREE.Points(geometry, material);
    scene.add(points);

    stats = new Stats();
    document.body.appendChild(stats.dom);
    animate();
  });

}

function animate() {

  requestAnimationFrame(animate);

  var position = points.geometry.attributes.position;
  var count = position.count;
  var rotation = points.geometry.attributes.rotation;
  var speed = patchSize * controls.speed / 100;
  if (speed > 0) {
    for (var i = 0; i < count; i++) {

      var wiggle = Math.random() > 0.9 ? THREE.Math.randFloat(-0.1, 0.1) : 0;
      var theta = rotation.getX(i) + wiggle;
      let dx = speed * Math.cos(theta);
      let dz = speed * Math.sin(theta);
      var x0 = position.getX(i);
      var z0 = position.getZ(i);
      var x = THREE.Math.clamp(x0 + dx, -worldRadius, worldRadius);
      var z = THREE.Math.clamp(z0 + dz, -worldRadius, worldRadius);
      if (Math.abs(x) === worldRadius) dx = -dx;
      if (Math.abs(z) === worldRadius) dz = -dz;
      position.setX(i, x);
      position.setZ(i, z);
      position.setY(i, 1);
      rotation.setX(i, Math.atan2(dz, dx));

    }
  }

  position.needsUpdate = true;

  stats.update();

  renderer.render(scene, camera);

}
init();

Best way to see the issues is to wait couple of seconds for the point sprites to spread across to area, use speed control on top right corner to pause animation and the use mouse’s left button to turn and rotate the camera.

Thanks for reading. Any help would be greatly appreciated.

Chaning this:

transparent: true,

To this:

transparent: false,
alphaTest: 0.5,

Fixed issue #2. However issue #1 is still present.

All your sprites have the same y coord. So I think internal threejs implementation used some algos that renders these lines you mentioned (2 sprites slightly overlapped by x,z but have the save y. what should be displayed when you looked from y axe?).

As a simple workaround I’d make you sprites have slightly different random y-coord:
position.setY(i, 1);
To this:
position.setY(i, 1+Math.random()/100);

Thank you fifonik! That fixed issue #2 and now everything seems to work as expected.