简体   繁体   English

Three.js的点精灵渲染问题

[英]Point sprite rendering issues with three.js

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. 我开始评估3D库,最终尝试使用three.js创建概念验证应用程序。 It is capable of animating and rendering up to 150 000 point sprites at 60 fps on my 1440p monitor. 它能够在1440p显示器上以60 fps的动画效果和渲染多达15万个点精灵。 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 当您旋转相机时,重叠的点精灵的透明区域将显示背景,而不是基础点精灵

Here is the proof of concept application: https://jsfiddle.net/tcpvfbsd/1/ 这是概念验证应用程序: 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. 解决问题的最佳方法是等待几秒钟,让点精灵散布到整个区域,使用右上角的速度控制来暂停动画,并使用鼠标的左键来旋转和旋转相机。

  1. Using alphaTest with value 0.5 clipped the corners off the circles without affecting the rendering of other circles 使用值为0.5的alphaTest可以修剪圆角,而不会影响其他圆的渲染
  2. Setting transparent value to false removed the buggy fade effect which came after setting alphaTest to 0.5 将透明值设置为false可以消除将alphaTest设置为0.5后出现的错误淡入效果
  3. Adding fading to the texture itself made the circles' borders smooth even thought the transparent setting which caused the fade effect was disabled 即使已禁用导致淡入淡出效果的透明设置,也可以向纹理本身添加淡入淡出效果,使圆滑的边框更平滑
  4. Randomizing the position on y axis by 0.01 units removed the strange horizontal lines 将y轴上的位置随机化0.01个单位可消除奇怪的水平线

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM