Here be the code… adding screens after all
Before the code… here is the usage:
[java]
// linear fog - mode, color, useless-density, start-distance, end-distance
FogFilter fog = new FogFilter(FogFilter.FOG_MODE.LINEAR, ColorRGBA.White, 1.0f, 50f, 150f);
// exp2 cam to distance fog - mode, color, density, distance, useless-distance-number
FogFilter fog = new FogFilter(FogFilter.FOG_MODE.EXP2_CAM_TO_DISTANCE, ColorRGBA.White, 1.0f, 50f, 150f);
// exp2 distance to infinity fog - mode, color, density, distance, useless-distance-number
FogFilter fog = new FogFilter(FogFilter.FOG_MODE.EXP2_DISTANCE_TO_INFINITY, ColorRGBA.White, 1.0f, 50f, 100f);
// Excluding sky bucket
fog.setExcludeSky(true);
[/java]
screens use the following setting with a change of modes:
[java]fog.setFogColor(new ColorRGBA(0.3f, 0.5f, 0.3f, 1.0f));
fog.setFogStartDistance(50f);
fog.setFogEndDistance(125f);
fog.setFogDensity(1.0f);
fog.setExcludeSky(true);[/java]
LINEAR:
EXP2_DISTANCE_TO_INFINITY:
EXP2_CAM_TO_DISTANCE:
Note about this filter:
The equations for calculating fog depth are home-brewed… so do me a favor and let me know if they are not matching up with your model scale so I can adjust them accordingly. As far as I can tell… they should be proper.
Other things to keep in mind:
Density has no effect on Linear fog.
1.0 is normal maximum density… however… in EXP2_DISTANCE_TO_INFINITY, raising this past 1.0 will bring infinity closer and closer
Density (0.0 to 1.0) in EXP2_CAMERA_TO_DISTANCE adjusts the exp2 curve of the fog. values outside of this range? I have no clue on > 1.0 … however, I doubt < 0.0 would do anything…
Filter:
FogFilter.java
[java]/*
- To change this template, choose Tools | Templates
- and open the template in the editor.
*/
package mygame;
import com.jme3.asset.AssetManager;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.post.Filter;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import java.io.IOException;
/**
- A filter to render the GLSL implementation of a fog effect
-
@author t0neg0d
*/
public class FogFilter extends Filter {
public static enum FOG_MODE {
LINEAR,
EXP2_CAM_TO_DISTANCE,
EXP2_DISTANCE_TO_INFINITY
}
private ColorRGBA fogColor = ColorRGBA.White.clone();
private float fogDensity = 1.0f;
private float fogStartDistance = 200f;
private float fogEndDistance = 500f;
private boolean excludeSky = false;
private FOG_MODE fogMode = FOG_MODE.EXP2_CAM_TO_DISTANCE;
/**
- Creates a FogFilter
*/
public FogFilter() {
super("FogFilter");
}
/**
- Create a fog filter
-
@param fogMode the mode to use for rendering fog (default is EXP2_CAM_TO_DISTANCE)
-
@param fogColor the color of the fog (default is white)
-
@param fogDensity the density of the fog (default is 1.0)
-
@param fogStartDistance Start distance is the absolute distance of the fog in mode EXP2_CAM_TO_DISTANCE and the start dstance in modes LINEAR and EXP2_DISTANCE_TO_INFINITY (default is 200)
-
@param fogEndDistance End distance (100% density) in mode LINEAR
*/
public FogFilter(FOG_MODE fogMode, ColorRGBA fogColor, float fogDensity, float fogStartDistance, float fogEndDistance) {
this();
this.fogMode = fogMode;
this.fogColor = fogColor;
this.fogDensity = fogDensity;
this.fogStartDistance = fogStartDistance;
this.fogEndDistance = fogEndDistance;
}
@Override
protected boolean isRequiresDepthTexture() {
return true;
}
@Override
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
material = new Material(manager, "MatDefs/Fog.j3md");
material.setInt("FogMode", fogMode.ordinal());
material.setColor("FogColor", fogColor);
material.setFloat("FogDensity", fogDensity);
material.setFloat("FogStartDistance", fogStartDistance);
material.setFloat("FogEndDistance", fogEndDistance);
material.setBoolean("ExcludeSky", excludeSky);
}
@Override
protected Material getMaterial() {
return material;
}
/**
- setsthe fog mode (default is EXP2_CAM_TO_DISTANCE)
-
@param fogMode
*/
public void setFogMode(FOG_MODE fogMode) {
if (material != null) {
material.setInt("FogMode", fogMode.ordinal());
}
this.fogMode = fogMode;
}
/**
- returns the fog mode (default is EXP2_CAM_TO_DISTANCE)
-
@return fogMode
*/
public FOG_MODE getFogMode() {
return this.fogMode;
}
/**
- returns the fog color
-
@return fogColor
*/
public ColorRGBA getFogColor() {
return fogColor;
}
/**
- Sets the color of the fog
-
@param fogColor
*/
public void setFogColor(ColorRGBA fogColor) {
if (material != null) {
material.setColor("FogColor", fogColor);
}
this.fogColor = fogColor;
}
/**
- returns the fog density
-
@return
*/
public float getFogDensity() {
return fogDensity;
}
/**
- Sets the density of the fog, a high value gives a thick fog
-
@param fogDensity
*/
public void setFogDensity(float fogDensity) {
if (material != null) {
material.setFloat("FogDensity", fogDensity);
}
this.fogDensity = fogDensity;
}
/**
- returns the fog start distance
-
@return fogStartDistance
*/
public float getFogStartDistance() {
return fogStartDistance;
}
/**
- Start distance is the absolute distance of the fog in mode EXP2_CAM_TO_DISTANCE and the start dstance in modes LINEAR and EXP2_DISTANCE_TO_INFINITY (default is 200)
-
@param fogStartDistance
*/
public void setFogStartDistance(float fogStartDistance) {
if (material != null) {
material.setFloat("FogStartDistance", fogStartDistance);
}
this.fogStartDistance = fogStartDistance;
}
/**
- returns the fog end distance
-
@return fogEndDistance
*/
public float getFogEndDistance() {
return fogEndDistance;
}
/**
- End distance (100% density) in mode LINEAR
-
@param fogEndDistance
*/
public void setFogEndDistance(float fogEndDistance) {
if (material != null) {
material.setFloat("FogEndDistance", fogEndDistance);
}
this.fogEndDistance = fogEndDistance;
}
/**
- Sets the exclude sky flag
-
@param excludeSky
*/
public void setExcludeSky(boolean excludeSky) {
if (material != null) {
material.setBoolean("ExcludeSky", excludeSky);
}
this.excludeSky = excludeSky;
}
/**
- returns the exclude sky flag
-
@return
*/
public boolean getExcludeSky() {
return excludeSky;
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(fogColor, "fogColor", ColorRGBA.White.clone());
oc.write(fogDensity, "fogDensity", 0.7f);
oc.write(fogStartDistance, "fogStartDistance", 200f);
oc.write(fogEndDistance, "fogEndDistance", 500f);
oc.write(excludeSky, "excludeSky", false);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
fogColor = (ColorRGBA) ic.readSavable("fogColor", ColorRGBA.White.clone());
fogDensity = ic.readFloat("fogDensity", 0.7f);
fogStartDistance = ic.readFloat("fogStartDistance", 200);
fogEndDistance = ic.readFloat("fogEndDistance", 500);
excludeSky = ic.readBoolean("excludeSky", false);
}
}
[/java]
Material Definition:
Fog.j3md
[java]MaterialDef Fog {
MaterialParameters {
Int NumSamples
Int NumSamplesDepth
Texture2D Texture
Texture2D DepthTexture
Int FogMode;
Vector4 FogColor;
Float FogDensity;
Float FogStartDistance;
Float FogEndDistance;
Boolean ExcludeSky : false
}
Technique {
VertexShader GLSL100: Common/MatDefs/Post/Post.vert
FragmentShader GLSL100: Shaders/Fog.frag
WorldParameters {
WorldViewProjectionMatrix
}
}
}[/java]
Shader:
Fog.frag
[java]uniform sampler2D m_Texture;
uniform sampler2D m_DepthTexture;
varying vec2 texCoord;
uniform int m_FogMode;
uniform vec4 m_FogColor;
uniform float m_FogDensity;
uniform float m_FogStartDistance;
uniform float m_FogEndDistance;
uniform bool m_ExcludeSky;
uniform float g_Time;
const float LOG2 = 1.442695;
float computeLinearFogFactor(in float depth, in vec2 frustumNear, in vec2 frustumFar) {
float depthS = (2.0 * frustumNear.x) / (frustumNear.y + frustumNear.x * (frustumNear.y - frustumNear.x));
float depthE = (2.0 * frustumFar.x) / (frustumFar.y + frustumFar.x * (frustumFar.y - frustumFar.x));
float fogDepth = 1.0/((frustumFar.y) /
(frustumNear.y - depth
(frustumNear.y)));
float fogFactor;
fogFactor = (depthE - fogDepth) / (depthE - depthS);
fogFactor = clamp( fogFactor, 0.0, 1.0 );
return fogFactor;
}
float computeExp2FogFactorC2D(in float depth, in vec2 frustumNear) {
float depthS = 1.0-(2.0 * frustumNear.x) / (frustumNear.y + frustumNear.x * (frustumNear.y-frustumNear.x));
float fogDepth = ((depthS) /
((frustumNear.y) - depth
((frustumNear.y))))(depthS4.0);
float fogFactor = 0.0;
if (depth < depthS)
fogFactor = exp2( -m_FogDensity * m_FogDensity * fogDepth * fogDepth * LOG2 );
fogFactor = clamp(fogFactor, 0.0, 1.0);
return fogFactor;
}
float computeExp2FogFactorD2I(in float depth, in vec2 frustumNear) {
float depthS = 1.0-(2.0 * frustumNear.x) / (frustumNear.y + frustumNear.x * (frustumNear.y-frustumNear.x));
float fogDepth = 1.0-((depthS) /
((frustumNear.y) - depth *
((frustumNear.y))));
float fogFactor = 1.0;
if (depth > depthS)
fogFactor = exp2( -m_FogDensity * m_FogDensity * fogDepth * fogDepth * LOG2 );
fogFactor = clamp(fogFactor, 0.0, 1.0);
return fogFactor;
}
void main() {
vec4 texVal = texture2D(m_Texture, texCoord);
float depth = texture2D(m_DepthTexture,texCoord).r;
vec2 frustumNear = vec2(1.0,m_FogStartDistance);
vec2 frustumFar = vec2(1.0,m_FogEndDistance);
float fogFactor;
if (m_FogMode == 0) fogFactor = computeLinearFogFactor(depth, frustumNear, frustumFar);
if (m_FogMode == 1) fogFactor = computeExp2FogFactorC2D(depth, frustumNear);
if (m_FogMode == 2) fogFactor = computeExp2FogFactorD2I(depth, frustumNear);
if (m_ExcludeSky) {
if (depth < 1.0)
gl_FragColor = mix(m_FogColor,texVal,fogFactor);
else
gl_FragColor = texVal;
} else
gl_FragColor = mix(m_FogColor,texVal,fogFactor);
}[/java]