3d 粒子和 3d 模型的透明度问题,libgdx

Transparency issues with 3d particles and 3d models, libgdx

我在透明度和 3d 粒子方面遇到了一些奇怪的问题。一个简短的视频来说明: https://youtu.be/ZHKI1X3MjhY 如您所见,我有一个 3d 粒子效果,火在燃烧。里面是一个没有 alpha 混合的 3 模型,它显示得很好。然后在远处有一个小骨架(打开了混合和 alphatest),它在火中也显示得很好。然后我转动相机,看着战士的骨架,它就消失了,而你看到的是他身后的东西。我再次转动相机,法师骨架也消失了,但你可以看到稍远一点的树木就好了,它们具有完全相同的混合和 alpha 测试设置。如果我将角色移动到 20 码外,它也会开始显示穿过火焰的效果。

所以好像跟3d粒子效果的距离有关系...

3d 粒子批处理是一个扩展的 BillboardParticleBatch,如下所示:

protected Renderable allocRenderable(){

         BlendingAttribute ba=new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE,1f);

         Renderable r = super.allocRenderable();
         r.material = new Material(   ba,
//               new DepthTestAttribute(GL20.GL_LEQUAL, 0.0f, 0.5f, true),
//                r.material.set(new FloatAttribute(FloatAttribute.AlphaTest, 0.0f),
               TextureAttribute.createDiffuse(texture));

         return r;
   }

所有角色和树都具有以下属性:

if (alpha) {
         FloatAttribute floatAttribute = new FloatAttribute(FloatAttribute.AlphaTest, 0.5f);
         BlendingAttribute blendingAttribute = new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, 1f);
         for (int i = 0; i < bulletEntity.modelInstance.materials.size; i++){
               bulletEntity.modelInstance.materials.get(i).set(blendingAttribute);
               bulletEntity.modelInstance.materials.get(i).set(floatAttribute);
         }

      }

先画模型再画粒子,我试过改变顺序但没有区别。我为 alphatest、depthtest 和 blendingattribute 尝试了很多不同的设置,但找不到任何有效的方法。

编辑 我从 3d 模型中删除了混合属性,现在它看起来与粒子效果有关。然而,我需要我的角色模型上的大多数材质都有混合设置..

有人知道我启用混合时为什么会发生这种情况吗?

我也尝试使用 BillboardParticleBatch 而不扩展它,以防我在那里做了一些事情,但效果更糟。所有启用了混合的模型都出现在粒子效果的前面,即使它们站在它后面。

ModelBatch 对您的渲染调用进行排序(检查 this link,真的,这是必读的),以避免不正确的行为(如您所经历的那样)。实际的 sorting/rendering 发生在对 ModelBatch#end 的调用中。默认情况下,它使用 DefaultRenderableSorter,这是默认实现。当然,由于该实现不了解您的场景,因此它可能无法完全满足您的需求。

DefaultRenderableSorter 尝试根据每个模型的转换矩阵来猜测每个模型的位置。根据该位置和相机的位置,它将对它们进行排序,以便:

  • 首先,所有不透明对象都从前向后渲染(因为不透明对象后面的任何东西无论如何都是不可见的,因此减少了对片段着色器的不必要调用)。
  • 其次,所有透明对象都是从后向前渲染的(因为一旦渲染了透明对象,那么之后渲染的所有内容以及在它后面的所有内容都将不可见)。

要确定对象是否透明,使用 BlendingAttribute#blended 成员。 (因此,如果您真的愿意,可以将该成员设置为 false 以强制将其视为(排序)就好像它是不透明的一样)

所以,你调用ModelBatch#render的顺序不一定是它们实际执行的顺序。如果您想强制渲染您添加到批处理之间的任何内容,请调用 ModelBatch#flush()。当然,经常这样做首先会破坏 ModelBatch 的某些目的。

相反,您可以实现自己的 RenderableSorter,它对您的场景有更多了解,因此可以比默认实现更好地进行排序。 (但是,如果 flush() 适合您并且没有其他问题,那么 flush 可能是最简单的解决方案。

也就是说,您还可以尝试其他各种解决方案。例如。粒子的区域是完全透明的,因此片段着色器最好将它们全部丢弃。尝试向粒子添加值为 0.5fFloatAttribute.AlphaTest。如果这与您的混合混淆,则逐渐将值降低到例如0.05f.

此外,您可以添加一个 DepthTestAttribute,其中 depthMask 设置为 false (new DepthTestAttribute(false))。这将防止粒子写入深度缓冲区。 (但也可能导致其他东西显示在粒子前面)。