5

免责声明:我对 three.js、WegGL 和一般的 3D 图形比较陌生。

我正在使用 three.js 以 3D 形式显示 GPS 轨迹中的点。我们必须能够可视化的数据集可能非常大(数十万个点),因此性能非常重要。

我使用一个Points对象,我用一个BufferGeometry包含所有点的填充。这些点按轨道的顺序添加,因此按时间顺序。

然后,我们使用PointsMaterial带有 2D 纹理(精灵)的 a,将点表示为一个圆,圆外的区域是透明的。2D 纹理是动态绘制到画布上的,因为颜色是动态的。

问题是,如果我们查看轨道方向上的点,即距离相机较远的点是在较近的点之后渲染的点,则会在点重叠的地方出现伪影,较近的点的透明部分被绘制在更远的点上:

3d 中的点

当我们从另一个方向看轨迹时,即从后到前渲染的点,问题就消失了:

在此处输入图像描述

我尝试了以下两个选项来解决该问题:

  • 使用alphaTest0 到 1 之间的值,哪种有效
    • 但是我们的点也可以是部分透明的(这是客户的要求),所以风险是 alphaTest 会剪掉应该实际渲染的点的一部分
    • 它会在点重叠的地方创建一个锯齿状边缘,看起来不太好

3d 中的点

  • 使用depthWrite: false点材质,它渲染得很好,但是无论相机的方向如何,最近的点总是被绘制在旧点上,它看起来很奇怪而且是错误的

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
  });
}
4

1 回答 1

5

解决方法:

这是 WebGL 在渲染点时的限制。就像上面提到的@ScieCode 一样,我个人一直在通过更改材料的混合模式来解决这个问题。有了它,每个点都像透明的 Photoshop 图层一样相互混合,并消除了重叠效果。通常,如果您有浅色背景,您会想要使用THREE.MultiplyBlending,如果您有深色背景,您会使用THREE.AdditiveBlending,但这完全是个人喜好问题。

解决方案:

此示例中实现了一个复杂的解决方案,它每帧按深度对所有顶点进行一次排序。如果你查看它的源代码,你会看到它在渲染循环中被调用,它将相机矩阵与几何体的世界矩阵相乘,以查看每个顶点深度并按顺序排序。sortPoints()

于 2019-06-25T20:39:52.050 回答