Rain?

I'm trying to add realistic looking rain into the menu of my game and so far it looks pretty rotten.  I'm still pretty new to particle effects but I thought someone might be able to show me the error in my ways:


        ParticleManager manager = new ParticleManager(300);
        manager.setGravityForce(new Vector3f(0.0f, -0.0040f, 0.0f));
        manager.setEmissionDirection(new Vector3f(0.0f, -1.0f, 0.0f));
        manager.setEmissionMaximumAngle(3.1415927f);
        manager.setEmissionMinimumAngle(0.0f);
        manager.setSpeed(0.5f);
        manager.setParticlesMinimumLifeTime(1626.0f);
        manager.setStartSize(3.1f);
        manager.setEndSize(8.6f);
        manager.setStartColor(new ColorRGBA(0.16078432f, 0.16078432f, 1.0f, 1.0f));
        manager.setEndColor(new ColorRGBA(0.16078432f, 0.16078432f, 1.0f, 0.15686275f));
        manager.setRandomMod(0.0f);
        manager.setControlFlow(false);
        manager.setReleaseRate(300);
        manager.setReleaseVariance(1.0f);
        manager.setInitialVelocity(0.58f);
        manager.setParticleSpinSpeed(0.0f);

        manager.warmUp(1000);
        manager.getParticles().addController(manager);

        AlphaState as1 = pg.getDisplay().getRenderer().createAlphaState();
        as1.setBlendEnabled( true );
        as1.setSrcFunction( AlphaState.SB_SRC_ALPHA );
        as1.setDstFunction( AlphaState.DB_ONE );
        as1.setTestEnabled( true );
        as1.setTestFunction( AlphaState.TF_GREATER );
        as1.setEnabled( true );

        TextureState ts = pg.getDisplay().getRenderer().createTextureState();
        ts.setTexture(
                TextureManager.loadTexture(
                        TestDynamicSmoker.class.getClassLoader().getResource(
                                "jmetest/data/texture/flaresmall.jpg" ),
                        Texture.MM_LINEAR_LINEAR,
                        Texture.FM_LINEAR ) );
        ts.setEnabled( true );
       
       
        Box box = new Box("Particle Mesh", new Vector3f(), 400.0f, 1.0f, 400.0f);
        manager.setGeometry(box);
       
        Node myNode = new Node("Particle Nodes");
        myNode.setRenderState(as1);
        myNode.setRenderState(ts);
        myNode.attachChild(manager.getParticles());
        ZBufferState zstate = pg.getDisplay().getRenderer().createZBufferState();
        zstate.setEnabled(false);
        manager.getParticles().setRenderState(zstate);
        myNode.setLocalTranslation(new Vector3f(0.0f, 400.0f, 0.0f));
        pg.attach(myNode);



I'm setting the geometry of the particle manager to a box hoping to get the effect of rain coming down everywhere but this is what I end up with:



It's not really easy to see, but the rain seems to be emitting from the four points of the box instead of over the entire surface of the box.

Thanks,

darkfrog

That's because the box is not tessellated (an entire side of a box is made from only 2 triangles), and the particle manager works per vertex. Most of OpenGL works per vertex too, things like shading and lighting. That's why a tessellated box or quad would look a lot better when you put eg. a spotlight on it in OpenGL than the type jME uses.



For you it might work to use a Sphere instead of a box for now, though I guess that'll mean an uneven distribution of the rain. So you should create a shape somewhat like a grid. Maybe a flat terrain, no matter how silly it is to have invisible terrain floating around in the sky :D, would work pretty well already already.

floating invisible terrain from which the rain will fall…it's just crazy enough to work. :-p



darkfrog

Okay, as it turns out, it was crazy enough to work, but I still can't get it to look like rain.  Anyone with more expertise in particle management willing to give me a hand here?



