I’ve been using ParticleEmitters for a long time, and recently started using Emitters from ParticleMonkey (which also uses the same Particle.j3md shader for particle sprites)
And I’m starting to notice that certain special effects are impossible to make, specifically dark special effects like a black smoke cloud.
It seems as though particles use the luminosity as transparency, so if you have a fully black particle color, it is entirely invisible, and gray colored particles with an alpha value of 1.0f will be more transaprent than a white particle with alpha of 1.0f even though both colors should be fully opaque if they have an alpha value of 1.0f.
Here’s a clip showing the bad results that happen when I use a dark opaque particle color (new ColorRGBA(0.02f, 0.02f, 0.02f, 1.0f) ) and you can see its practically invisible and is much closer to white than it is black: (the particles are also much more visible when I make it night at the end of the clip since there’s less bright things behind it)
Now I was able to work-around this if I edit the particle texture to have transparency (instead of being a grayscale texture with black representing the transparent parts of the particle the way the official JME documentation suggest) and also by setting the blendmode to BlendMode.Alpha. And now I can finally make a fully opaque black smoke cloud. Here’s a clip of the same exact emitter from the previous clip except it has its blend mode set to BlendMode.Alpha and uses transparency in the particle texture:
So I’m curious if this is a potential bug in the way that the JME particle system works, and I also am wondering if it is okay to set the particle materials to BlendMode.Alpha to fix this the way I did without causing any other potential issues or using more resources as a result?
This also has me wondering why the particle system was initially designed to use grayscale textures where black represents transparency, instead of just using a texture with transparency with a material set to Blendmode.Alpha. I’m guessing there was probably a good reason but so far I don’t quite understand it.
Thanks in advance for any replies, I’m interested to hear others’ thoughts on all of this.
It’s all about the default blend mode of AlphaAdd. Obviously, you need transparency in the texture, too… but AlphaAdd is why nothing would get darker.
The issue with regular Alpha is that you will get artifacts from different angles unless you sort the particles in real time. Else, from one side, things will be drawn back to front and look correct but the other side may be front to back and look strange.
Edit: for monochrome textures in your video it matters less… but also probably because you must be turning off depth write or something. Else the zbuffer would show artifacts, too.
Or are you already sorting the particles back to front?
I’m not entirely sure how to do that to be honest lol.
I haven’t changed anything with the particle’s depth write.
The only other non-ordinary thing I’m doing that might effect rendering order is that I have the particles added to the TransluscentBucket, and I also added a TransluscentBucketFilter to the FilterPostProcessor (this is something I was instructed to do a long time ago to prevent the WaterProcessor from rendering over top of my particles, so I didn’t quite understand the logic behind it or what its doing since I was very new to jme at the time)
It’s self ordering within the mesh, not how the scene is sorted.
Within a single mesh, particles are rendered in the order that they are in the mesh. So if you look from one side that might be sorted front to back and from another they might not be.
From your video, we are either looking at the plume from only good sides or there is no depth write or something. Else nearer particles would fill the zbuffer with their semi-transparent pixels and prevent farther+later particles’ pixels from getting rendered.
I just tried setting DepthWrite to true and suddenly notice the artifacts you are describing.
It looks like the DepthWrite boolean is set to false by default in Particle.j3md, so that’s why my original clip isn’t showing the artifacts, since I wasn’t calling any code to set it to true or false and it was just using that default value.
So in that case, I’m guessing I should be okay leaving DepthWrite as false and changing the BlendMode to Alpha when I want opaque particles like this? Or would there be a better way of achieving the same thing?
It looks like I am having some trouble with this when a spell with particle emitters is moving through the black smoke emitter.
Its not too noticeable and isn’t necessarily a problem for spells since they travel through the black particles fast and the spell particles become visible again within a split second so its barely noticable they disappeared in the black particles, but I also was planning to layer another particle emitter over the black one to make it look more like dirty water spewing and splashing out of the geyser eventually, so I will likely want to have more than one emitter in the same spot for this effect (and it won’t be black when its done, I’m just using black since its the best color to test the opacity issue since black particles will render fully transparent if i"m using the default AlphaAddative blendmode)
Do you know of any other way I could make an opaque black smoke from a particle emitter without having to change the emitter’s material to blendmode.Alpha?
Or maybe I should also ask if you think there is any better way to simulate a special effect for a geyser without using only particle emitters? I wonder if I am maybe going down the wrong path trying to use an Emitter for an opaque effect like a geyser?
Although I still am interested in finding a clean way to do an opaque black particle emitter for things like smoke coming off of an explosion eventually, even if I don’t end up using the same approach for this geyser when all is said and done.
This is a classic particle transparency problem… and probably why many particle emitters default to alpha add and depth write = off… because it nicely side-steps the problem. At the expense of the limitations you have already discovered.
The choices are not great:
Alpha but set the discard threshold very high… basically on pixels or off pixels, nothing in between (Minecraft style)
sort the particles back to front, either every frame or when the player/particles move relative to each other.
Sorting the particles isn’t terribly difficult depending on how the “particle system” is setup (ie: the library). Particles tend not to use the index buffer so if you don’t care about the extra RAM and you have a fixed number of particles (or known max) then sometimes you can cheat by adding an index buffer and just sorting the index buffer. That way you don’t have to sort all of the different color, texture, etc. buffers when you sort for position.
Though sorting an index buffer based on a separate position buffer is maybe a non-trivial piece of code.
Sorting is much easier if the particle system code is already keeping separate particle objects… then you just sort those and rewrite them to the buffer.
The “Sort by distance” part is easy enough.
float distance = cam.getDirection().dot(particlePos.subtract(cam.getLocation()));