Simple rain effect

As in title. Any suggestion is welcome !!!



[java]



import com.jme3.app.SimpleApplication;

import com.jme3.asset.TextureKey;

import com.jme3.asset.plugins.HttpZipLocator;

import com.jme3.asset.plugins.ZipLocator;

import com.jme3.bounding.BoundingBox;

import com.jme3.font.BitmapText;

import com.jme3.input.ChaseCamera;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.material.RenderState.BlendMode;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Vector3f;

import com.jme3.renderer.Camera;

import com.jme3.renderer.queue.RenderQueue.Bucket;

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Sphere;

import com.jme3.terrain.geomipmap.TerrainLodControl;

import com.jme3.terrain.geomipmap.TerrainQuad;

import com.jme3.terrain.heightmap.AbstractHeightMap;

import com.jme3.terrain.heightmap.ImageBasedHeightMap;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture.WrapMode;

import com.jme3.util.SkyFactory;







import java.io.File;

import java.util.ArrayList;

import java.util.List;



import jme3tools.converters.ImageToAwt;



public class TestRainLoading extends SimpleApplication {



private Sphere sphereMesh = new Sphere(32, 32, 10, false, true);

private Geometry sphere = new Geometry("Sky", sphereMesh);

private Rain rain;

private float angle1;

private Geometry ballGeom;

private ChaseCamera chaser;

private TerrainQuad terrain;

private Material matRock;

private Material matWire;

private BitmapText hintText;

protected boolean wireframe;

protected boolean rainTarget;



public static void main(String[] args) {



TestRainLoading app = new TestRainLoading();

app.start();

}



@Override

public void simpleUpdate(float tpf){

sphere.setLocalTranslation(cam.getLocation());

angle1 += tpf * 1.25f;

angle1 %= FastMath.TWO_PI;



ballGeom.setLocalTranslation(new Vector3f(FastMath.cos(angle1) * 240f, 20.5f, FastMath.sin(angle1) * 240f));



}



public void simpleInitApp() {

loadHintText();

setupKeys();

this.flyCam.setMoveSpeed(10);

flyCam.setEnabled(false);

cam.setLocation(new Vector3f(0,1000,0));

buildTerrain();

// load sky

rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));







DirectionalLight sun = new DirectionalLight();

sun.setDirection(new Vector3f(-0.4790551f, -0.39247334f, -0.7851566f));

sun.setColor(ColorRGBA.White.clone().multLocal(2));

terrain.addLight(sun);



rain =new Rain(assetManager,cam,1);

rootNode.attachChild(rain);

Sphere ball = new Sphere(32, 32, 2f);

ballGeom = new Geometry("Ball Name", ball);

Material mat3 = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");

mat3.setColor("m_Color", new ColorRGBA(0, 0, 1, 0.6f));

mat3.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);

ballGeom.setMaterial(mat3);

ballGeom.setQueueBucket(Bucket.Transparent);

rootNode.attachChild(ballGeom);

chaser = new ChaseCamera(cam,ballGeom,inputManager);

chaser.setMaxDistance(1200);

chaser.setSmoothMotion(true);

rain.setTarget(ballGeom);

}

public void loadHintText() {

hintText = new BitmapText(guiFont, false);

hintText.setSize(guiFont.getCharSet().getRenderedSize());

hintText.setLocalTranslation(0, getCamera().getHeight(), 0);

hintText.setText("Hit R to switch rain targetrnHit T to switch to wireframe");

guiNode.attachChild(hintText);

}

private void setupKeys() {

flyCam.setMoveSpeed(50);

inputManager.addMapping("rain", new KeyTrigger(KeyInput.KEY_R));

inputManager.addListener(actionListener, "rain");

inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));

inputManager.addListener(actionListener, "wireframe");

}

private ActionListener actionListener = new ActionListener() {



public void onAction(String name, boolean pressed, float tpf) {

if (name.equals("wireframe") && !pressed) {

wireframe = !wireframe;

if (!wireframe) {

terrain.setMaterial(matWire);

} else {

terrain.setMaterial(matRock);

}



}

if (name.equals("rain") && !pressed) {

rainTarget = !rainTarget;

if (!rainTarget) {

rain.setTarget(ballGeom);

chaser.setEnabled(true);

flyCam.setEnabled(false);

} else {

rain.setTarget(null);

chaser.setEnabled(false);

flyCam.setEnabled(true);

}



}

}

};