This is what I've worked up to:


    public void createRain() {
        int heightMapSize = 64;
        int[] heightMap = new int[heightMapSize * heightMapSize];
        for (int i = 0; i < heightMap.length; i++) {
            heightMap[i] = 0;
        }
        Vector3f terrainScale = new Vector3f(13.0f, 1.0f, 13.0f);
        TerrainBlock tb = new TerrainBlock("Terrain", heightMapSize, terrainScale, heightMap, new Vector3f(0, 0, 0), true);
        tb.setModelBound(new BoundingBox());
        tb.updateModelBound();
        tb.setLocalTranslation(new Vector3f(-400.0f, 400.0f, -400.0f));
       
        ParticleManager manager = new ParticleManager(300);
        manager.setGravityForce(new Vector3f(0.0f, -0.0040f, 0.0f));
        manager.setEmissionDirection(new Vector3f(0.0f, -1.0f, 0.0f));
        manager.setEmissionMaximumAngle(3.1415927f);
        manager.setEmissionMinimumAngle(0.0f);
        manager.setSpeed(0.9f);
        manager.setParticlesMinimumLifeTime(1626.0f);
        manager.setStartSize(2.0f);
        manager.setEndSize(2.0f);
        manager.setStartColor(new ColorRGBA(0.8f, 0.8f, 1.0f, 0.5f));
        manager.setEndColor(new ColorRGBA(0.8f, 0.8f, 1.0f, 0.5f));
        manager.setRandomMod(0.0f);
        manager.setControlFlow(true);
        manager.setReleaseRate(60000);
        manager.setReleaseVariance(1.0f);
        manager.setInitialVelocity(0.58f);
        manager.setParticleSpinSpeed(0.0f);

        manager.warmUp(1000);
        manager.getParticles().addController(manager);

        AlphaState as1 = pg.getDisplay().getRenderer().createAlphaState();
        as1.setBlendEnabled( true );
        as1.setSrcFunction( AlphaState.SB_SRC_ALPHA );
        as1.setDstFunction( AlphaState.DB_ONE );
        as1.setTestEnabled( true );
        as1.setTestFunction( AlphaState.TF_GREATER );
        as1.setEnabled( true );

        TextureState ts = pg.getDisplay().getRenderer().createTextureState();
        ts.setTexture(
                TextureManager.loadTexture(
                        TestDynamicSmoker.class.getClassLoader().getResource(
                                "jmetest/data/texture/flaresmall.jpg" ),
                        Texture.MM_LINEAR_LINEAR,
                        Texture.FM_LINEAR ) );
        ts.setEnabled( true );

        manager.setGeometry(tb);
       
        Node myNode = new Node("Particle Nodes");
        myNode.setRenderState(as1);
        myNode.setRenderState(ts);
        myNode.attachChild(manager.getParticles());
        ZBufferState zstate = pg.getDisplay().getRenderer().createZBufferState();
        zstate.setEnabled(false);
        manager.getParticles().setRenderState(zstate);
        myNode.setLocalTranslation(new Vector3f(0.0f, 400.0f, 0.0f));
        pg.attach(myNode);
    }



What this ends up showing is this:



I'd like it to be a pretty heavy rain coming down that can be seen all over the map.  My terrain covers the entire skybox area and sits at the top right under the top of the screen.

Thanks llama for getting me most of the way there!

darkfrog

Think the trouble is you may not be looking at rain with youre own eyes.



When you view rain falling ( illuminated ) looking horixontally, it appears as long dashes as the brain cant process it that fast to get a dot snapshot.

Make it thinner and a lot longer - the length top to tail in the direction its falling

Looks nice darkfrog. ^^



The menu is a JMEDesktop, is it?

Okay, so I’ve made some significant progress and I’m here to show it off (although a screenshot can’t do a very good job showing off the coolness of rain):







Anyone interested I used basically a vertical line and the following code:


    public void createRain() {
        int heightMapSize = 64;
        int[] heightMap = new int[heightMapSize * heightMapSize];
        for (int i = 0; i < heightMap.length; i++) {
            heightMap[i] = 0;
        }
        Vector3f terrainScale = new Vector3f(8.0f, 1.0f, 4.0f);
        TerrainBlock tb = new TerrainBlock("Terrain", heightMapSize, terrainScale, heightMap, new Vector3f(0, 0, 0), true);
        tb.setModelBound(new BoundingBox());
        tb.updateModelBound();
        tb.setLocalTranslation(new Vector3f(-250.0f, 10.0f, 50.0f));
       
        ParticleManager manager = new ParticleManager(3000);
        manager.setGravityForce(new Vector3f(0.0f, -0.0020f, 0.0f));
        manager.setEmissionDirection(new Vector3f(0.0f, -1.0f, 0.0f));
        manager.setEmissionMaximumAngle(0.1f * FastMath.PI);
        manager.setEmissionMinimumAngle(0.0f);
        manager.setSpeed(0.3f);
        manager.setParticlesMinimumLifeTime(200.0f);
        manager.setStartSize(1.0f);
        manager.setEndSize(1.0f);
        manager.setStartColor(new ColorRGBA(0.3f, 0.3f, 0.6f, 0.7f));
        manager.setEndColor(new ColorRGBA(0.3f, 0.3f, 0.6f, 0.7f));
        manager.setRandomMod(1.0f);
        manager.setControlFlow(false);
        manager.setReleaseRate(500);
        manager.setReleaseVariance(0.5f);
        manager.setInitialVelocity(0.58f);
        manager.setParticleSpinSpeed(0.0f);

        manager.warmUp(1000);
        manager.getParticles().addController(manager);

        AlphaState as1 = pg.getDisplay().getRenderer().createAlphaState();
        as1.setBlendEnabled( true );
        as1.setSrcFunction( AlphaState.SB_SRC_ALPHA );
        as1.setDstFunction( AlphaState.DB_ONE );
        as1.setTestEnabled( true );
        as1.setTestFunction( AlphaState.TF_GREATER );
        as1.setEnabled( true );

        TextureState ts = pg.getDisplay().getRenderer().createTextureState();
        ts.setTexture(
                TextureManager.loadTexture(
                        //TestDynamicSmoker.class.getClassLoader().getResource("jmetest/data/texture/flaresmall.jpg"),
                        IntroGame.class.getResource("/data/rainline.jpg"),
                        Texture.MM_LINEAR_LINEAR,
                        Texture.FM_LINEAR ) );
        ts.setEnabled( true );

        manager.setGeometry(tb);
       
        Node myNode = new Node("Particle Nodes");
        myNode.setRenderState(as1);
        myNode.setRenderState(ts);
        myNode.attachChild(manager.getParticles());
        ZBufferState zstate = pg.getDisplay().getRenderer().createZBufferState();
        zstate.setEnabled(false);
        manager.getParticles().setRenderState(zstate);
        myNode.setLocalTranslation(new Vector3f(0.0f, 50.0f, 0.0f));
        pg.attach(myNode);
    }



