深度测试为 true 的 Three.js 精灵的黑色背景 [英] Black background for three.js sprites with depthTest true

查看:172
本文介绍了深度测试为 true 的 Three.js 精灵的黑色背景的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试转换自定义属性 BufferGeometry 示例 (

相比之下,这使用了来自不同three.js 示例(

如您所见,第二个 PointsMaterial 示例按预期工作.因为 PointsMaterial 只接受一种固定的大小和颜色,所以我需要创建 36 种不同的点几何来渲染这张图片.

我更喜欢在第一个示例中使用自定义着色器(它具有自定义大小和颜色属性,并且只需要一个几何图形).有没有办法像 PointsMaterial 那样定义一个自定义着色器来支持 depthTest?

解决方案

WebGL 有一个深度缓冲区,用于找出隐藏在其他像素后面的像素.如果一个像素隐藏在另一个像素后面,它就不会被渲染.通常这就是你想要的,你为什么要浪费 GPU 时间来渲染你永远不会看到的像素?考虑下面的示例深度缓冲区,白色方块离相机更近,而深色方块离相机更远:

如果有一个方块隐藏在另一个方块后面,您将不会在 depthBuffer 中看到它,您只会看到最近的一个.depthBuffer 不知道您的正方形具有部分透明度并且您希望某些部分是透明的.这在其他实时引擎中也是一个问题,这是来自 Unity 的一个例子:

距离较近的方块在 depthBuffer 中阻挡了较远的方块的一部分,因此被遮挡的像素不会被渲染.这就是为什么将

如果您必须设置depthTest,(例如,如果您希望精灵隐藏在实心墙后面),您可以在精灵材质上将 depthWrite 设置为 false.它仍然会检查哪些像素在其他像素之后,但是精灵的像素不会写入 depthBuffer,因此没有精灵可以阻止另一个精灵.

depthTest: true;//测试像素深度深度测试:假;//不测试像素深度深度写入:真;//将像素深度写入depthBuffer深度写入:假;//不将像素深度写入depthBuffer

就混合模式而言,我更喜欢 THREE.AdditiveBlending,因为当粒子在另一个之上堆积时,它会给粒子一个很好的发光效果.但这取决于你.

I have been experimenting with converting the custom attribute BufferGeometry example (https://threejs.org/examples/webgl_buffergeometry_custom_attributes_particles.html) into a fly through animation and I find that the sprites have dark backgrounds (and those that I create myself as well) if depthTest is set to true. See the image.

The sprite in the custom attribute example has a transparent background but this appears to be ignored when it is rendered if depthTest is set to true.

I have tried numerous custom blending rules but cannot find a way to remove the background, only to reduce the effect a bit. The background disappears if depthTest is set to false.

Is this a known limitation? Is there a work around?

I am modifying this question to add clearer images with a different ball sprite (also with a transparent background). This image has depthTest set to true for the custom ShaderMaterial used in the https://threejs.org/examples/webgl_buffergeometry_custom_attributes_particles.html three.js example.

By comparison, this uses multiple PointsMaterials from a different three.js example (https://threejs.org/examples/webgl_points_sprites.html), also with depthTest set to true and using the PointsMaterial map parameter for the sprite.

As you can see, the second PointsMaterial example works as expected. Because PointsMaterial only accepts one fixed size and color, I need to create 36 different point geometries to render this image.

I would prefer to use the custom shader in the first example (which has custom size and color attributes and requires only one geometry). Is there a way to define a custom shader to support depthTest like the PointsMaterial does?

解决方案

WebGL has a depth buffer that's used to find out which pixels are hiding behind other pixels. If a pixel is hiding behind another, it doesn't get rendered. Typically that's what you would want, why would you waste GPU time rendering pixels you're never going to see? Consider the example depthbuffer below, white squares are closer to the camera, while darker squares are further away:

If there was a square hiding behind another one, you wouldn't see it in the depthBuffer, you'd only see the closest one. The depthBuffer doesn't know that your squares have partial transparency and you want some parts to be see-through. This is an issue in other realtime engines too, this is an example from Unity:

The squares that are closer are blocking part of the squares that are further away in the depthBuffer, so the occluded pixels don't get rendered. That's why setting depthTest to false is useful. You're basically telling the renderer to stop testing which pixels are behind others, and just render all of them. Here it is again with depthTest = false:

If you must set depthTest on, (for instance, if you want the sprites to hide behind a solid wall) you could set depthWrite to false on the sprite material. It would still check which pixels are behind others, but the pixels from the sprites wouldn't get written to the depthBuffer, so no sprite could block another sprite.

depthTest: true;   // Tests pixel depth
depthTest: false;  // Does not test pixel depth
depthWrite: true;  // Writes pixel depth to depthBuffer
depthWrite: false; // Does not write pixel depth to depthBuffer

As far as blending mode, I prefer THREE.AdditiveBlending because it gives the particles a nice glowing effect when they accumulate one on top of the other. But that's up to you.

这篇关于深度测试为 true 的 Three.js 精灵的黑色背景的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