diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag index 9b8aa2709..32f353578 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag @@ -6,6 +6,26 @@ #import "Common/ShaderLib/Lighting.glsllib" #endif +// fog - jayfella +#ifdef USE_FOG +#import "Common/ShaderLib/MaterialFog.glsllib" +varying float fog_distance; +uniform vec4 m_FogColor; + +#ifdef FOG_LINEAR +uniform vec2 m_LinearFog; +#endif + +#ifdef FOG_EXP +uniform float m_ExpFog; +#endif + +#ifdef FOG_EXPSQ +uniform float m_ExpSqFog; +#endif + +#endif // end fog + varying vec2 texCoord; #ifdef SEPARATE_TEXCOORD varying vec2 texCoord2; @@ -115,6 +135,7 @@ void main(){ #endif + // *********************** // Read from textures // *********************** @@ -207,5 +228,22 @@ void main(){ DiffuseSum.rgb * diffuseColor.rgb * vec3(light.x) + SpecularSum2.rgb * specularColor.rgb * vec3(light.y); #endif + + + // add fog after the lighting because shadows will cause the fog to darken + // which just results in the geometry looking like it's changed color + #ifdef USE_FOG + #ifdef FOG_LINEAR + gl_FragColor = getFogLinear(gl_FragColor, m_FogColor, m_LinearFog.x, m_LinearFog.y, fog_distance); + #endif + #ifdef FOG_EXP + gl_FragColor = getFogExp(gl_FragColor, m_FogColor, m_ExpFog, fog_distance); + #endif + #ifdef FOG_EXPSQ + gl_FragColor = getFogExpSquare(gl_FragColor, m_FogColor, m_ExpSqFog, fog_distance); + #endif + #endif // end fog + + gl_FragColor.a = alpha; } diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md index 2a8847324..824a17369 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md @@ -120,6 +120,14 @@ MaterialDef Phong Lighting { Boolean UseInstancing Boolean BackfaceShadows : false + + // fog - jayfella + Boolean UseFog + Color FogColor + Vector2 LinearFog + Float ExpFog + Float ExpSqFog + } Technique { @@ -159,6 +167,12 @@ MaterialDef Phong Lighting { INSTANCING : UseInstancing NUM_MORPH_TARGETS: NumberOfMorphTargets NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers + + // fog - jayfella + USE_FOG : UseFog + FOG_LINEAR : LinearFog + FOG_EXP : ExpFog + FOG_EXPSQ : ExpSqFog } } @@ -200,6 +214,12 @@ MaterialDef Phong Lighting { INSTANCING : UseInstancing NUM_MORPH_TARGETS: NumberOfMorphTargets NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers + + // fog - jayfella + USE_FOG : UseFog + FOG_LINEAR : LinearFog + FOG_EXP : ExpFog + FOG_EXPSQ : ExpSqFog } } diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert index 6c74a7557..390c1f1a4 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert @@ -8,6 +8,11 @@ #import "Common/ShaderLib/BlinnPhongLighting.glsllib" #endif +// fog - jayfella +#ifdef USE_FOG +varying float fog_distance; +uniform vec3 g_CameraPosition; +#endif uniform vec4 m_Ambient; uniform vec4 m_Diffuse; @@ -178,5 +183,9 @@ void main(){ #ifdef USE_REFLECTION computeRef(modelSpacePos); - #endif + #endif + + #ifdef USE_FOG + fog_distance = distance(g_CameraPosition, (g_WorldMatrix * modelSpacePos).xyz); + #endif } \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag index a510fc1db..2b5a4481c 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag @@ -6,6 +6,26 @@ #import "Common/ShaderLib/Lighting.glsllib" #endif +// fog - jayfella +#ifdef USE_FOG +#import "Common/ShaderLib/MaterialFog.glsllib" +varying float fog_distance; +uniform vec4 m_FogColor; + +#ifdef FOG_LINEAR +uniform vec2 m_LinearFog; +#endif + +#ifdef FOG_EXP +uniform float m_ExpFog; +#endif + +#ifdef FOG_EXPSQ +uniform float m_ExpSqFog; +#endif + +#endif // end fog + varying vec2 texCoord; #ifdef SEPARATE_TEXCOORD varying vec2 texCoord2; @@ -226,5 +246,20 @@ void main(){ } #endif + + // add fog after the lighting because shadows will cause the fog to darken + // which just results in the geometry looking like it's changed color + #ifdef USE_FOG + #ifdef FOG_LINEAR + gl_FragColor = getFogLinear(gl_FragColor, m_FogColor, m_LinearFog.x, m_LinearFog.y, fog_distance); + #endif + #ifdef FOG_EXP + gl_FragColor = getFogExp(gl_FragColor, m_FogColor, m_ExpFog, fog_distance); + #endif + #ifdef FOG_EXPSQ + gl_FragColor = getFogExpSquare(gl_FragColor, m_FogColor, m_ExpSqFog, fog_distance); + #endif + #endif // end fog + gl_FragColor.a = alpha; } diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert index f9fbe40cf..71233819b 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert @@ -8,6 +8,11 @@ #import "Common/ShaderLib/BlinnPhongLighting.glsllib" #endif +// fog - jayfella +#ifdef USE_FOG +varying float fog_distance; +uniform vec3 g_CameraPosition; +#endif uniform vec4 m_Ambient; uniform vec4 m_Diffuse; @@ -187,5 +192,9 @@ void main(){ #ifdef USE_REFLECTION computeRef(modelSpacePos); - #endif + #endif + + #ifdef USE_FOG + fog_distance = distance(g_CameraPosition, (g_WorldMatrix * modelSpacePos).xyz); + #endif } \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/ShaderLib/MaterialFog.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/MaterialFog.glsllib new file mode 100644 index 000000000..912be9d4c --- /dev/null +++ b/jme3-core/src/main/resources/Common/ShaderLib/MaterialFog.glsllib @@ -0,0 +1,25 @@ + +vec4 getFogLinear(in vec4 diffuseColor, in vec4 fogColor, in float start, in float end, in float distance) { + + float fogFactor = (end - distance) / (end - start); + fogFactor = clamp(fogFactor, 0.0, 1.0); + + return mix(fogColor, diffuseColor, fogFactor); +} + +vec4 getFogExp(in vec4 diffuseColor, in vec4 fogColor, in float fogDensity, in float distance) { + + float fogFactor = 1.0 / exp(distance * fogDensity); + fogFactor = clamp( fogFactor, 0.0, 1.0 ); + + return mix(fogColor, diffuseColor, fogFactor); +} + +vec4 getFogExpSquare(in vec4 diffuseColor, in vec4 fogColor, in float fogDensity, in float distance) { + + float fogFactor = 1.0 / exp( (distance * fogDensity) * (distance * fogDensity)); + fogFactor = clamp( fogFactor, 0.0, 1.0 ); + + vec4 finalColor = mix(fogColor, diffuseColor, fogFactor); + return finalColor; +} \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/light/TestLightingFog.java b/jme3-examples/src/main/java/jme3test/light/TestLightingFog.java new file mode 100644 index 000000000..adcb24a0c --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/light/TestLightingFog.java @@ -0,0 +1,79 @@ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +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.Materials; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Sphere; + +public class TestLightingFog extends SimpleApplication implements ActionListener { + + private Material material; + private Vector2f linear = new Vector2f(25, 120); + private float exp = 0.015f; + private float expsq = 0.02f; + + public static void main(String[] args) { + TestLightingFog testLightingFog = new TestLightingFog(); + testLightingFog.start(); + } + + @Override + public void simpleInitApp() { + + ColorRGBA skyColor = new ColorRGBA(0.5f, 0.6f, 0.7f, 0.0f); + + flyCam.setMoveSpeed(20); + viewPort.setBackgroundColor(skyColor.mult(0.9f)); + + DirectionalLight directionalLight = new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal()); + rootNode.addLight(directionalLight); + + material = new Material(assetManager, Materials.LIGHTING); + material.setBoolean("UseFog", true); + material.setColor("FogColor", skyColor); + material.setVector2("LinearFog", linear); + + int distance = -3; + + for (int i = 0; i < 100; i++) { + Geometry geometry = new Geometry("Sphere", new Sphere(32, 32, 2)); + geometry.setMaterial(material); + + geometry.setLocalTranslation((FastMath.nextRandomFloat() - 0.5f) * 45, 0, i * distance); + rootNode.attachChild(geometry); + } + + inputManager.addMapping("Linear", new KeyTrigger(KeyInput.KEY_1)); + inputManager.addMapping("Exponential", new KeyTrigger(KeyInput.KEY_2)); + inputManager.addMapping("ExponentialSquared", new KeyTrigger(KeyInput.KEY_3)); + inputManager.addListener(this, "Linear", "Exponential", "ExponentialSquared"); + } + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("Linear") && !isPressed) { + material.setVector2("LinearFog", linear); + material.clearParam("ExpFog"); + material.clearParam("ExpSqFog"); + } + else if (name.equals("Exponential") && !isPressed) { + material.clearParam("LinearFog"); + material.setFloat("ExpFog", exp); + material.clearParam("ExpSqFog"); + } + else if (name.equals("ExponentialSquared") && !isPressed) { + material.clearParam("LinearFog"); + material.clearParam("ExpFog"); + material.setFloat("ExpSqFog", expsq); + } + } +}