private void buildTerrain(){

// First, we load up our textures and the heightmap texture for the terrain



// TERRAIN TEXTURE material

matRock = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");



// ALPHA map (for splat textures)

matRock.setTexture("m_Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));



// HEIGHTMAP image (for the terrain heightmap)

Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");



// GRASS texture

Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");

grass.setWrap(WrapMode.Repeat);

matRock.setTexture("m_Tex1", grass);

matRock.setFloat("m_Tex1Scale", 64f);



// DIRT texture

Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");

dirt.setWrap(WrapMode.Repeat);

matRock.setTexture("m_Tex2", dirt);

matRock.setFloat("m_Tex2Scale", 32f);



// ROCK texture

Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");

rock.setWrap(WrapMode.Repeat);

matRock.setTexture("m_Tex3", rock);

matRock.setFloat("m_Tex3Scale", 128f);



// WIREFRAME material

matWire = new Material(assetManager, "Common/MatDefs/Misc/WireColor.j3md");

matWire.setColor("m_Color", ColorRGBA.Green);





// CREATE HEIGHTMAP

AbstractHeightMap heightmap = null;

try {

//heightmap = new HillHeightMap(1025, 1000, 50, 100, (byte) 3);



heightmap = new ImageBasedHeightMap(ImageToAwt.convert(heightMapImage.getImage(), false, true, 0), 1f);

heightmap.load();



} catch (Exception e) {

e.printStackTrace();

}



/*

  • Here we create the actual terrain. The tiles will be 65x65, and the total size of the
  • terrain will be 513x513. It uses the heightmap we created to generate the height values.

    */

    /**
  • Optimal terrain patch size is 65 (64x64)
  • If you go for small patch size, it will definitely slow down because the depth of
  • the quad tree will increase, and more is done on the CPU then to traverse it.
  • I plan to give each node in the tree a reference to its neighbours so that should
  • resolve any of these slowdowns. -Brent

    *
  • The total size is up to you. At 1025 it ran fine for me (200+FPS), however at
  • size=2049, it got really slow. But that is a jump from 2 million to 8 million triangles…

    /

    terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());

    List<Camera> cameras = new ArrayList<Camera>();

    cameras.add(getCamera());

    TerrainLodControl control = new TerrainLodControl(terrain, cameras);

    terrain.addControl(control);

    terrain.setMaterial(matRock);

    terrain.setModelBound(new BoundingBox());

    terrain.updateModelBound();

    terrain.setLocalTranslation(0, -100, 0);

    terrain.setLocalScale(2f, 1f, 2f);

    rootNode.attachChild(terrain);

    }

    }



    [/java]



    where Rain.java is:



    [java]

    package mypackage;







    import java.util.Properties;

    import java.util.logging.Logger;



    import com.jme3.asset.AssetManager;

    import com.jme3.bounding.BoundingSphere;

    import com.jme3.effect.EmitterSphereShape;

    import com.jme3.effect.ParticleEmitter;

    import com.jme3.effect.ParticleMesh;

    import com.jme3.effect.ParticleMesh.Type;

    import com.jme3.material.Material;

    import com.jme3.material.RenderState.BlendMode;

    import com.jme3.math.ColorRGBA;

    import com.jme3.math.Plane;

    import com.jme3.math.Ray;

    import com.jme3.math.Ring;

    import com.jme3.math.Vector3f;

    import com.jme3.renderer.Camera;

    import com.jme3.renderer.queue.RenderQueue.Bucket;

    import com.jme3.renderer.queue.RenderQueue.ShadowMode;

    import com.jme3.scene.Geometry;

    import com.jme3.scene.Node;

    import com.jme3.scene.Spatial;

    import com.jme3.scene.shape.Sphere;











    public class Rain extends Node {



    private static final long serialVersionUID = -1057124936652689175L;

    private static Logger log = Logger.getLogger(Rain.class.getCanonicalName());

    private ParticleEmitter points;

    private boolean useGravity = false;

    private Node _rootNode;

    private AssetManager assetManager;

    private Camera cam;

    private int height=440;

    private Spatial target;



    public Rain(AssetManager assetManager,Camera cam, int weather) {

    super("rain");

    this.assetManager=assetManager;

    this.cam=cam;

    applyParameters(weather);





    Sphere ball = new Sphere(32, 32, 20f);

    Geometry ballGeom = new Geometry("Ball Name", ball);

    Material mat3 = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");

    mat3.setColor("m_Color", new ColorRGBA(1, 1, 0, 0.2f));

    mat3.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);

    ballGeom.setMaterial(mat3);

    ballGeom.setQueueBucket(Bucket.Transparent);

    this.attachChild(ballGeom);

    }



    public void applyParameters(int weather) {

    points = new ParticleEmitter("rainPoints", Type.Triangle, 800
    weather);

    points.setShape(new EmitterSphereShape(Vector3f.ZERO, 600f));

    // points.setLocalTranslation(new Vector3f(0f, height, 0f));

    points.setInitialVelocity(new Vector3f(0.0f, -1.0f, 0.0f));

    //points.setMaximumAngle(3.1415927f);

    //points.setMinimumAngle(0.0f);

    //points.setImagesX(1);

    //points.setImagesY(1);

    points.setGravity(1159.9fweather);

    // points.setLowLife(1626.0f);

    points.setLowLife(2);

    points.setHighLife(5);

    points.setStartSize(1.8f);

    points.setEndSize(1.6f);

    points.setStartColor(new ColorRGBA(0.8f, 0.8f, 1.0f, 0.8f));

    points.setEndColor(new ColorRGBA(0.8f, 0.8f, 1.0f, 0.6f));

    //points.setRandomAngle(randomAngle)Mod(0.0f);

    points.setFacingVelocity(false);

    //points.setFaceNormal(new Vector3f(0,0,1));

    points.setParticlesPerSec(80000
    weather);

    points.setVelocityVariation(20.0f);

    //points.setInitialVelocity(0.58f);

    points.setRotateSpeed(0.0f);

    points.setShadowMode(ShadowMode.CastAndReceive);

    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");

    mat.setTexture("m_Texture", assetManager.loadTexture("textures/raindrop.png"));

    points.setMaterial(mat);

    points.setQueueBucket(Bucket.Transparent);

    points.updateLogicalState(0);

    points.updateGeometricState();

    }





    public void updateLogicalState(float tpf){



    super.updateLogicalState(tpf);

    float far=800f;

    Vector3f intersection=Vector3f.ZERO;

    if(target==null){

    Vector3f loc=new Vector3f(cam.getLocation());

    Plane piano=new Plane(loc,far);

    Ray ray=new Ray(loc,cam.getDirection());

    intersection=new Vector3f(cam.getLocation());

    ray.intersectsWherePlane(piano, intersection);



    }

    else{

    intersection=new Vector3f(target.getLocalTranslation());

    }

    intersection.y=height;

    this.setLocalTranslation(intersection);





    }



    public Spatial getTarget() {

    return target;

    }



    public void setTarget(Spatial target) {

    this.target = target;

    }



    }



    [/java]



    just pressing R, you can switch rain follows target or cam
4 Likes

I’m eager to test your work but I miss the raindrop.png, could you provide it?

Well I cant really see how it looks without the rain texture :confused:

:smiley:

you’re right



raindrop texture

EmpirePhoenix said:
Well I cant really see how it looks without the rain texture :/


any suggestion to improve it?

Well …there might be a problem, when i test it I only see a blue sphere making circles around a terrain. Don’t see any rain.

which resolution do you use?



maybe the problem is here:



[java]

points.setStartSize(1.8f);

points.setEndSize(1.6f);

[/java]

Well I basically have the same problem , I only see a blue circle but no rain.

Honestly i don’t get it, the rain node is never attached to the scene, the emitter never emits its particle.

Could you make video of what it should look like?

nehon said:
Honestly i don't get it, the rain node is never attached to the scene, the emitter never emits it's particle.
Could you make video of what it should look like?


ok I've updated jme3, and I had the same problem (I think related with lights)

[java]
import java.util.Properties;
import java.util.logging.Logger;

import com.jme3.asset.AssetManager;
import com.jme3.bounding.BoundingSphere;
import com.jme3.effect.EmitterSphereShape;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.effect.ParticleMesh.Type;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Plane;
import com.jme3.math.Ray;
import com.jme3.math.Ring;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Sphere;




/**
* a point particle effect for rain
* @author galun
* @version $Id: Rain.java,v 1.4 2006/11/11 22:23:29 galun Exp $
*/
public class Rain extends Node {

private static final long serialVersionUID = -1057124936652689175L;
private static Logger log = Logger.getLogger(Rain.class.getCanonicalName());
private ParticleEmitter points;
//private SimpleParticleInfluenceFactory.BasicGravity gravity;
private boolean useGravity = false;
private Node _rootNode;
private AssetManager assetManager;
private Camera cam;
private int height=400;
private Spatial target;

public Rain(AssetManager assetManager,Camera cam, int weather) {
super("rain");
this.assetManager=assetManager;
this.cam=cam;
applyParameters(weather);
attachChild(points);
Sphere ball = new Sphere(32, 32, 20f);
Geometry ballGeom = new Geometry("Ball Name", ball);
Material mat3 = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
mat3.setColor("m_Color", new ColorRGBA(1, 1, 0, 0.2f));
mat3.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
ballGeom.setMaterial(mat3);
ballGeom.setQueueBucket(Bucket.Transparent);
this.attachChild(ballGeom);
}

public void applyParameters(int weather) {
points = new ParticleEmitter("rainPoints", Type.Triangle, 800*weather);
points.setShape(new EmitterSphereShape(Vector3f.ZERO, 600f));
// points.setLocalTranslation(new Vector3f(0f, height, 0f));
points.setInitialVelocity(new Vector3f(0.0f, -1.0f, 0.0f));
//points.setMaximumAngle(3.1415927f);
//points.setMinimumAngle(0.0f);
points.setImagesX(1);
points.setImagesY(1);
points.setGravity(1159.9f*weather);
// points.setLowLife(1626.0f);
points.setLowLife(2);
points.setHighLife(5);
points.setStartSize(1.8f);
points.setEndSize(1.6f);
points.setStartColor(new ColorRGBA(0.0f, 0.0f, 1.0f, 0.8f));
points.setEndColor(new ColorRGBA(0.8f, 0.8f, 1.0f, 0.6f));
//points.setRandomAngle(randomAngle)Mod(0.0f);
points.setFacingVelocity(false);
//points.setFaceNormal(new Vector3f(0,0,1));
points.setParticlesPerSec(80000*weather);
//points.setVelocityVariation(20.0f);
//points.setInitialVelocity(0.58f);
points.setRotateSpeed(0.0f);
points.setShadowMode(ShadowMode.CastAndReceive);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
mat.setTexture("m_Texture", assetManager.loadTexture("textures/raindrop.png"));
points.setMaterial(mat);
points.setQueueBucket(Bucket.Transparent);
points.updateLogicalState(0);
points.updateGeometricState();
}

private ColorRGBA parseColor(String s) {
ColorRGBA color = new ColorRGBA(ColorRGBA.White);
try {
float r = 1;
float g = 1;
float b = 1;
float a = 1;
String[] p = s.split(",\s+");
r = Float.parseFloat(p[0]);
if (p.length > 1)
g = Float.parseFloat(p[1]);
if (p.length > 2)
b = Float.parseFloat(p[2]);
if (p.length > 3)
a = Float.parseFloat(p[3]);
color.set(r, g, b, a);
} catch (Exception ex) {
log.warning("unparsable color: " + s + " (" + ex.toString() + ")");
}
return color;
}
public void updateLogicalState(float tpf){
//if(points.getMesh()==null)return;
super.updateLogicalState(tpf);
float far=800f;
Vector3f intersection=Vector3f.ZERO;
if(target==null){
Vector3f loc=new Vector3f(cam.getLocation());
Plane piano=new Plane(loc,far);
Ray ray=new Ray(loc,cam.getDirection());
intersection=new Vector3f(cam.getLocation());
ray.intersectsWherePlane(piano, intersection);

}
else{
intersection=new Vector3f(target.getLocalTranslation());
}
intersection.y=height;
//intersection.x=cam.getLocation().x+cam.getDirection().x*50f;
//intersection.z=cam.getLocation().z+cam.getDirection().z*50f;
this.setLocalTranslation(intersection);
System.out.println("pos rain="+this.getLocalTranslation());
/*System.out.println("pos rain="+points.getParticles()[0].position);
float x=(int) (Math.random()*far)-far/2;
float z=(int) (Math.random()*far)-far/2;
if(points.getParticles()[0].position.y==height){
points.setLocalTranslation(new Vector3f(x, height, z));
}
else if(points.getLocalTranslation().y<0)
points.killAllParticles();*/

}

public Spatial getTarget() {
return target;
}

public void setTarget(Spatial target) {
this.target = target;
}

}
[/java]

[java]
import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.asset.plugins.HttpZipLocator;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bounding.BoundingBox;
import com.jme3.font.BitmapText;
import com.jme3.input.ChaseCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.light.PointLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Sphere;
import com.jme3.shadow.PssmShadowRenderer;
import com.jme3.terrain.geomipmap.TerrainLodControl;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import com.jme3.util.SkyFactory;

import it.F1Viewer3D.Rain;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import jme3tools.converters.ImageToAwt;

public class TestRainLoading extends SimpleApplication {

private Sphere sphereMesh = new Sphere(32, 32, 10, false, true);
private Geometry sphere = new Geometry("Sky", sphereMesh);
private Rain rain;
private float angle1;
private Geometry ballGeom;
private ChaseCamera chaser;
private TerrainQuad terrain;
private Material matRock;
private Material matWire;
private BitmapText hintText;
protected boolean wireframe;
protected boolean rainTarget;
private Vector3f lightDir = new Vector3f(.1f, -1, .1f).normalizeLocal();

public static void main(String[] args) {

TestRainLoading app = new TestRainLoading();
app.start();
}

@Override
public void simpleUpdate(float tpf){
super.simpleUpdate(tpf);
sphere.setLocalTranslation(cam.getLocation());
angle1 += tpf * 1.25f;
angle1 %= FastMath.TWO_PI;

ballGeom.setLocalTranslation(new Vector3f(FastMath.cos(angle1) * 240f, 20.5f, FastMath.sin(angle1) * 240f));

}

public void simpleInitApp() {
loadHintText();
setupKeys();
setupBasicShadow();
this.flyCam.setMoveSpeed(10);
flyCam.setEnabled(false);
cam.setLocation(new Vector3f(0,1000,0));
buildTerrain();
// load sky
rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false));



setupLighting();

rain =new Rain(assetManager,cam,1);
rootNode.attachChild(rain);
Sphere ball = new Sphere(32, 32, 2f);
ballGeom = new Geometry("Ball Name", ball);
Material mat3 = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
mat3.setColor("m_Color", new ColorRGBA(0, 0, 1, 0.6f));
mat3.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
ballGeom.setMaterial(mat3);
ballGeom.setQueueBucket(Bucket.Transparent);
rootNode.attachChild(ballGeom);
chaser = new ChaseCamera(cam,ballGeom,inputManager);
chaser.setMaxDistance(1200);
chaser.setSmoothMotion(true);
rain.setTarget(ballGeom);
}
public void loadHintText() {
hintText = new BitmapText(guiFont, false);
hintText.setSize(guiFont.getCharSet().getRenderedSize());
hintText.setLocalTranslation(0, getCamera().getHeight(), 0);
hintText.setText("Hit R to switch rain targetrnHit T to switch to wireframe");
guiNode.attachChild(hintText);
}
public void setupLighting() {
// boolean hdr = hdrRender.isEnabled();

// flourescent main light
PointLight pl = new PointLight();
pl.setColor(new ColorRGBA(1f, 1f, 1f, 1f));
pl.setRadius(320);
// pl.setPosition(new Vector3f(0f,400,0f));
rootNode.addLight(pl);

DirectionalLight dl = new DirectionalLight();
// sunset light

dl.setDirection(new Vector3f(-0.1f, -0.7f, .5f));
dl.setColor(new ColorRGBA(0.44f, 0.40f, 0.40f, .25f));
rootNode.addLight(dl);

// skylight
DirectionalLight dl1 = new DirectionalLight();
dl1.setDirection(new Vector3f(-0.6f, -1, -0.6f).normalizeLocal());
dl1.setColor(new ColorRGBA(0.20f, 0.22f, 0.24f, .25f));
rootNode.addLight(dl1);

// white ambient light
DirectionalLight dl2 = new DirectionalLight();
dl2.setDirection(new Vector3f(0, -1, -0));
dl2.setColor(new ColorRGBA(.9f, .9f, .9f, 1f));
rootNode.addLight(dl2);
}
public void setupBasicShadow() {

PssmShadowRenderer pssmRenderer = new PssmShadowRenderer(assetManager, 1024,4,PssmShadowRenderer.EDGE_FILTERING_PCF);
pssmRenderer.setDirection(lightDir);
pssmRenderer.setLambda(0.3f);
pssmRenderer.setShadowIntensity(0.6f);
pssmRenderer.setCropShadows(false);
pssmRenderer.setPcfFilter(PssmShadowRenderer.FILTERING.PCF16X16);
pssmRenderer.setEdgesThickness(5);
viewPort.addProcessor(pssmRenderer);
}
private void setupKeys() {
flyCam.setMoveSpeed(50);
inputManager.addMapping("rain", new KeyTrigger(KeyInput.KEY_R));
inputManager.addListener(actionListener, "rain");
inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
inputManager.addListener(actionListener, "wireframe");
}
private ActionListener actionListener = new ActionListener() {

public void onAction(String name, boolean pressed, float tpf) {
if (name.equals("wireframe") && !pressed) {
wireframe = !wireframe;
if (!wireframe) {
terrain.setMaterial(matWire);
} else {
terrain.setMaterial(matRock);
}

}
if (name.equals("rain") && !pressed) {
rainTarget = !rainTarget;
if (!rainTarget) {
rain.setTarget(ballGeom);
chaser.setEnabled(true);
flyCam.setEnabled(false);
} else {
rain.setTarget(null);
chaser.setEnabled(false);
flyCam.setEnabled(true);
}

}
}
};
private void buildTerrain(){
// First, we load up our textures and the heightmap texture for the terrain

// TERRAIN TEXTURE material
matRock = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");

// ALPHA map (for splat textures)
matRock.setTexture("m_Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));

// HEIGHTMAP image (for the terrain heightmap)
Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");

// GRASS texture
Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
grass.setWrap(WrapMode.Repeat);
matRock.setTexture("m_Tex1", grass);
matRock.setFloat("m_Tex1Scale", 64f);

// DIRT texture
Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
dirt.setWrap(WrapMode.Repeat);
matRock.setTexture("m_Tex2", dirt);
matRock.setFloat("m_Tex2Scale", 32f);

// ROCK texture
Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
rock.setWrap(WrapMode.Repeat);
matRock.setTexture("m_Tex3", rock);
matRock.setFloat("m_Tex3Scale", 128f);

// WIREFRAME material
matWire = new Material(assetManager, "Common/MatDefs/Misc/WireColor.j3md");
matWire.setColor("m_Color", ColorRGBA.Green);


// CREATE HEIGHTMAP
AbstractHeightMap heightmap = null;
try {
//heightmap = new HillHeightMap(1025, 1000, 50, 100, (byte) 3);

heightmap = new ImageBasedHeightMap(ImageToAwt.convert(heightMapImage.getImage(), false, true, 0), 1f);
heightmap.load();

} catch (Exception e) {
e.printStackTrace();
}

/*
* Here we create the actual terrain. The tiles will be 65x65, and the total size of the
* terrain will be 513x513. It uses the heightmap we created to generate the height values.
*/
/**
* Optimal terrain patch size is 65 (64x64)
* If you go for small patch size, it will definitely slow down because the depth of
* the quad tree will increase, and more is done on the CPU then to traverse it.
* I plan to give each node in the tree a reference to its neighbours so that should
* resolve any of these slowdowns. -Brent
*
* The total size is up to you. At 1025 it ran fine for me (200+FPS), however at
* size=2049, it got really slow. But that is a jump from 2 million to 8 million triangles...
*/
terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());
List cameras = new ArrayList();
cameras.add(getCamera());
TerrainLodControl control = new TerrainLodControl(terrain, cameras);
terrain.addControl(control);
terrain.setMaterial(matRock);
terrain.setModelBound(new BoundingBox());
terrain.updateModelBound();
terrain.setLocalTranslation(0, -100, 0);
terrain.setLocalScale(2f, 1f, 2f);
rootNode.attachChild(terrain);
}
}
[/java]

it should work
bye

Hey, it’s cool!!

The only thing i’d see to improve it would be to use another drop texture.

i’d use just some kind of blurred white line, instead of an actual drop, it would increase the impression of speed of the drops, and would looks more realistic.

Yep I agree looks good so far,



there might be a posibility to increase the detail with pixel shaders for refraction fo lgiht ect, but thats a lot of work for a questionable gain. How about a raindrops on screen thingy ?



(Also is the demo just very fast, or is it because it is frame rate dependent?

Hi, thank you for the inspiration.