【发布时间】: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