1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-22 17:18:39 +00:00

Add particle blend mode "clip" (#15444)

This lets modders avoid alpha blending rendering bugs as well as potential (future) performance issues.
The appropriate blend modes are also used for node dig particles.

---------

Co-authored-by: sfan5 <sfan5@live.de>
This commit is contained in:
Lars Müller 2024-11-19 13:30:17 +01:00 committed by GitHub
parent f493e73aeb
commit 138052adfc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 93 additions and 33 deletions

View file

@ -22,6 +22,8 @@
#include "settings.h"
#include "profiler.h"
using BlendMode = ParticleParamTypes::BlendMode;
ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc)
{
tex = p;
@ -603,8 +605,11 @@ video::S3DVertex *ParticleBuffer::getVertices(u16 index)
void ParticleBuffer::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT_EFFECT);
if (IsVisible) {
SceneManager->registerNodeForRendering(this,
m_mesh_buffer->getMaterial().MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF
? scene::ESNRP_SOLID : scene::ESNRP_TRANSPARENT_EFFECT);
}
scene::ISceneNode::OnRegisterSceneNode();
}
@ -906,6 +911,9 @@ void ParticleManager::addNodeParticle(IGameDef *gamedef,
if (!getNodeParticleParams(n, f, p, &ref, texpos, texsize, &color))
return;
p.texture.blendmode = f.alpha == ALPHAMODE_BLEND
? BlendMode::alpha : BlendMode::clip;
p.expirationtime = myrand_range(0, 100) / 100.0f;
// Physics
@ -940,40 +948,47 @@ void ParticleManager::reserveParticleSpace(size_t max_estimate)
m_particles.reserve(m_particles.size() + max_estimate);
}
video::SMaterial ParticleManager::getMaterialForParticle(const ClientParticleTexRef &texture)
static void setBlendMode(video::SMaterial &material, BlendMode blendmode)
{
// translate blend modes to GL blend functions
video::E_BLEND_FACTOR bfsrc, bfdst;
video::E_BLEND_OPERATION blendop;
const auto blendmode = texture.tex ? texture.tex->blendmode :
ParticleParamTypes::BlendMode::alpha;
switch (blendmode) {
case ParticleParamTypes::BlendMode::add:
case BlendMode::add:
bfsrc = video::EBF_SRC_ALPHA;
bfdst = video::EBF_DST_ALPHA;
blendop = video::EBO_ADD;
break;
case ParticleParamTypes::BlendMode::sub:
case BlendMode::sub:
bfsrc = video::EBF_SRC_ALPHA;
bfdst = video::EBF_DST_ALPHA;
blendop = video::EBO_REVSUBTRACT;
break;
case ParticleParamTypes::BlendMode::screen:
case BlendMode::screen:
bfsrc = video::EBF_ONE;
bfdst = video::EBF_ONE_MINUS_SRC_COLOR;
blendop = video::EBO_ADD;
break;
default: // includes ParticleParamTypes::BlendMode::alpha
default: // includes BlendMode::alpha
bfsrc = video::EBF_SRC_ALPHA;
bfdst = video::EBF_ONE_MINUS_SRC_ALPHA;
blendop = video::EBO_ADD;
break;
}
material.MaterialTypeParam = video::pack_textureBlendFunc(
bfsrc, bfdst,
video::EMFN_MODULATE_1X,
video::EAS_TEXTURE | video::EAS_VERTEX_COLOR);
material.BlendOperation = blendop;
}
video::SMaterial ParticleManager::getMaterialForParticle(const Particle *particle)
{
const ClientParticleTexRef &texture = particle->getTextureRef();
video::SMaterial material;
// Texture
@ -984,17 +999,18 @@ video::SMaterial ParticleManager::getMaterialForParticle(const ClientParticleTex
tex.MagFilter = video::ETMAGF_NEAREST;
});
// We don't have working transparency sorting. Disable Z-Write for
// correct results for clipped-alpha at least.
material.ZWriteEnable = video::EZW_OFF;
// enable alpha blending and set blend mode
material.MaterialType = video::EMT_ONETEXTURE_BLEND;
material.MaterialTypeParam = video::pack_textureBlendFunc(
bfsrc, bfdst,
video::EMFN_MODULATE_1X,
video::EAS_TEXTURE | video::EAS_VERTEX_COLOR);
material.BlendOperation = blendop;
const auto blendmode = particle->getBlendMode();
if (blendmode == BlendMode::clip) {
material.ZWriteEnable = video::EZW_ON;
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.MaterialTypeParam = 0.5f;
} else {
// We don't have working transparency sorting. Disable Z-Write for
// correct results for clipped-alpha at least.
material.ZWriteEnable = video::EZW_OFF;
material.MaterialType = video::EMT_ONETEXTURE_BLEND;
setBlendMode(material, blendmode);
}
material.setTexture(0, texture.ref);
return material;
@ -1004,7 +1020,7 @@ bool ParticleManager::addParticle(std::unique_ptr<Particle> toadd)
{
MutexAutoLock lock(m_particle_list_lock);
auto material = getMaterialForParticle(toadd->getTextureRef());
auto material = getMaterialForParticle(toadd.get());
ParticleBuffer *found = nullptr;
// simple shortcut when multiple particles of the same type get added