Отказ от ответственности: Я относительно новичок в Three.js, WegGL и 3D-графике в целом.
Я использую Three.js для отображения точек с GPS-треков в 3D.Наборы данных, которые мы должны визуализировать, могут быть довольно большими (сотни тысяч точек), поэтому производительность очень важна.
Я использую объект Points
, который я заполняю BufferGeometry
, содержащим всеточки.Точки добавляются в порядке следа, то есть в хронологическом порядке.
Затем мы используем PointsMaterial
с 2D-текстурой (спрайт), которая представляет точку в виде круга, с областями за пределамикруг, будучи прозрачным2D-текстура динамически отрисовывается на холсте, потому что цвет является динамическим.
Проблема в том, что если мы посмотрим на точки в направлении дорожки, то есть, если точки, расположенные дальше от камеры, будут отображатьсяпосле ближайших есть артефакты, в которых точки перекрываются, при этом прозрачная часть более близких точек рисуется над дальней точкой:
Когдамы смотрим на трек в другом направлении, то есть с точками, отрисованными сзади-вперед, проблема исчезает:
Я пробовал следующие дваВарианты решения этой проблемы:
- Использование
alphaTest
со значением от 0 до 1, что вид работает - , но наши точки также могут быть частичнопрозрачный (это требование клиента), поэтому существует риск, что alphaTest будет обрезать части точек, которые должны быть визуализированы
- , и создаст зубчатый край, где точки перекрываются, чтовыглядит не очень хорошо
- Используя
depthWrite: false
для материала очков, он хорошо выглядитно тогда последние точки всегда рисуются поверх более старых, независимо от ориентации камеры, это выглядит странно и неправильно
Каким было бы решение для визуализации точек в глубине порядка, начиная с самого дальнего и заканчивая ближайшим?
Вот соответствующиечасти кода.
Построение геометрии.Объект 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
});
}