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.5f
的 FloatAttribute.AlphaTest
。如果这与您的混合混淆,则逐渐将值降低到例如0.05f
.
此外,您可以添加一个 DepthTestAttribute,其中 depthMask
设置为 false
(new DepthTestAttribute(false)
)。这将防止粒子写入深度缓冲区。 (但也可能导致其他东西显示在粒子前面)。
我在透明度和 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.5f
的 FloatAttribute.AlphaTest
。如果这与您的混合混淆,则逐渐将值降低到例如0.05f
.
此外,您可以添加一个 DepthTestAttribute,其中 depthMask
设置为 false
(new DepthTestAttribute(false)
)。这将防止粒子写入深度缓冲区。 (但也可能导致其他东西显示在粒子前面)。