【问题标题】:How to render particles in depth order in three.js?如何在three.js中按深度顺序渲染粒子?
【发布时间】:2019-11-07 14:33:05
【问题描述】:

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

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

我使用一个Points 对象,我用包含所有点的BufferGeometry 填充该对象。这些点是按曲目顺序添加的,所以按时间顺序。

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

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

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

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

  • 使用具有介于 0 和 1 之间的值的 alphaTest一种 有效
    • 但我们的点也可以是部分透明的(这是客户的要求),因此风险在于 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
  });
}

【问题讨论】:

  • 这个问题没有内置的解决方案。您可以更新您的BufferGeometry 按深度排序的position 属性,但根据点数,这不是一个实用/有效的解决方案。另一种方法是使用不同的混合选项,例如AdditiveBlending。不过,这可能会产生不必要的副作用。

标签: javascript three.js 3d depth-testing


【解决方案1】:

解决方法:

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

解决办法:

有一个更复杂的解决方案,已实现in this example,它每帧按深度对所有顶点进行一次排序。如果您查看its source code,您会看到在渲染循环中调用了sortPoints(),它将相机矩阵与几何体的世界矩阵相乘,以查看每个顶点深度并按顺序排序。

【讨论】:

  • 补充:如果场景中的点/相机是静态的,则不需要每帧对顶点进行排序。仅当相机或点移动时。
  • 感谢您的回答。乘法混合对我不起作用,我有一个具有透明背景的场景,因此这些点不可见,除非它们后面有其他东西(如地面地图)。加法混合会改变它们重叠的点的颜色,所以也不是很好。但是我通过 alphaTest 得到了一个可以接受的结果,如果真的需要,我会求助于自定义排序。
  • @ScieCode:是的,实际上整个场景都是静态的,所以我基本上不渲染,除非相机移动了。
  • @Marquizzo 我用这个例子做了一些测试,结果不是很好,因为排序是由 CPU 完成的,它已经过载了几万个点。知道如何将其委托给 GPU 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-08
  • 1970-01-01
  • 2012-09-21
  • 2017-01-08
  • 1970-01-01
  • 2019-10-01
  • 2011-01-18
相关资源
最近更新 更多