Как визуализировать частицы в порядке глубины в three.js? - PullRequest
3 голосов
/ 25 июня 2019

Отказ от ответственности: Я относительно новичок в Three.js, WegGL и 3D-графике в целом.

Я использую Three.js для отображения точек с GPS-треков в 3D.Наборы данных, которые мы должны визуализировать, могут быть довольно большими (сотни тысяч точек), поэтому производительность очень важна.

Я использую объект Points, который я заполняю BufferGeometry, содержащим всеточки.Точки добавляются в порядке следа, то есть в хронологическом порядке.

Затем мы используем PointsMaterial с 2D-текстурой (спрайт), которая представляет точку в виде круга, с областями за пределамикруг, будучи прозрачным2D-текстура динамически отрисовывается на холсте, потому что цвет является динамическим.

Проблема в том, что если мы посмотрим на точки в направлении дорожки, то есть, если точки, расположенные дальше от камеры, будут отображатьсяпосле ближайших есть артефакты, в которых точки перекрываются, при этом прозрачная часть более близких точек рисуется над дальней точкой:

points in 3d

Когдамы смотрим на трек в другом направлении, то есть с точками, отрисованными сзади-вперед, проблема исчезает:

enter image description here

Я пробовал следующие дваВарианты решения этой проблемы:

  • Использование alphaTest со значением от 0 до 1, что вид работает
    • , но наши точки также могут быть частичнопрозрачный (это требование клиента), поэтому существует риск, что alphaTest будет обрезать части точек, которые должны быть визуализированы
    • , и создаст зубчатый край, где точки перекрываются, чтовыглядит не очень хорошо

points in 3d

  • Используя depthWrite: false для материала очков, он хорошо выглядитно тогда последние точки всегда рисуются поверх более старых, независимо от ориентации камеры, это выглядит странно и неправильно

points in 3d

Каким было бы решение для визуализации точек в глубине порядка, начиная с самого дальнего и заканчивая ближайшим?

Вот соответствующиечасти кода.

Построение геометрии.Объект timeline3d содержит все точки и получен из XHR-запроса:

  const particlesGeometry = new BufferGeometry();
  const vertices = [];

  for (let i = 0; i < timeline3d.points.length; i++) {
    const coordinates = timeline3d.points[i].sceneCoordinates;
    vertices.push(coordinates[0], coordinates[1], coordinates[2]);
  }

  particlesGeometry.addAttribute('position', new Float32BufferAttribute(vertices, 3));
  return new Points(particlesGeometry, buildTimelinePointsMaterial(timeline3d));

Материал:

function buildTimelinePointsMaterial (timeline) {
  const pointTexture = new CanvasTexture(drawPointSprite(POINT_SPRITE_RADIUS, timeline.color));

  return new PointsMaterial({
    size: POINT_SIZE,
    sizeAttenuation: true,
    map: pointTexture,
    transparent: true,
    alphaTest: 0.4
  });
}

1 Ответ

4 голосов
/ 25 июня 2019

Обходной путь:

Это ограничение WebGL при рендеринге точек.Как и вышеупомянутый @ScieCode, я лично работал над этой проблемой, изменяя режим смешивания материала .При этом каждая точка сливается с другой, как прозрачный слой Photoshop, и удаляет эффект перекрытия.Обычно, если у вас светлый фон, вам нужно использовать THREE.MultiplyBlending, а если у вас темный фон, вы должны использовать THREE.AdditiveBlending, но это все дело вкуса.

Решение:

Там - это более сложное решение, которое реализовано в этом примере , которое сортирует все вершины по глубине один раз за кадр.Если вы посмотрите на его исходный код , вы увидите, что sortPoints() вызывается в цикле рендеринга, и он умножает матрицы камеры на матрицу мира геометрии, чтобы посмотреть глубину каждой вершины и отсортировать по порядку..

...