I'm still trying to tweak it since my FPS has dropped significantly since I added this feature and it's taking forever to start the main screen, but here's progress. :)

darkfrog

Nice one !!!



havent tried or anything - maybe to get fps up you could drop the terrain down to 16 and increase the scale, include culling ???

try using as few particles as possible…  3000 is just too many.  Also, instead of particles you may consider using one or more screen aligned quads with alpha blended animated textures (updated to stay relative to your camera)

Renanse,



Basically like the force-field mojo uses in the FlagRush tutorial?  I could use a couple at different positions in front of the camera to give the appearance of depth?  I guess the biggest problem would be to try to make it look realistic.  I might give that a try if it would significantly increase my fps.  The other problem I have though is that there are menus on all six sides of this cube and so that means sometimes they will have to be facing straight up in the air, and others they will be facing straight down.  Any idea how I could handle that?



madlion: yeah, this is actually using six JMEDesktops (one for each side of the cube).  I created a DesktopBox object that extends Node that I can just instantiate and call getter methods for each side of the cube's JMEDesktops and I can tell it which side is currently being viewed and it disables all the input handlers for the others and enables it.



darkfrog

Okay, I've got my FPS boosted a lot by using Line instead of terrain (thanks again Renanse for the tip) but now I'm having a strange issue with one emitter in the very center of the screen which I'm not sure why it's there.


        Vector3f[] lines = new Vector3f[260];
        int count = 0;
        float pointZ = 140.0f;
        for (int j = 0; j < 6; j++) {
            float pointX = -50.0f;
            for (int i = 0; i < 26; i++) {
                lines[count++] = new Vector3f(pointX, 50.0f, pointZ);
                pointX += 4;
            }
            pointZ += 10.0f;
        }
        Line line = new Line("Line", lines, null, null, null);
       
        ParticleManager manager = new ParticleManager(200);
        manager.setGravityForce(new Vector3f(0.0f, -0.0020f, 0.0f));
        manager.setEmissionDirection(new Vector3f(0.0f, -1.0f, 0.0f));
        manager.setEmissionMaximumAngle(0.1f * FastMath.PI);
        manager.setEmissionMinimumAngle(0.0f);
        manager.setSpeed(0.3f);
        manager.setParticlesMinimumLifeTime(100.0f);
        manager.setStartSize(1.5f);
        manager.setEndSize(1.5f);
        manager.setStartColor(new ColorRGBA(0.3f, 0.3f, 0.6f, 0.8f));
        manager.setEndColor(new ColorRGBA(0.3f, 0.3f, 0.6f, 0.8f));
        manager.setRandomMod(1.0f);
        manager.setControlFlow(false);
        manager.setReleaseRate(400);
        manager.setReleaseVariance(0.5f);
        manager.setInitialVelocity(0.58f);
        manager.setParticleSpinSpeed(0.0f);

        manager.warmUp(1000);
        manager.getParticles().addController(manager);

        AlphaState as1 = pg.getDisplay().getRenderer().createAlphaState();
        as1.setBlendEnabled( true );
        as1.setSrcFunction( AlphaState.SB_SRC_ALPHA );
        as1.setDstFunction( AlphaState.DB_ONE );
        as1.setTestEnabled( true );
        as1.setTestFunction( AlphaState.TF_GREATER );
        as1.setEnabled( true );

        TextureState ts = pg.getDisplay().getRenderer().createTextureState();
        ts.setTexture(
                TextureManager.loadTexture(
                        IntroGame.class.getResource("/data/rainline.jpg"),
                        Texture.MM_LINEAR_LINEAR,
                        Texture.FM_LINEAR ) );
        ts.setEnabled( true );

        manager.setGeometry(line);
       
        Node myNode = new Node("Particle Nodes");
        myNode.setRenderState(as1);
        myNode.setRenderState(ts);
        myNode.attachChild(manager.getParticles());
        myNode.setLocalTranslation(line.getLocalTranslation());
        myNode.updateRenderState();
        pg.attach(myNode);



This is the most recent screenshot:



But here is a zoom-in to see the renegade particle emitter:



Thanks,

darkfrog