Bug: point-sprite particles in GUI

Hi,
I am playing with particle effects in GUI node.
I used the trick that @nehon provided some time ago:

        flame.setQueueBucket(Bucket.Gui);
        flame.setFaceNormal(Vector3f.UNIT_Z);

The trick works great!

But I noticed that particle sizes look strange on some occasions and decided to make a simple test case.

import com.jme3.app.SimpleApplication;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh.Type;
import com.jme3.effect.shapes.EmitterSphereShape;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Node;

public class TestExplosionGuiEffect extends SimpleApplication {
    public static void main(String[] args) {
        TestExplosionGuiEffect app = new TestExplosionGuiEffect();
        app.start();
    }

    private ParticleEmitter createFlame() {
        ParticleEmitter flame = new ParticleEmitter("Flame", Type.Point, 32);
        flame.setSelectRandomImage(true);
        flame.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, 1f));
        flame.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));
        flame.setStartSize(30f);
        flame.setEndSize(40f);
        flame.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
        flame.setParticlesPerSec(0);
        flame.setLowLife(8f);
        flame.setHighLife(10f);
        flame.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 7, 0));
        flame.getParticleInfluencer().setVelocityVariation(1f);
        flame.setImagesX(2);
        flame.setImagesY(2);
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
        mat.setBoolean("PointSprite", true);
        flame.setMaterial(mat);
        flame.setQueueBucket(Bucket.Gui);
        flame.setFaceNormal(Vector3f.UNIT_Z);
        return flame;
    }

    @Override
    public void simpleInitApp() {
        ParticleEmitter emit1 = createFlame();
        ParticleEmitter emit2 = createFlame();
        ParticleEmitter emit3 = createFlame();
        ParticleEmitter emit4 = createFlame();

        emit1.setLocalTranslation(cam.getWidth() * 1f / 3f, cam.getHeight() * 1f / 3f, 0);
        emit2.setLocalTranslation(cam.getWidth() * 1f / 3f, cam.getHeight() * 2f / 3f, 0);
        emit3.setLocalTranslation(cam.getWidth() * 2f / 3f, cam.getHeight() * 1f / 3f, 0);
        emit4.setLocalTranslation(cam.getWidth() * 2f / 3f, cam.getHeight() * 2f / 3f, 0);
        
        Node explosionEffect = new Node("explosionEffect");
        explosionEffect.attachChild(emit1);
        explosionEffect.attachChild(emit2);
        explosionEffect.attachChild(emit3);
        explosionEffect.attachChild(emit4);

        renderManager.preloadScene(explosionEffect);
        guiNode.attachChild(explosionEffect);

        emit1.emitAllParticles();
        emit2.emitAllParticles();
        emit3.emitAllParticles();
        emit4.emitAllParticles();
    }
}

Note the 4 particle emitters are the same, but depending on their position on the screen, they are larger/smaller.
This only happens if point sprite particles are used, other cases work perfectly OK.

I suppose this is a bug in the particles shader. And since I am not at all a shader master, I am posting this here, so someone could take a look and maybe come up with a fix. :smile:

Thanks!

PS: This is JME 3.1.

Larger than they are supposed to be or smaller than they are supposed to be? (Screen shot is worth a thousand words.)

Not sure (that’s why I just pasted the whole working test case). :wink:

Ok I have done another test where I changed base particle vertex shader.
So original JME shader has:

#ifdef POINT_SPRITE
    vec4 worldPos = g_WorldMatrix * pos;
    float d = distance(g_CameraPosition.xyz, worldPos.xyz);
    gl_PointSize = max(1.0, (inSize * SIZE_MULTIPLIER * m_Quadratic) / d);

    //vec4 worldViewPos = g_WorldViewMatrix * pos;
    //gl_PointSize = (inSize * SIZE_MULTIPLIER * m_Quadratic)*100.0 / worldViewPos.z;

    color.a *= min(gl_PointSize, 1.0);
#endif

I just modified it a bit to contain this:

#ifdef POINT_SPRITE
    gl_PointSize = max(1.0, inSize);

    color.a *= min(gl_PointSize, 1.0);
#endif

The result is here:

So all the particle emitters are now of the same size and all correspond to their sizes of 30f or 40f (start and end size) in pixels.
Obviously with original shader they depend on the distance to the 0,0 coordinate (closer to it, the bigger the particles)?

So the removed part in shader causes a problem for 2D, not sure about what happens in 3D.
Also after some more playing around, I found out that particle emitters that have setFacingVelocity(true) won’t work in GUI node, but they work without problem in 3D. That leads me to believe that even the code that prepares particle emitter mesh does not work correctly?

Does anyone have any experience with this? :smile: Also there was some talk a lot of time ago about some other particle system, any news about that?

Thanks!

The code you removed is what makes the particles get bigger/smaller as they get closer/farther from the camera. You can control how dramatic this is with the Quadratic parameter.

setFacingVelocity(true) seems like it doesn’t make much sense in 2D.

I disagree, I think that setFacingVelocity(true) makes sense also in 2D - the texture of the particle would turn in the direction it is traveling, the same as in 3D, except now it is only traveling on a 2D plane. I think that particle engine should take this into account when this is provided:

flame.setFaceNormal(Vector3f.UNIT_Z);

Also how do other engines usually have the partical effects? Do they have different shaders and systems for 2D and 3D or can everything be solved with one?

Not sure. I looked into the Ogre3D manual once and they have a very cool particle subsystem. But about their 2D particles I don’t know.

But…
I think we could modify the shader so that it will not use the 3D size calculations when in 2D mode. We could detect that the camera matrix makes an ortho cam (or use a Boolean or ask OpenGL if the cam is ortho or perspective) and then if it’s an ortho cam use your code instead of the 3D code…

Marked the topic as [SOLVED] because people can use your shader code now for 2D point sprites.

Not sure that I am happy with [solved] state. :smile:
I think that maybe the particle system should be enhanced to work also in GUI node without any additional shader hacks.
Also the issue of setFacingVelocity() is there. :wink:

Okay, sorry. Agree that there will something need to be done.