package org.pollux3d.map;
import org.pollux3d.cam.CamTarget;
import org.pollux3d.core.Pollux;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.TangentBinormalGenerator;
/**
* This class contains the main parameters used in the shaders.
*
* @author mawi, jiyarza
*/
public class Planet extends MapEntity implements CamTarget, PlanetUpdateListener {
private static final String MESH_SPHERE = "Models/Sphere.mesh.j3o";
/**
* Number of sample rays to use in integral equation
* requires updateCalculations() on change
*/
private int nSamples = 3;
/**
* Atmosphere size factor
* atmosphere size = inner Radius * atmosphere size factor
* requires updateCalculations() on change
*/
private float atmosphereSizeFactor = 1.025f;
/**
* Rayleigh scattering constant
* requires updateCalculations() on change
*/
private float Kr = 0.0025f;
/**
* Mie scattering constant
* requires updateCalculations() on change
*/
private float Km = 0.0015f;
/**
* Sun brightness constant
* requires updateCalculations() on change
*/
private float ESun = 10f;
/**
* The scale depth (i.e. the altitude at which the atmosphere's average density is found)
* requires updateCalculations() on change
*/
private float scaleDepth = 0.25f;
/**
* TODO: add description
* requires updateCalculations() on change
*/
private Vector3f wavelength = new Vector3f(0.731f, 0.612f, 0.455f);
/**
* Atmosphere dim out factor
* Atmosphere starts to dim out after an camera distance of
* atmosphereDimOutFactor * innerRadius
*/
private float atmosphereDimOutFactor = 6f;
/**
* The Mie phase asymmetry factor
*/
private float G = -0.990f;
/**
* TODO: add description
*/
private float exposure = 2f;
/**
* Planet ground radius
*/
private float innerRadius;
/**
* Cloud rotation speed
*/
private float rotationSpeed = 0.00002f;
/**
* The position of the planet
*/
private Vector3f position;
/**
* Calculated by updateCalculations()
* 1 / (outerRadius - innerRadius)
*/
private float scale;
/**
* Calculated by updateCalculations()
* scale / scaleDepth
*/
private float scaleOverScaleDepth;
/**
* Calculated by updateCalculations()
* 1 / pow(wavelength, 4) for the red, green, and blue channels
*/
private Vector3f invWavelength4 = new Vector3f();
/**
* Calculated by updateCalculations()
* Kr * ESun
*/
private float KrESun;
/**
* Calculated by updateCalculations()
* Kr * 4 * PI
*/
private float Kr4PI;
/**
* Calculated by updateCalculations()
* Km * ESun
*/
private float KmESun;
/**
* Calculated by updateCalculations()
* Km * 4 * PI
*/
private float Km4PI;
/**
* AssetManager for textures and materials
*/
private AssetManager assetManager;
/**
* Planet ground spatial
*/
private Spatial ground;
/**
* Atmosphere sphere spatial
*/
private Spatial atmosphere;
/**
* Cloud sphere spatial
*/
private Spatial clouds;
/**
* Planet ground material
*/
private Material mPlanetGround;
/**
* Atmosphere sphere material
*/
private Material mAtmosphere;
public Planet(AssetManager assetManager, String name, String groundTexture, String cloudTexture, float radius, Vector3f position, boolean useAtmosphere, Vector3f atmosphereWavelength) {
super(name);
this.assetManager = assetManager;
if (atmosphereWavelength != null)
wavelength = atmosphereWavelength;
setRadius(radius);
setPosition(position);
updateCalculations();
// Create spatials and materials
if (groundTexture != null) {
createGround(groundTexture);
Pollux.get().getGeometryManager().registerGeometry((Geometry) ((Node) ground).getChild(0), this);
}
if (useAtmosphere)
createAtmosphere();
if (cloudTexture != null)
createClouds(cloudTexture);
// register with pollux core
Pollux.get().getStateManager().getPlanetAnimation().registerPlanet(this);
this.setCullHint(CullHint.Never);
// attach the spatials
if (groundTexture != null)
attachChild(ground);
if (useAtmosphere)
attachChild(atmosphere);
if (cloudTexture != null)
attachChild(clouds);
}
/**
* Call this method after changing parameter values
*/
public void updateCalculations() {
scale = 1.0f / ((innerRadius * atmosphereSizeFactor) - innerRadius);
scaleOverScaleDepth = scale / scaleDepth;
KrESun = Kr * ESun;
KmESun = Km * ESun;
Kr4PI = Kr * 4.0f * FastMath.PI;
Km4PI = Km * 4.0f * FastMath.PI;
invWavelength4.x = 1.0f / FastMath.pow(wavelength.x, 4.0f);
invWavelength4.y = 1.0f / FastMath.pow(wavelength.y, 4.0f);
invWavelength4.z = 1.0f / FastMath.pow(wavelength.z, 4.0f);
}
private void createGround(String groundTexture) {
Spatial geom = createSphere();
geom.scale(getInnerRadius());
mPlanetGround = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
mPlanetGround.setTexture("DiffuseMap", assetManager.loadTexture(groundTexture));
mPlanetGround.setTexture("GlowMap", assetManager.loadTexture("Textures/Planets/Earth/Earthlights2_1280.jpg"));
mPlanetGround.setFloat("Shininess", 0.01f); // [1,128]
geom.setMaterial(mPlanetGround);
geom.setLocalTranslation(getPosition());
TangentBinormalGenerator.generate(geom);
geom.updateModelBound();
ground = geom;
}
private void createClouds(String cloudTexture) {
Spatial geom = createSphere();
geom.scale(getCloudRadius());
Material mClouds = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
mClouds.setTexture("DiffuseMap", assetManager.loadTexture(cloudTexture));
mClouds.setFloat("Shininess", 0.01f); // [1,128]
mClouds.getAdditionalRenderState().setBlendMode(BlendMode.AlphaAdditive);
geom.setMaterial(mClouds);
geom.setLocalTranslation(getPosition());
TangentBinormalGenerator.generate(geom);
geom.updateModelBound();
clouds = geom;
}
private void createAtmosphere() {
// create the spatial
atmosphere = createSphere();
atmosphere.scale(getOuterRadius());
atmosphere.setLocalTranslation(getPosition());
atmosphere.setQueueBucket(Bucket.Transparent);
atmosphere.setMaterial(mAtmosphere);
TangentBinormalGenerator.generate(atmosphere);
atmosphere.updateModelBound();
//create the material
mAtmosphere = new Material(assetManager, "MatDefs/Atmosphere.j3md");
mAtmosphere.setVector3("v3LightPos", new Vector3f(1,0,0));
mAtmosphere.setVector3("v3Center", position);
mAtmosphere.setVector3("v3InvWavelength", this.getInvWavelength4());
mAtmosphere.setFloat("fKrESun", this.getKrESun());
mAtmosphere.setFloat("fKmESun", this.getKmESun());
mAtmosphere.setFloat("fOuterRadius", this.getOuterRadius());
mAtmosphere.setFloat("fInnerRadius", this.getInnerRadius());
mAtmosphere.setFloat("fOuterRadius2", this.getOuterRadius() * this.getOuterRadius());
mAtmosphere.setFloat("fInnerRadius2", this.getInnerRadius() * this.getInnerRadius());
mAtmosphere.setFloat("fKr4PI", this.getKr4PI());
mAtmosphere.setFloat("fKm4PI", this.getKm4PI());
mAtmosphere.setFloat("fScale", this.getScale());
mAtmosphere.setFloat("fScaleDepth", this.getScaleDepth());
mAtmosphere.setFloat("fScaleOverScaleDepth", this.getScaleOverScaleDepth());
mAtmosphere.setFloat("fSamples", this.getfSamples());
mAtmosphere.setInt("nSamples", this.getnSamples());
mAtmosphere.setFloat("fg", this.getG());
mAtmosphere.setFloat("fg2", this.getG() * this.getG());
mAtmosphere.setFloat("fExposure", this.getExposure());
mAtmosphere.setFloat("fCameraHeightDimOut", this.getInnerRadius()*this.getAtmosphereDimOut());
atmosphere.setMaterial(mAtmosphere);
}
private Spatial createSphere() {
Spatial sphere = assetManager.loadModel(MESH_SPHERE);
sphere.scale(0.25f);
return sphere;
}
public void update(float tpf, Vector3f cameraLocation, Vector3f sunLocation) {
Vector3f lightPosNormalized = sunLocation.subtract(getPosition()).normalize();
Vector3f planetToCamera = cameraLocation.subtract(getPosition());
float cameraHeight = planetToCamera.length();
// rotate the clouds
if (clouds != null)
clouds.rotate(0, rotationSpeed, 0);
if (mAtmosphere != null) {
// update the atmosphere material
mAtmosphere.setVector3("v3CameraPos", cameraLocation);
mAtmosphere.setVector3("v3LightPos", lightPosNormalized);
mAtmosphere.setVector3("v3Center", position);
mAtmosphere.setFloat("fCameraHeight", cameraHeight);
mAtmosphere.setFloat("fCameraHeight2", cameraHeight * cameraHeight);
mAtmosphere.setVector3("v3InvWavelength", getInvWavelength4());
mAtmosphere.setFloat("fKrESun", getKrESun());
mAtmosphere.setFloat("fKmESun", getKmESun());
mAtmosphere.setFloat("fKr4PI", getKr4PI());
mAtmosphere.setFloat("fKm4PI", getKm4PI());
mAtmosphere.setFloat("fg", getG());
mAtmosphere.setFloat("fg2", getG() * getG());
mAtmosphere.setFloat("fExposure", getExposure());
atmosphere.setMaterial(mAtmosphere);
}
}
// customizable values
public void setRadius(float radius) { this.innerRadius = radius; }
public void setPosition(Vector3f pos) { position = pos; }
public void setKr(float Kr) { this.Kr = Kr; }
public void setKm(float Km) { this.Km = Km; }
public void setESun(float ESun) { this.ESun = ESun; }
public void setG(float G) { this.G = G; }
public void setRed(float w) { wavelength.x = w; }
public void setGreen(float w) { wavelength.y = w; }
public void setBlue(float w) { wavelength.z = w; }
public void setSamples(int n) { nSamples = n; }
public void setExposure(float f) { exposure = f; }
public void setRotationSpeed(float speed) { this.rotationSpeed = speed; }
public void setAtmosphereDimOut(float factor) { this.atmosphereDimOutFactor = factor; }
// Getters
public float getRadius() { return innerRadius; }
public Vector3f getPosition() { return position; }
public int getnSamples() { return nSamples; }
public float getfSamples() { return (float) nSamples; }
public float getKr() { return Kr; }
public float getKrESun() { return KrESun; }
public float getKr4PI() { return Kr4PI; }
public float getKm() { return Km; }
public float getKmESun() { return KmESun; }
public float getKm4PI() { return Km4PI; }
public float getESun() { return ESun; }
public float getG() { return G; }
public float getInnerRadius() { return innerRadius; }
public float getOuterRadius() { return innerRadius * atmosphereSizeFactor; }
public float getCloudRadius() { return innerRadius * 1.001f; }
public float getScale() { return scale; }
public float getScaleDepth() { return scaleDepth; }
public float getScaleOverScaleDepth() { return scaleOverScaleDepth; }
public Vector3f getWavelength() { return wavelength; }
public Vector3f getInvWavelength4() { return invWavelength4; }
public float getExposure() { return exposure; }
public float getRotationSpeed() { return rotationSpeed; }
public float getAtmosphereDimOut() { return atmosphereDimOutFactor; }
@Override
public float getZoomDistance() {
return 180;
}
public Spatial getTarget() {
return this;
}
/* (non-Javadoc)
* @see com.jme3.scene.Spatial#getLocalTranslation()
*/
@Override
public Vector3f getLocalTranslation() {
return getPosition();
}
}