aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core-effects
diff options
context:
space:
mode:
authorScott Barta <sbarta@google.com>2012-03-01 12:35:35 -0800
committerScott Barta <sbarta@google.com>2012-03-01 12:40:08 -0800
commit59b2e6871c65f58fdad78cd7229c292f6a177578 (patch)
tree2d4e7bfc05b93f40b34675d77e403dd1c25efafd /engine/src/core-effects
parentf9b30489e75ac1eabc365064959804e99534f7ab (diff)
downloadjmonkeyengine-59b2e6871c65f58fdad78cd7229c292f6a177578.tar.gz
Adds the jMonkeyEngine library to the build.
Adds the jMonkeyEngine open source 3D game engine to the build. This is built as a static library and is only used by the Finsky client. Change-Id: I06a3f054df7b8a67757267d884854f70c5a16ca0
Diffstat (limited to 'engine/src/core-effects')
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/BloomExtract.j3md43
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/BloomFinal.j3md36
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.frag55
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.j3md48
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/CartoonEdge15.frag57
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/CrossHatch.frag51
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/CrossHatch.j3md41
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/CrossHatch15.frag53
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/DepthOfField.frag89
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/DepthOfField.j3md25
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/FXAA.frag88
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/FXAA.j3md20
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/FXAA.vert18
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Fade.frag11
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Fade.j3md34
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Fade15.frag11
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Fog.frag21
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Fog.j3md39
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Fog15.frag24
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.frag23
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.j3md39
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/GammaCorrection15.frag26
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/LightScattering.frag36
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/LightScattering.j3md41
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/LightScattering.vert14
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/LightScattering15.frag39
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/LightScattering15.vert14
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Overlay.frag9
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Overlay.j3md36
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Overlay15.frag11
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Post.vert10
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Post15.vert12
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Posterization.frag18
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Posterization.j3md32
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/Posterization15.frag20
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/bloomExtract.frag29
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/bloomExtract15.frag33
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/bloomFinal.frag12
-rw-r--r--engine/src/core-effects/Common/MatDefs/Post/bloomFinal15.frag15
-rw-r--r--engine/src/core-effects/Common/MatDefs/SSAO/Textures/random.pngbin0 -> 42993 bytes
-rw-r--r--engine/src/core-effects/Common/MatDefs/SSAO/normal.frag21
-rw-r--r--engine/src/core-effects/Common/MatDefs/SSAO/normal.vert16
-rw-r--r--engine/src/core-effects/Common/MatDefs/SSAO/ssao.frag104
-rw-r--r--engine/src/core-effects/Common/MatDefs/SSAO/ssao.j3md51
-rw-r--r--engine/src/core-effects/Common/MatDefs/SSAO/ssao15.frag96
-rw-r--r--engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.frag159
-rw-r--r--engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.j3md57
-rw-r--r--engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur15.frag160
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/SimpleWater.j3md34
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Textures/caustics.jpgbin0 -> 57225 bytes
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Textures/dudv_map.jpgbin0 -> 39633 bytes
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Textures/foam.jpgbin0 -> 65823 bytes
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Textures/foam2.jpgbin0 -> 80871 bytes
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Textures/foam3.jpgbin0 -> 100447 bytes
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Textures/heightmap.jpgbin0 -> 24995 bytes
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Textures/water_normalmap.ddsbin0 -> 32896 bytes
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Water.frag402
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Water.j3md90
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Water15.frag419
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/simple_water.frag126
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/simple_water.vert87
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/BloomFilter.java309
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java245
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java111
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java305
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java158
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java95
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/FadeFilter.java177
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/FogFilter.java172
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java78
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java243
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java147
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java156
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java80
-rw-r--r--engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java324
-rw-r--r--engine/src/core-effects/com/jme3/water/ReflectionProcessor.java125
-rw-r--r--engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java589
-rw-r--r--engine/src/core-effects/com/jme3/water/WaterFilter.java1050
78 files changed, 7419 insertions, 0 deletions
diff --git a/engine/src/core-effects/Common/MatDefs/Post/BloomExtract.j3md b/engine/src/core-effects/Common/MatDefs/Post/BloomExtract.j3md
new file mode 100644
index 0000000..76614cc
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/BloomExtract.j3md
@@ -0,0 +1,43 @@
+MaterialDef Bloom {
+
+ MaterialParameters {
+ Int NumSamples
+ Texture2D Texture
+ Float ExposurePow
+ Float ExposureCutoff
+ Boolean Extract
+ Texture2D GlowMap
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/bloomExtract15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ HAS_GLOWMAP : GlowMap
+ DO_EXTRACT : Extract
+ RESOLVE_MS : NumSamples
+ }
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/bloomExtract.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ HAS_GLOWMAP : GlowMap
+ DO_EXTRACT : Extract
+ }
+ }
+
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/BloomFinal.j3md b/engine/src/core-effects/Common/MatDefs/Post/BloomFinal.j3md
new file mode 100644
index 0000000..68f8c28
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/BloomFinal.j3md
@@ -0,0 +1,36 @@
+MaterialDef Bloom Final {
+
+ MaterialParameters {
+ Int NumSamples
+ Texture2D Texture
+ Texture2D BloomTex
+ Float BloomIntensity
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/bloomFinal15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ RESOLVE_MS : NumSamples
+ }
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/bloomFinal.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+
+
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.frag b/engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.frag
new file mode 100644
index 0000000..7ee7f78
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.frag
@@ -0,0 +1,55 @@
+uniform vec4 m_EdgeColor;
+
+uniform float m_EdgeWidth;
+uniform float m_EdgeIntensity;
+
+uniform float m_NormalThreshold;
+uniform float m_DepthThreshold;
+
+uniform float m_NormalSensitivity;
+uniform float m_DepthSensitivity;
+
+varying vec2 texCoord;
+
+uniform sampler2D m_Texture;
+uniform sampler2D m_NormalsTexture;
+uniform sampler2D m_DepthTexture;
+
+uniform vec2 g_Resolution;
+
+vec4 fetchNormalDepth(vec2 tc){
+ vec4 nd;
+ nd.xyz = texture2D(m_NormalsTexture, tc).rgb;
+ nd.w = texture2D(m_DepthTexture, tc).r;
+ return nd;
+}
+
+void main(){
+ vec3 color = texture2D(m_Texture, texCoord).rgb;
+
+ vec2 edgeOffset = vec2(m_EdgeWidth) / g_Resolution;
+
+ vec4 n1 = fetchNormalDepth(texCoord + vec2(-1.0, -1.0) * edgeOffset);
+ vec4 n2 = fetchNormalDepth(texCoord + vec2( 1.0, 1.0) * edgeOffset);
+ vec4 n3 = fetchNormalDepth(texCoord + vec2(-1.0, 1.0) * edgeOffset);
+ vec4 n4 = fetchNormalDepth(texCoord + vec2( 1.0, -1.0) * edgeOffset);
+
+ // Work out how much the normal and depth values are changing.
+ vec4 diagonalDelta = abs(n1 - n2) + abs(n3 - n4);
+
+ float normalDelta = dot(diagonalDelta.xyz, vec3(1.0));
+ float depthDelta = diagonalDelta.w;
+
+ // Filter out very small changes, in order to produce nice clean results.
+ normalDelta = clamp((normalDelta - m_NormalThreshold) * m_NormalSensitivity, 0.0, 1.0);
+ depthDelta = clamp((depthDelta - m_DepthThreshold) * m_DepthSensitivity, 0.0, 1.0);
+
+ // Does this pixel lie on an edge?
+ float edgeAmount = clamp(normalDelta + depthDelta, 0.0, 1.0) * m_EdgeIntensity;
+
+ // Apply the edge detection result to the main scene color.
+ //color *= (1.0 - edgeAmount);
+ color = mix (color,m_EdgeColor.rgb,edgeAmount);
+
+ gl_FragColor = vec4(color, 1.0);
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.j3md b/engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.j3md
new file mode 100644
index 0000000..687193e
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.j3md
@@ -0,0 +1,48 @@
+MaterialDef Cartoon Edge {
+
+ MaterialParameters {
+ Int NumSamples
+ Int NumSamplesDepth
+ Texture2D Texture
+ Texture2D NormalsTexture
+ Texture2D DepthTexture
+ Color EdgeColor
+ Float EdgeWidth
+ Float EdgeIntensity
+ Float NormalThreshold
+ Float DepthThreshold
+ Float NormalSensitivity
+ Float DepthSensitivity
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/CartoonEdge15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldViewMatrix
+ Resolution
+ }
+
+ Defines {
+ RESOLVE_MS : NumSamples
+ RESOLVE_DEPTH_MS : NumSamplesDepth
+ }
+ }
+
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/CartoonEdge.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldViewMatrix
+ Resolution
+ }
+ }
+
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/CartoonEdge15.frag b/engine/src/core-effects/Common/MatDefs/Post/CartoonEdge15.frag
new file mode 100644
index 0000000..3c3921a
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/CartoonEdge15.frag
@@ -0,0 +1,57 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+uniform sampler2D m_NormalsTexture;
+uniform vec2 g_Resolution;
+
+uniform vec4 m_EdgeColor;
+
+uniform float m_EdgeWidth;
+uniform float m_EdgeIntensity;
+
+uniform float m_NormalThreshold;
+uniform float m_DepthThreshold;
+
+uniform float m_NormalSensitivity;
+uniform float m_DepthSensitivity;
+
+in vec2 texCoord;
+out vec4 outFragColor;
+
+vec4 fetchNormalDepth(vec2 tc){
+ vec4 nd;
+ nd.xyz = texture2D(m_NormalsTexture, tc).rgb;
+ nd.w = fetchTextureSample(m_DepthTexture, tc,0).r;
+ return nd;
+}
+
+void main(){
+ vec3 color = getColor(m_Texture, texCoord).rgb;
+
+ vec2 edgeOffset = vec2(m_EdgeWidth) / textureSize(m_NormalsTexture, 0);
+ vec4 n1 = fetchNormalDepth(texCoord + vec2(-1.0, -1.0) * edgeOffset);
+ vec4 n2 = fetchNormalDepth(texCoord + vec2( 1.0, 1.0) * edgeOffset);
+ vec4 n3 = fetchNormalDepth(texCoord + vec2(-1.0, 1.0) * edgeOffset);
+ vec4 n4 = fetchNormalDepth(texCoord + vec2( 1.0, -1.0) * edgeOffset);
+
+ // Work out how much the normal and depth values are changing.
+ vec4 diagonalDelta = abs(n1 - n2) + abs(n3 - n4);
+
+ float normalDelta = dot(diagonalDelta.xyz, vec3(1.0));
+ float depthDelta = diagonalDelta.w;
+
+ // Filter out very small changes, in order to produce nice clean results.
+ normalDelta = clamp((normalDelta - m_NormalThreshold) * m_NormalSensitivity, 0.0, 1.0);
+ depthDelta = clamp((depthDelta - m_DepthThreshold) * m_DepthSensitivity, 0.0, 1.0);
+
+ // Does this pixel lie on an edge?
+ float edgeAmount = clamp(normalDelta + depthDelta, 0.0, 1.0) * m_EdgeIntensity;
+
+ // Apply the edge detection result to the main scene color.
+ //color *= (1.0 - edgeAmount);
+ color = mix (color,m_EdgeColor.rgb,edgeAmount);
+
+ outFragColor = vec4(color, 1.0);
+}
diff --git a/engine/src/core-effects/Common/MatDefs/Post/CrossHatch.frag b/engine/src/core-effects/Common/MatDefs/Post/CrossHatch.frag
new file mode 100644
index 0000000..fc700f8
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/CrossHatch.frag
@@ -0,0 +1,51 @@
+uniform sampler2D m_Texture;
+varying vec2 texCoord;
+
+uniform vec4 m_LineColor;
+uniform vec4 m_PaperColor;
+uniform float m_ColorInfluenceLine;
+uniform float m_ColorInfluencePaper;
+
+uniform float m_FillValue;
+uniform float m_Luminance1;
+uniform float m_Luminance2;
+uniform float m_Luminance3;
+uniform float m_Luminance4;
+uniform float m_Luminance5;
+
+uniform float m_LineDistance;
+uniform float m_LineThickness;
+
+void main() {
+ vec4 texVal = texture2D(m_Texture, texCoord);
+ float linePixel = 0.0;
+
+ float lum = texVal.r*0.2126 + texVal.g*0.7152 + texVal.b*0.0722;
+
+ if (lum < m_Luminance1){
+ if (mod(gl_FragCoord.x + gl_FragCoord.y, m_LineDistance * 2.0) < m_LineThickness)
+ linePixel = 1.0;
+ }
+ if (lum < m_Luminance2){
+ if (mod(gl_FragCoord.x - gl_FragCoord.y, m_LineDistance * 2.0) < m_LineThickness)
+ linePixel = 1.0;
+ }
+ if (lum < m_Luminance3){
+ if (mod(gl_FragCoord.x + gl_FragCoord.y - m_LineDistance, m_LineDistance) < m_LineThickness)
+ linePixel = 1.0;
+ }
+ if (lum < m_Luminance4){
+ if (mod(gl_FragCoord.x - gl_FragCoord.y - m_LineDistance, m_LineDistance) < m_LineThickness)
+ linePixel = 1.0;
+ }
+ if (lum < m_Luminance5){ // No line, make a blob instead
+ linePixel = m_FillValue;
+ }
+
+ // Mix line color with existing color information
+ vec4 lineColor = mix(m_LineColor, texVal, m_ColorInfluenceLine);
+ // Mix paper color with existing color information
+ vec4 paperColor = mix(m_PaperColor, texVal, m_ColorInfluencePaper);
+
+ gl_FragColor = mix(paperColor, lineColor, linePixel);
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/CrossHatch.j3md b/engine/src/core-effects/Common/MatDefs/Post/CrossHatch.j3md
new file mode 100644
index 0000000..bf850dc
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/CrossHatch.j3md
@@ -0,0 +1,41 @@
+MaterialDef CrossHatch {
+
+ MaterialParameters {
+ Int NumSamples
+ Texture2D Texture;
+ Vector4 LineColor;
+ Vector4 PaperColor;
+ Float ColorInfluenceLine;
+ Float ColorInfluencePaper;
+ Float FillValue;
+ Float Luminance1;
+ Float Luminance2;
+ Float Luminance3;
+ Float Luminance4;
+ Float Luminance5;
+ Float LineThickness;
+ Float LineDistance;
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/CrossHatch15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/CrossHatch.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique FixedFunc {
+ }
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/CrossHatch15.frag b/engine/src/core-effects/Common/MatDefs/Post/CrossHatch15.frag
new file mode 100644
index 0000000..8daa4f7
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/CrossHatch15.frag
@@ -0,0 +1,53 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+in vec2 texCoord;
+
+uniform vec4 m_LineColor;
+uniform vec4 m_PaperColor;
+uniform float m_ColorInfluenceLine;
+uniform float m_ColorInfluencePaper;
+
+uniform float m_FillValue;
+uniform float m_Luminance1;
+uniform float m_Luminance2;
+uniform float m_Luminance3;
+uniform float m_Luminance4;
+uniform float m_Luminance5;
+
+uniform float m_LineDistance;
+uniform float m_LineThickness;
+
+void main() {
+ vec4 texVal = getColor(m_Texture, texCoord);
+ float linePixel = 0;
+
+ float lum = texVal.r*0.2126 + texVal.g*0.7152 + texVal.b*0.0722;
+
+ if (lum < m_Luminance1){
+ if (mod(gl_FragCoord.x + gl_FragCoord.y, m_LineDistance * 2.0) < m_LineThickness)
+ linePixel = 1;
+ }
+ if (lum < m_Luminance2){
+ if (mod(gl_FragCoord.x - gl_FragCoord.y, m_LineDistance * 2.0) < m_LineThickness)
+ linePixel = 1;
+ }
+ if (lum < m_Luminance3){
+ if (mod(gl_FragCoord.x + gl_FragCoord.y - m_LineDistance, m_LineDistance) < m_LineThickness)
+ linePixel = 1;
+ }
+ if (lum < m_Luminance4){
+ if (mod(gl_FragCoord.x - gl_FragCoord.y - m_LineDistance, m_LineDistance) < m_LineThickness)
+ linePixel = 1;
+ }
+ if (lum < m_Luminance5){ // No line, make a blob instead
+ linePixel = m_FillValue;
+ }
+
+ // Mix line color with existing color information
+ vec4 lineColor = mix(m_LineColor, texVal, m_ColorInfluenceLine);
+ // Mix paper color with existing color information
+ vec4 paperColor = mix(m_PaperColor, texVal, m_ColorInfluencePaper);
+
+ gl_FragColor = mix(paperColor, lineColor, linePixel);
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/DepthOfField.frag b/engine/src/core-effects/Common/MatDefs/Post/DepthOfField.frag
new file mode 100644
index 0000000..658da54
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/DepthOfField.frag
@@ -0,0 +1,89 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+varying vec2 texCoord;
+
+uniform float m_FocusRange;
+uniform float m_FocusDistance;
+uniform float m_XScale;
+uniform float m_YScale;
+
+vec2 m_NearFar = vec2( 0.1, 1000.0 );
+
+void main() {
+
+ vec4 texVal = texture2D( m_Texture, texCoord );
+
+ float zBuffer = texture2D( m_DepthTexture, texCoord ).r;
+
+ //
+ // z_buffer_value = a + b / z;
+ //
+ // Where:
+ // a = zFar / ( zFar - zNear )
+ // b = zFar * zNear / ( zNear - zFar )
+ // z = distance from the eye to the object
+ //
+ // Which means:
+ // zb - a = b / z;
+ // z * (zb - a) = b
+ // z = b / (zb - a)
+ //
+ float a = m_NearFar.y / (m_NearFar.y - m_NearFar.x);
+ float b = m_NearFar.y * m_NearFar.x / (m_NearFar.x - m_NearFar.y);
+ float z = b / (zBuffer - a);
+
+ // Above could be the same for any depth-based filter
+
+ // We want to be purely focused right at
+ // m_FocusDistance and be purely unfocused
+ // at +/- m_FocusRange to either side of that.
+ float unfocus = min( 1.0, abs( z - m_FocusDistance ) / m_FocusRange );
+
+ if( unfocus < 0.2 ) {
+ // If we are mostly in focus then don't bother with the
+ // convolution filter
+ gl_FragColor = texVal;
+ } else {
+ // Perform a wide convolution filter and we scatter it
+ // a bit to avoid some texture look-ups. Instead of
+ // a full 5x5 (25-1 lookups) we'll skip every other one
+ // to only perform 12.
+ // 1 0 1 0 1
+ // 0 1 0 1 0
+ // 1 0 x 0 1
+ // 0 1 0 1 0
+ // 1 0 1 0 1
+ //
+ // You can get away with 8 just around the outside but
+ // it looks more jittery to me.
+
+ vec4 sum = vec4(0.0);
+
+ float x = texCoord.x;
+ float y = texCoord.y;
+
+ float xScale = m_XScale;
+ float yScale = m_YScale;
+
+ // In order from lower left to right, depending on how you look at it
+ sum += texture2D( m_Texture, vec2(x - 2.0 * xScale, y - 2.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x - 0.0 * xScale, y - 2.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x + 2.0 * xScale, y - 2.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x - 1.0 * xScale, y - 1.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x + 1.0 * xScale, y - 1.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x - 2.0 * xScale, y - 0.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x + 2.0 * xScale, y - 0.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x - 1.0 * xScale, y + 1.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x + 1.0 * xScale, y + 1.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x - 2.0 * xScale, y + 2.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x - 0.0 * xScale, y + 2.0 * yScale) );
+ sum += texture2D( m_Texture, vec2(x + 2.0 * xScale, y + 2.0 * yScale) );
+
+ sum = sum / 12.0;
+
+ gl_FragColor = mix( texVal, sum, unfocus );
+
+ // I used this for debugging the range
+ // gl_FragColor.r = unfocus;
+}
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/DepthOfField.j3md b/engine/src/core-effects/Common/MatDefs/Post/DepthOfField.j3md
new file mode 100644
index 0000000..db30a09
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/DepthOfField.j3md
@@ -0,0 +1,25 @@
+MaterialDef Depth Of Field {
+
+ MaterialParameters {
+ Int NumSamples
+ Int NumSamplesDepth
+ Texture2D Texture
+ Texture2D DepthTexture
+ Float FocusRange;
+ Float FocusDistance;
+ Float XScale;
+ Float YScale;
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/DepthOfField.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/FXAA.frag b/engine/src/core-effects/Common/MatDefs/Post/FXAA.frag
new file mode 100644
index 0000000..d630b35
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/FXAA.frag
@@ -0,0 +1,88 @@
+#extension GL_EXT_gpu_shader4 : enable
+
+uniform sampler2D m_Texture;
+uniform vec2 g_Resolution;
+
+uniform float m_VxOffset;
+uniform float m_SpanMax;
+uniform float m_ReduceMul;
+
+varying vec2 texCoord;
+varying vec4 posPos;
+
+#define FxaaTex(t, p) texture2D(t, p)
+
+#if __VERSION__ >= 130
+ #define OffsetVec(a, b) ivec2(a, b)
+ #define FxaaTexOff(t, p, o, r) textureOffset(t, p, o)
+#elif defined(GL_EXT_gpu_shader4)
+ #define OffsetVec(a, b) ivec2(a, b)
+ #define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o)
+#else
+ #define OffsetVec(a, b) vec2(a, b)
+ #define FxaaTexOff(t, p, o, r) texture2D(t, p + o * r)
+#endif
+
+vec3 FxaaPixelShader(
+ vec4 posPos, // Output of FxaaVertexShader interpolated across screen.
+ sampler2D tex, // Input texture.
+ vec2 rcpFrame) // Constant {1.0/frameWidth, 1.0/frameHeight}.
+{
+
+ #define FXAA_REDUCE_MIN (1.0/128.0)
+ //#define FXAA_REDUCE_MUL (1.0/8.0)
+ //#define FXAA_SPAN_MAX 8.0
+
+ vec3 rgbNW = FxaaTex(tex, posPos.zw).xyz;
+ vec3 rgbNE = FxaaTexOff(tex, posPos.zw, OffsetVec(1,0), rcpFrame.xy).xyz;
+ vec3 rgbSW = FxaaTexOff(tex, posPos.zw, OffsetVec(0,1), rcpFrame.xy).xyz;
+ vec3 rgbSE = FxaaTexOff(tex, posPos.zw, OffsetVec(1,1), rcpFrame.xy).xyz;
+
+ vec3 rgbM = FxaaTex(tex, posPos.xy).xyz;
+
+ vec3 luma = vec3(0.299, 0.587, 0.114);
+ float lumaNW = dot(rgbNW, luma);
+ float lumaNE = dot(rgbNE, luma);
+ float lumaSW = dot(rgbSW, luma);
+ float lumaSE = dot(rgbSE, luma);
+ float lumaM = dot(rgbM, luma);
+
+ float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
+ float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
+
+ vec2 dir;
+ dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
+ dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
+
+ float dirReduce = max(
+ (lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * m_ReduceMul),
+ FXAA_REDUCE_MIN);
+ float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);
+ dir = min(vec2( m_SpanMax, m_SpanMax),
+ max(vec2(-m_SpanMax, -m_SpanMax),
+ dir * rcpDirMin)) * rcpFrame.xy;
+
+ vec3 rgbA = (1.0/2.0) * (
+ FxaaTex(tex, posPos.xy + dir * vec2(1.0/3.0 - 0.5)).xyz +
+ FxaaTex(tex, posPos.xy + dir * vec2(2.0/3.0 - 0.5)).xyz);
+ vec3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (
+ FxaaTex(tex, posPos.xy + dir * vec2(0.0/3.0 - 0.5)).xyz +
+ FxaaTex(tex, posPos.xy + dir * vec2(3.0/3.0 - 0.5)).xyz);
+
+ float lumaB = dot(rgbB, luma);
+
+ if ((lumaB < lumaMin) || (lumaB > lumaMax))
+ {
+ return rgbA;
+ }
+ else
+ {
+ return rgbB;
+ }
+}
+
+void main()
+{
+ vec2 rcpFrame = vec2(1.0) / g_Resolution;
+ gl_FragColor = vec4(FxaaPixelShader(posPos, m_Texture, rcpFrame), 1.0);
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/FXAA.j3md b/engine/src/core-effects/Common/MatDefs/Post/FXAA.j3md
new file mode 100644
index 0000000..6685585
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/FXAA.j3md
@@ -0,0 +1,20 @@
+MaterialDef FXAA {
+ MaterialParameters {
+ Int NumSamples
+ Texture2D Texture
+ Float SubPixelShift
+ Float VxOffset
+ Float SpanMax
+ Float ReduceMul
+ }
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/FXAA.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/FXAA.frag
+ WorldParameters {
+ WorldViewProjectionMatrix
+ Resolution
+ }
+ }
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/FXAA.vert b/engine/src/core-effects/Common/MatDefs/Post/FXAA.vert
new file mode 100644
index 0000000..2390384
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/FXAA.vert
@@ -0,0 +1,18 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform vec2 g_Resolution;
+
+uniform float m_SubPixelShift;
+
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+
+varying vec2 texCoord;
+varying vec4 posPos;
+
+void main() {
+ gl_Position = inPosition * 2.0 - 1.0; //vec4(pos, 0.0, 1.0);
+ texCoord = inTexCoord;
+ vec2 rcpFrame = vec2(1.0) / g_Resolution;
+ posPos.xy = inTexCoord.xy;
+ posPos.zw = inTexCoord.xy - (rcpFrame * vec2(0.5 + m_SubPixelShift));
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Fade.frag b/engine/src/core-effects/Common/MatDefs/Post/Fade.frag
new file mode 100644
index 0000000..b616239
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Fade.frag
@@ -0,0 +1,11 @@
+uniform sampler2D m_Texture;
+varying vec2 texCoord;
+
+uniform float m_Value;
+
+void main() {
+ vec4 texVal = texture2D(m_Texture, texCoord);
+
+ gl_FragColor = texVal * m_Value;
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Fade.j3md b/engine/src/core-effects/Common/MatDefs/Post/Fade.j3md
new file mode 100644
index 0000000..e93b276
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Fade.j3md
@@ -0,0 +1,34 @@
+MaterialDef Fade {
+
+ MaterialParameters {
+ Int NumSamples
+ Texture2D Texture
+ Float Value
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/Fade15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ RESOLVE_MS : NumSamples
+ }
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/Fade.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique FixedFunc {
+ }
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Fade15.frag b/engine/src/core-effects/Common/MatDefs/Post/Fade15.frag
new file mode 100644
index 0000000..c99de34
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Fade15.frag
@@ -0,0 +1,11 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform float m_Value;
+
+in vec2 texCoord;
+
+void main() {
+ vec4 texVal = getColor(m_Texture, texCoord);
+ gl_FragColor = texVal * m_Value;
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Fog.frag b/engine/src/core-effects/Common/MatDefs/Post/Fog.frag
new file mode 100644
index 0000000..7321b15
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Fog.frag
@@ -0,0 +1,21 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+varying vec2 texCoord;
+
+uniform vec4 m_FogColor;
+uniform float m_FogDensity;
+uniform float m_FogDistance;
+
+vec2 m_FrustumNearFar=vec2(1.0,m_FogDistance);
+const float LOG2 = 1.442695;
+
+void main() {
+ vec4 texVal = texture2D(m_Texture, texCoord);
+ float fogVal =texture2D(m_DepthTexture,texCoord).r;
+ float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - fogVal* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+
+ float fogFactor = exp2( -m_FogDensity * m_FogDensity * depth * depth * LOG2 );
+ fogFactor = clamp(fogFactor, 0.0, 1.0);
+ gl_FragColor =mix(m_FogColor,texVal,fogFactor);
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Fog.j3md b/engine/src/core-effects/Common/MatDefs/Post/Fog.j3md
new file mode 100644
index 0000000..e5d6c8d
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Fog.j3md
@@ -0,0 +1,39 @@
+MaterialDef Fade {
+
+ MaterialParameters {
+ Int NumSamples
+ Int NumSamplesDepth
+ Texture2D Texture
+ Texture2D DepthTexture
+ Vector4 FogColor;
+ Float FogDensity;
+ Float FogDistance;
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/Fog15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ RESOLVE_MS : NumSamples
+ RESOLVE_DEPTH_MS : NumSamplesDepth
+ }
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/Fog.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique FixedFunc {
+ }
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Fog15.frag b/engine/src/core-effects/Common/MatDefs/Post/Fog15.frag
new file mode 100644
index 0000000..65a3407
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Fog15.frag
@@ -0,0 +1,24 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+uniform vec4 m_FogColor;
+uniform float m_FogDensity;
+uniform float m_FogDistance;
+
+in vec2 texCoord;
+
+vec2 m_FrustumNearFar=vec2(1.0,m_FogDistance);
+const float LOG2 = 1.442695;
+
+void main() {
+ vec4 texVal = getColor(m_Texture, texCoord);
+ float fogVal = getDepth(m_DepthTexture,texCoord).r;
+ float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - fogVal* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+
+ float fogFactor = exp2( -m_FogDensity * m_FogDensity * depth * depth * LOG2 );
+ fogFactor = clamp(fogFactor, 0.0, 1.0);
+ gl_FragColor =mix(m_FogColor,texVal,fogFactor);
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.frag b/engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.frag
new file mode 100644
index 0000000..90b2ade
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.frag
@@ -0,0 +1,23 @@
+uniform sampler2D m_Texture;
+varying vec2 texCoord;
+
+uniform float m_gamma;
+
+vec3 gamma(vec3 L,float gamma)
+{
+ return pow(L, vec3(1.0 / gamma));
+}
+
+void main() {
+ vec4 texVal = texture2D(m_Texture, texCoord);
+
+ if(m_gamma > 0.0)
+ {
+ texVal.rgb = gamma(texVal.rgb , m_gamma);
+ }
+ #ifdef COMPUTE_LUMA
+ texVal.a = dot(texVal.rgb, vec3(0.299, 0.587, 0.114));
+ #endif
+
+ gl_FragColor = texVal;
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.j3md b/engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.j3md
new file mode 100644
index 0000000..b9c94c0
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.j3md
@@ -0,0 +1,39 @@
+MaterialDef GammaCorrection {
+
+ MaterialParameters {
+ Int NumSamples
+ Texture2D Texture
+ Float gamma
+ Boolean computeLuma
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/GammaCorrection15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ COMPUTE_LUMA : computeLuma
+ }
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/GammaCorrection.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ COMPUTE_LUMA : computeLuma
+ }
+ }
+
+ Technique FixedFunc {
+ }
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/GammaCorrection15.frag b/engine/src/core-effects/Common/MatDefs/Post/GammaCorrection15.frag
new file mode 100644
index 0000000..b786190
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/GammaCorrection15.frag
@@ -0,0 +1,26 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+in vec2 texCoord;
+
+uniform float m_gamma;
+
+vec3 gamma(vec3 L,float gamma)
+{
+ return pow(L, vec3(1.0 / gamma));
+}
+
+void main() {
+ vec4 texVal = texture2D(m_Texture, texCoord);
+
+ if(m_gamma > 0.0)
+ {
+ texVal.rgb = gamma(texVal.rgb , m_gamma);
+ }
+
+ #ifdef COMPUTE_LUMA
+ texVal.a = dot(texVal.rgb, vec3(0.299, 0.587, 0.114));
+ #endif
+
+ gl_FragColor = texVal;
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/LightScattering.frag b/engine/src/core-effects/Common/MatDefs/Post/LightScattering.frag
new file mode 100644
index 0000000..683bbea
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/LightScattering.frag
@@ -0,0 +1,36 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+uniform int m_NbSamples;
+uniform float m_BlurStart;
+uniform float m_BlurWidth;
+uniform float m_LightDensity;
+uniform bool m_Display;
+
+varying vec2 lightPos;
+varying vec2 texCoord;
+
+void main(void)
+{
+ if(m_Display){
+
+ vec4 colorRes= texture2D(m_Texture,texCoord);
+ float factor=(m_BlurWidth/float(m_NbSamples-1.0));
+ float scale;
+ vec2 texCoo=texCoord-lightPos;
+ vec2 scaledCoord;
+ vec4 res = vec4(0.0);
+ for(int i=0; i<m_NbSamples; i++) {
+ scale = i * factor + m_BlurStart ;
+ scaledCoord=texCoo*scale+lightPos;
+ if(texture2D(m_DepthTexture,scaledCoord).r==1.0){
+ res += texture2D(m_Texture,scaledCoord);
+ }
+ }
+ res /= m_NbSamples;
+
+ //Blend the original color with the averaged pixels
+ gl_FragColor =mix( colorRes, res, m_LightDensity);
+ }else{
+ gl_FragColor= texture2D(m_Texture,texCoord);
+ }
+}
diff --git a/engine/src/core-effects/Common/MatDefs/Post/LightScattering.j3md b/engine/src/core-effects/Common/MatDefs/Post/LightScattering.j3md
new file mode 100644
index 0000000..37e0e85
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/LightScattering.j3md
@@ -0,0 +1,41 @@
+MaterialDef Light Scattering {
+ MaterialParameters {
+ Int NumSamples
+ Int NumSamplesDepth
+ Texture2D Texture
+ Texture2D DepthTexture
+ Vector3 LightPosition
+ Int NbSamples
+ Float BlurStart
+ Float BlurWidth
+ Float LightDensity
+ Boolean Display
+ Boolean multiSampledDepth
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/LightScattering15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/LightScattering15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ RESOLVE_MS : NumSamples
+ RESOLVE_DEPTH_MS : NumSamplesDepth
+ }
+ }
+
+ Technique {
+ VertexShader GLSL120: Common/MatDefs/Post/LightScattering.vert
+ FragmentShader GLSL120: Common/MatDefs/Post/LightScattering.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/LightScattering.vert b/engine/src/core-effects/Common/MatDefs/Post/LightScattering.vert
new file mode 100644
index 0000000..f58f66e
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/LightScattering.vert
@@ -0,0 +1,14 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform vec3 m_LightPosition;
+
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+varying vec2 texCoord;
+varying vec2 lightPos;
+
+void main() {
+ vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
+ gl_Position = vec4(pos, 0.0, 1.0);
+ lightPos=m_LightPosition.xy;
+ texCoord = inTexCoord;
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/LightScattering15.frag b/engine/src/core-effects/Common/MatDefs/Post/LightScattering15.frag
new file mode 100644
index 0000000..2a5ae26
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/LightScattering15.frag
@@ -0,0 +1,39 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+uniform int m_NbSamples;
+uniform float m_BlurStart;
+uniform float m_BlurWidth;
+uniform float m_LightDensity;
+uniform bool m_Display;
+
+in vec2 lightPos;
+in vec2 texCoord;
+
+void main(void)
+{
+ if(m_Display){
+
+ vec4 colorRes= getColor(m_Texture,texCoord);
+ float factor=(m_BlurWidth/float(m_NbSamples-1.0));
+ float scale;
+ vec2 texCoo=texCoord-lightPos;
+ vec2 scaledCoord;
+ vec4 res = vec4(0.0);
+ for(int i=0; i<m_NbSamples; i++) {
+ scale = i * factor + m_BlurStart ;
+ scaledCoord=texCoo*scale+lightPos;
+ if(fetchTextureSample(m_DepthTexture, scaledCoord,0).r==1.0){
+ res += fetchTextureSample(m_Texture,scaledCoord,0);
+ }
+ }
+ res /= m_NbSamples;
+
+ //Blend the original color with the averaged pixels
+ gl_FragColor =mix( colorRes, res, m_LightDensity);
+ }else{
+ gl_FragColor= getColor(m_Texture,texCoord);
+ }
+}
diff --git a/engine/src/core-effects/Common/MatDefs/Post/LightScattering15.vert b/engine/src/core-effects/Common/MatDefs/Post/LightScattering15.vert
new file mode 100644
index 0000000..990951b
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/LightScattering15.vert
@@ -0,0 +1,14 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform vec3 m_LightPosition;
+
+in vec4 inPosition;
+in vec2 inTexCoord;
+out vec2 texCoord;
+out vec2 lightPos;
+
+void main() {
+ vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
+ gl_Position = vec4(pos, 0.0, 1.0);
+ lightPos=m_LightPosition.xy;
+ texCoord = inTexCoord;
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Overlay.frag b/engine/src/core-effects/Common/MatDefs/Post/Overlay.frag
new file mode 100644
index 0000000..15d4bcb
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Overlay.frag
@@ -0,0 +1,9 @@
+uniform sampler2D m_Texture;
+uniform vec4 m_Color;
+varying vec2 texCoord;
+
+void main() {
+ vec4 texVal = texture2D(m_Texture, texCoord);
+ gl_FragColor = texVal * m_Color;
+}
+
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Overlay.j3md b/engine/src/core-effects/Common/MatDefs/Post/Overlay.j3md
new file mode 100644
index 0000000..fbf2d24
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Overlay.j3md
@@ -0,0 +1,36 @@
+MaterialDef Default GUI {
+
+ MaterialParameters {
+ Int NumSamples
+ Texture2D Texture
+ Color Color
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/Overlay15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ RESOLVE_MS : NumSamples
+ }
+
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/Overlay.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ }
+
+ Technique FixedFunc {
+ }
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Overlay15.frag b/engine/src/core-effects/Common/MatDefs/Post/Overlay15.frag
new file mode 100644
index 0000000..7dc4d1e
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Overlay15.frag
@@ -0,0 +1,11 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform vec4 m_Color;
+in vec2 texCoord;
+
+void main() {
+ vec4 texVal = getColor(m_Texture, texCoord);
+ gl_FragColor = texVal * m_Color;
+}
+
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Post.vert b/engine/src/core-effects/Common/MatDefs/Post/Post.vert
new file mode 100644
index 0000000..6d80905
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Post.vert
@@ -0,0 +1,10 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+varying vec2 texCoord;
+
+void main() {
+ gl_Position = inPosition * 2.0 - 1.0; //vec4(pos, 0.0, 1.0);
+ texCoord = inTexCoord;
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Post15.vert b/engine/src/core-effects/Common/MatDefs/Post/Post15.vert
new file mode 100644
index 0000000..367c330
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Post15.vert
@@ -0,0 +1,12 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+
+in vec4 inPosition;
+in vec2 inTexCoord;
+
+out vec2 texCoord;
+
+void main() {
+ vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
+ gl_Position = vec4(pos, 0.0, 1.0);
+ texCoord = inTexCoord;
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Posterization.frag b/engine/src/core-effects/Common/MatDefs/Post/Posterization.frag
new file mode 100644
index 0000000..d184bc6
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Posterization.frag
@@ -0,0 +1,18 @@
+uniform sampler2D m_Texture;
+varying vec2 texCoord;
+
+uniform int m_NumColors;
+uniform float m_Gamma;
+uniform float m_Strength;
+
+void main() {
+ vec4 texVal = texture2D(m_Texture, texCoord);
+
+ texVal = pow(texVal, vec4(m_Gamma));
+ texVal = texVal * vec4(m_NumColors);
+ texVal = floor(texVal);
+ texVal = texVal / vec4(m_NumColors);
+ texVal = pow(texVal, vec4(1.0/m_Gamma));
+
+ gl_FragColor = mix(texture2D(m_Texture, texCoord), texVal, m_Strength);
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Posterization.j3md b/engine/src/core-effects/Common/MatDefs/Post/Posterization.j3md
new file mode 100644
index 0000000..244dcbc
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Posterization.j3md
@@ -0,0 +1,32 @@
+MaterialDef Posterization {
+
+ MaterialParameters {
+ Int NumSamples
+ Texture2D Texture;
+ Int NumColors;
+ Float Gamma;
+ Float Strength;
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/Post/Posterization15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL100: Common/MatDefs/Post/Posterization.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique FixedFunc {
+ }
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/Posterization15.frag b/engine/src/core-effects/Common/MatDefs/Post/Posterization15.frag
new file mode 100644
index 0000000..f55ac5b
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/Posterization15.frag
@@ -0,0 +1,20 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+in vec2 texCoord;
+
+uniform int m_NumColors;
+uniform float m_Gamma;
+uniform float m_Strength;
+
+void main() {
+ vec4 texVal = getColor(m_Texture, texCoord);
+
+ texVal = pow(texVal, vec4(m_Gamma));
+ texVal = texVal * m_NumColors;
+ texVal = floor(texVal);
+ texVal = texVal / m_NumColors;
+ texVal = pow(texVal, vec4(1.0/m_Gamma));
+
+ gl_FragColor = mix(getColor(m_Texture, texCoord), texVal, m_Strength);
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Post/bloomExtract.frag b/engine/src/core-effects/Common/MatDefs/Post/bloomExtract.frag
new file mode 100644
index 0000000..23aa45e
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/bloomExtract.frag
@@ -0,0 +1,29 @@
+uniform float m_ExposurePow;
+uniform float m_ExposureCutoff;
+uniform sampler2D m_Texture;
+
+varying vec2 texCoord;
+
+#ifdef HAS_GLOWMAP
+ uniform sampler2D m_GlowMap;
+#endif
+
+void main(){
+ vec4 color = vec4(0.0);
+ #ifdef DO_EXTRACT
+ color = texture2D( m_Texture, texCoord );
+ if ( (color.r+color.g+color.b)/3.0 < m_ExposureCutoff ) {
+ color = vec4(0.0);
+ }else{
+ color = pow(color,vec4(m_ExposurePow));
+ }
+ #endif
+
+ #ifdef HAS_GLOWMAP
+ vec4 glowColor = texture2D(m_GlowMap, texCoord);
+ glowColor = pow(glowColor, vec4(m_ExposurePow));
+ color += glowColor;
+ #endif
+
+ gl_FragColor = color;
+}
diff --git a/engine/src/core-effects/Common/MatDefs/Post/bloomExtract15.frag b/engine/src/core-effects/Common/MatDefs/Post/bloomExtract15.frag
new file mode 100644
index 0000000..7194f9c
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/bloomExtract15.frag
@@ -0,0 +1,33 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+
+uniform float m_ExposurePow;
+uniform float m_ExposureCutoff;
+
+in vec2 texCoord;
+out vec4 outFragColor;
+
+#ifdef HAS_GLOWMAP
+ uniform sampler2D m_GlowMap;
+#endif
+
+void main(){
+ vec4 color = vec4(0.0);
+ #ifdef DO_EXTRACT
+ color = getColorSingle(m_Texture, texCoord);
+ if ( (color.r + color.g + color.b) / 3.0 >= m_ExposureCutoff ) {
+ color = pow(color, vec4(m_ExposurePow));
+ }else{
+ color = vec4(0.0);
+ }
+ #endif
+
+ #ifdef HAS_GLOWMAP
+ vec4 glowColor = texture2D( m_GlowMap, texCoord );
+ glowColor = pow(glowColor, vec4(m_ExposurePow));
+ color += glowColor;
+ #endif
+
+ outFragColor = color;
+}
diff --git a/engine/src/core-effects/Common/MatDefs/Post/bloomFinal.frag b/engine/src/core-effects/Common/MatDefs/Post/bloomFinal.frag
new file mode 100644
index 0000000..9499e58
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/bloomFinal.frag
@@ -0,0 +1,12 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_BloomTex;
+uniform float m_BloomIntensity;
+
+varying vec2 texCoord;
+
+void main(){
+ vec4 colorRes = texture2D(m_Texture, texCoord);
+ vec4 bloom = texture2D(m_BloomTex, texCoord);
+ gl_FragColor = bloom * m_BloomIntensity + colorRes;
+}
+
diff --git a/engine/src/core-effects/Common/MatDefs/Post/bloomFinal15.frag b/engine/src/core-effects/Common/MatDefs/Post/bloomFinal15.frag
new file mode 100644
index 0000000..34268c5
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Post/bloomFinal15.frag
@@ -0,0 +1,15 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+
+uniform sampler2D m_BloomTex;
+uniform float m_BloomIntensity;
+
+in vec2 texCoord;
+
+void main(){
+ vec4 colorRes = getColor(m_Texture,texCoord);
+ vec4 bloom = texture2D(m_BloomTex, texCoord);
+ gl_FragColor = bloom * m_BloomIntensity + colorRes;
+}
+
diff --git a/engine/src/core-effects/Common/MatDefs/SSAO/Textures/random.png b/engine/src/core-effects/Common/MatDefs/SSAO/Textures/random.png
new file mode 100644
index 0000000..e19b7f5
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/SSAO/Textures/random.png
Binary files differ
diff --git a/engine/src/core-effects/Common/MatDefs/SSAO/normal.frag b/engine/src/core-effects/Common/MatDefs/SSAO/normal.frag
new file mode 100644
index 0000000..289c4c0
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/SSAO/normal.frag
@@ -0,0 +1,21 @@
+varying vec3 normal;
+varying vec2 texCoord;
+
+
+#ifdef DIFFUSEMAP_ALPHA
+ uniform sampler2D m_DiffuseMap;
+ uniform float m_AlphaDiscardThreshold;
+#endif
+
+void main(void)
+{
+
+ #ifdef DIFFUSEMAP_ALPHA
+ if(texture2D(m_DiffuseMap,texCoord).a<m_AlphaDiscardThreshold){
+ discard;
+ }
+ #endif
+ gl_FragColor = vec4(normal.xy* 0.5 + 0.5,-normal.z* 0.5 + 0.5, 1.0);
+
+}
+
diff --git a/engine/src/core-effects/Common/MatDefs/SSAO/normal.vert b/engine/src/core-effects/Common/MatDefs/SSAO/normal.vert
new file mode 100644
index 0000000..24a76cb
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/SSAO/normal.vert
@@ -0,0 +1,16 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform mat3 g_NormalMatrix;
+
+attribute vec3 inPosition;
+attribute vec3 inNormal;
+attribute vec4 inTexCoord;
+
+varying vec3 normal;
+varying vec2 texCoord;
+
+void main(void)
+{
+ texCoord=inTexCoord.xy;
+ normal = normalize(g_NormalMatrix * inNormal);
+ gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition,1.0);
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/SSAO/ssao.frag b/engine/src/core-effects/Common/MatDefs/SSAO/ssao.frag
new file mode 100644
index 0000000..3cd860d
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/SSAO/ssao.frag
@@ -0,0 +1,104 @@
+uniform vec2 g_Resolution;
+uniform vec2 m_FrustumNearFar;
+uniform sampler2D m_Texture;
+uniform sampler2D m_Normals;
+uniform sampler2D m_DepthTexture;
+uniform vec3 m_FrustumCorner;
+uniform float m_SampleRadius;
+uniform float m_Intensity;
+uniform float m_Scale;
+uniform float m_Bias;
+uniform bool m_UseOnlyAo;
+uniform bool m_UseAo;
+uniform vec2[4] m_Samples;
+
+varying vec2 texCoord;
+
+float depthv;
+
+vec3 getPosition(in vec2 uv){
+ //Reconstruction from depth
+ depthv =texture2D(m_DepthTexture,uv).r;
+ float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - depthv* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+
+ //one frustum corner method
+ float x = mix(-m_FrustumCorner.x, m_FrustumCorner.x, uv.x);
+ float y = mix(-m_FrustumCorner.y, m_FrustumCorner.y, uv.y);
+
+ return depth* vec3(x, y, m_FrustumCorner.z);
+}
+
+vec3 getNormal(in vec2 uv){
+ return normalize(texture2D(m_Normals, uv).xyz * 2.0 - 1.0);
+}
+
+vec2 getRandom(in vec2 uv){
+ float rand=(fract(uv.x*(g_Resolution.x/2.0))*0.25)+(fract(uv.y*(g_Resolution.y/2.0))*0.5);
+ return normalize(vec2(rand,rand));
+}
+
+float doAmbientOcclusion(in vec2 tc, in vec3 pos, in vec3 norm){
+ vec3 diff = getPosition(tc)- pos;
+ vec3 v = normalize(diff);
+ float d = length(diff) * m_Scale;
+
+ return max(0.0, dot(norm, v) - m_Bias) * ( 1.0/(1.0 + d) ) * m_Intensity;
+}
+
+vec4 getColor(in float result){
+
+ if(m_UseOnlyAo){
+ return vec4(result,result,result, 1.0);
+ }
+ if(m_UseAo){
+ return texture2D(m_Texture,texCoord)* vec4(result,result,result, 1.0);
+ }else{
+ return texture2D(m_Texture,texCoord);
+ }
+
+}
+
+vec2 reflection(in vec2 v1,in vec2 v2){
+ vec2 result= 2.0 * dot(v2, v1) * v2;
+ result=v1-result;
+ return result;
+}
+
+
+//const vec2 vec[4] = vec2[4](vec2(1.0,0.0), vec2(-1.0,0.0), vec2(0.0,1.0), vec2(0.0,-1.0));
+void main(){
+
+ float result;
+
+ //vec2 vec[4] = { vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0) };
+ vec3 position = getPosition(texCoord);
+ //optimization, do not calculate AO if depth is 1
+ if(depthv==1.0){
+ gl_FragColor=getColor(1.0);
+ return;
+ }
+ vec3 normal = getNormal(texCoord);
+ vec2 rand = getRandom(texCoord);
+
+ float ao = 0.0;
+ float rad =m_SampleRadius / position.z;
+
+
+ int iterations = 4;
+ for (int j = 0; j < iterations; ++j){
+ vec2 coord1 = reflection(vec2(m_Samples[j]), vec2(rand)) * vec2(rad,rad);
+ vec2 coord2 = vec2(coord1.x* 0.707 - coord1.y* 0.707, coord1.x* 0.707 + coord1.y* 0.707) ;
+
+ ao += doAmbientOcclusion(texCoord + coord1.xy * 0.25, position, normal);
+ ao += doAmbientOcclusion(texCoord + coord2 * 0.50, position, normal);
+ ao += doAmbientOcclusion(texCoord + coord1.xy * 0.75, position, normal);
+ ao += doAmbientOcclusion(texCoord + coord2 * 1.00, position, normal);
+
+ }
+ ao /= float(iterations) * 4.0;
+ result = 1.0-ao;
+
+ gl_FragColor=getColor(result);
+
+//gl_FragColor=vec4(normal,1.0);
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/SSAO/ssao.j3md b/engine/src/core-effects/Common/MatDefs/SSAO/ssao.j3md
new file mode 100644
index 0000000..762c1e5
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/SSAO/ssao.j3md
@@ -0,0 +1,51 @@
+MaterialDef SSAO {
+
+ MaterialParameters {
+ Int NumSamples
+ Int NumSamplesDepth
+ Texture2D Texture
+ Texture2D RandomMap
+ Texture2D Normals
+ Texture2D DepthTexture
+ Vector3 FrustumCorner
+ Float SampleRadius
+ Float Intensity
+ Float Scale
+ Float Bias
+ Vector2 FrustumNearFar
+ Vector2Array Samples
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/SSAO/ssao15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldViewMatrix
+ Resolution
+ }
+
+ Defines {
+ RESOLVE_MS : NumSamples
+ RESOLVE_DEPTH_MS : NumSamplesDepth
+ }
+ }
+
+ Technique {
+ VertexShader GLSL120: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL120: Common/MatDefs/SSAO/ssao.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldViewMatrix
+ Resolution
+
+ }
+ }
+
+
+
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/SSAO/ssao15.frag b/engine/src/core-effects/Common/MatDefs/SSAO/ssao15.frag
new file mode 100644
index 0000000..de3b846
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/SSAO/ssao15.frag
@@ -0,0 +1,96 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+uniform vec2 g_Resolution;
+uniform vec2 m_FrustumNearFar;
+uniform sampler2D m_Normals;
+uniform sampler2D m_RandomMap;
+uniform vec3 m_FrustumCorner;
+uniform float m_SampleRadius;
+uniform float m_Intensity;
+uniform float m_Scale;
+uniform float m_Bias;
+uniform vec2[4] m_Samples;
+
+in vec2 texCoord;
+
+float depthv;
+
+vec3 getPosition(in vec2 uv){
+ //Reconstruction from depth
+ depthv =getDepth(m_DepthTexture,uv).r;
+ float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - depthv* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+
+ //one frustum corner method
+ float x = mix(-m_FrustumCorner.x, m_FrustumCorner.x, uv.x);
+ float y = mix(-m_FrustumCorner.y, m_FrustumCorner.y, uv.y);
+
+ return depth* vec3(x, y, m_FrustumCorner.z);
+}
+
+vec3 getNormal(in vec2 uv){
+ return normalize(texture2D(m_Normals, uv).xyz * 2.0 - 1.0);
+}
+
+vec2 getRandom(in vec2 uv){
+ //float rand=(fract(uv.x*(g_Resolution.x/2.0))*0.25)+(fract(uv.y*(g_Resolution.y/2.0))*0.5);
+ vec4 rand=texture2D(m_RandomMap,g_Resolution * uv / 128.0 * 3.0)*2.0 -1.0;
+
+ return normalize(rand.xy);
+}
+
+float doAmbientOcclusion(in vec2 tc, in vec3 pos, in vec3 norm){
+ vec3 diff = getPosition(tc)- pos;
+ vec3 v = normalize(diff);
+ float d = length(diff) * m_Scale;
+
+ return max(0.0, dot(norm, v) - m_Bias) * ( 1.0/(1.0 + d) ) * m_Intensity;
+}
+
+
+vec2 reflection(in vec2 v1,in vec2 v2){
+ vec2 result= 2.0 * dot(v2, v1) * v2;
+ result=v1-result;
+ return result;
+}
+
+
+//const vec2 vec[4] = vec2[4](vec2(1.0,0.0), vec2(-1.0,0.0), vec2(0.0,1.0), vec2(0.0,-1.0));
+void main(){
+
+ float result;
+
+ //vec2 vec[4] = { vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0) };
+ vec3 position = getPosition(texCoord);
+ //optimization, do not calculate AO if depth is 1
+ if(depthv==1.0){
+ gl_FragColor=vec4(1.0);
+ return;
+ }
+ vec3 normal = getNormal(texCoord);
+ vec2 rand = getRandom(texCoord);
+
+ float ao = 0.0;
+ float rad =m_SampleRadius / position.z;
+
+
+ int iterations = 4;
+ for (int j = 0; j < iterations; ++j){
+ vec2 coord1 = reflection(vec2(m_Samples[j]), rand) * vec2(rad,rad);
+ vec2 coord2 = vec2(coord1.x* 0.707 - coord1.y* 0.707, coord1.x* 0.707 + coord1.y* 0.707) ;
+
+ ao += doAmbientOcclusion(texCoord + coord1.xy * 0.25, position, normal);
+ ao += doAmbientOcclusion(texCoord + coord2 * 0.50, position, normal);
+ ao += doAmbientOcclusion(texCoord + coord1.xy * 0.75, position, normal);
+ ao += doAmbientOcclusion(texCoord + coord2 * 1.00, position, normal);
+
+ }
+ ao /= float(iterations) * 4.0;
+ result = 1.0-ao;
+
+ gl_FragColor=vec4(result,result,result, 1.0);
+//gl_FragColor=vec4(depthv,depthv,depthv, 1.0);
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.frag b/engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.frag
new file mode 100644
index 0000000..48f4a2f
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.frag
@@ -0,0 +1,159 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+uniform sampler2D m_SSAOMap;
+uniform vec2 g_Resolution;
+uniform bool m_UseOnlyAo;
+uniform bool m_UseAo;
+uniform float m_XScale;
+uniform float m_YScale;
+uniform vec2 m_FrustumNearFar;
+
+varying vec2 texCoord;
+
+vec4 getColor(vec4 color){
+
+
+ #ifdef USE_ONLY_AO
+ return color;
+ #endif
+ #ifdef USE_AO
+ return texture2D(m_Texture,texCoord)* color;
+ #endif
+
+ return texture2D(m_Texture,texCoord);
+
+}
+
+float readDepth(in vec2 uv){
+ float depthv =texture2D(m_DepthTexture,uv).r;
+ return (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - depthv* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+}
+
+ const float epsilon = 0.005;
+
+
+/*
+ const int kernelSize=7;
+
+ vec4 bilateralFilter() {
+ vec4 color = vec4(0.0);
+
+ vec2 sample;
+ float sum = 0.0;
+ float coefZ;
+ float Zp = readDepth(texCoord);
+
+ for(int i = -(kernelSize-1); i <= (kernelSize-1); i+=2) {
+ for(int j = -(kernelSize-1); j <= (kernelSize-1); j+=2) {
+ sample = texCoord + vec2(i,j) / g_Resolution;
+ float zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ sum += coefZ;
+
+ color += coefZ * texture2D(m_SSAOMap,sample);
+
+ }
+ }
+
+ return color / sum;
+ }
+*/
+
+ vec4 convolutionFilter(){
+ vec4 sum = vec4(0.0);
+
+ float x = texCoord.x;
+ float y = texCoord.y;
+
+ float xScale = m_XScale;
+ float yScale = m_YScale;
+
+ float zsum = 1.0;
+ float Zp =readDepth(texCoord);
+
+
+ vec2 sample = vec2(x - 2.0 * xScale, y - 2.0 * yScale);
+ float zTmp =readDepth(sample);
+ float coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 0.0 * xScale, y - 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 2.0 * xScale, y - 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 1.0 * xScale, y - 1.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 1.0 * xScale, y - 1.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 2.0 * xScale, y - 0.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 2.0 * xScale, y - 0.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 1.0 * xScale, y + 1.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 1.0 * xScale, y + 1.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 2.0 * xScale, y + 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 0.0 * xScale, y + 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 2.0 * xScale, y + 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+
+ return sum / zsum;
+ }
+
+
+ void main(){
+ // float depth =texture2D(m_DepthTexture,uv).r;
+
+ gl_FragColor=getColor(convolutionFilter());
+ // gl_FragColor=getColor(bilateralFilter());
+ // gl_FragColor=texture2D(m_SSAOMap,texCoord);
+
+ } \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.j3md b/engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.j3md
new file mode 100644
index 0000000..dcc5e49
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.j3md
@@ -0,0 +1,57 @@
+MaterialDef SSAOBlur {
+
+ MaterialParameters {
+ Int NumSamples
+ Int NumSamplesDepth
+ Texture2D Texture
+ Texture2D SSAOMap
+ Texture2D DepthTexture
+ Vector2 FrustumNearFar
+ Boolean UseAo
+ Boolean UseOnlyAo
+ Float XScale
+ Float YScale
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150: Common/MatDefs/SSAO/ssaoBlur15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldViewMatrix
+ Resolution
+ }
+
+ Defines {
+ USE_AO : UseAo
+ USE_ONLY_AO : UseOnlyAo
+ RESOLVE_MS : NumSamples
+ RESOLVE_DEPTH_MS : NumSamplesDepth
+ }
+ }
+
+ Technique {
+ VertexShader GLSL120: Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL120: Common/MatDefs/SSAO/ssaoBlur.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldViewMatrix
+ Resolution
+
+ }
+
+ Defines {
+ USE_AO : UseAo
+ USE_ONLY_AO : UseOnlyAo
+ RESOLVE_MS : NumSamples
+ RESOLVE_DEPTH_MS : NumSamplesDepth
+ }
+ }
+
+
+
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur15.frag b/engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur15.frag
new file mode 100644
index 0000000..e90a76f
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur15.frag
@@ -0,0 +1,160 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+uniform sampler2D m_SSAOMap;
+uniform vec2 g_Resolution;
+uniform bool m_UseOnlyAo;
+uniform bool m_UseAo;
+uniform float m_XScale;
+uniform float m_YScale;
+uniform vec2 m_FrustumNearFar;
+
+in vec2 texCoord;
+
+vec4 getResult(vec4 color){
+
+ #ifdef USE_ONLY_AO
+ return color;
+ #endif
+ #ifdef USE_AO
+ return getColor(m_Texture,texCoord)* color;
+ #endif
+
+ return getColor(m_Texture,texCoord);
+
+}
+
+float readDepth(in vec2 uv){
+ float depthv =fetchTextureSample(m_DepthTexture,uv,0).r;
+ return (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - depthv* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+}
+
+ const float epsilon = 0.005;
+
+
+/*
+ const int kernelSize=7;
+
+ vec4 bilateralFilter() {
+ vec4 color = vec4(0.0);
+
+ vec2 sample;
+ float sum = 0.0;
+ float coefZ;
+ float Zp = readDepth(texCoord);
+
+ for(int i = -(kernelSize-1); i <= (kernelSize-1); i+=2) {
+ for(int j = -(kernelSize-1); j <= (kernelSize-1); j+=2) {
+ sample = texCoord + vec2(i,j) / g_Resolution;
+ float zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ sum += coefZ;
+
+ color += coefZ * texture2D(m_SSAOMap,sample);
+
+ }
+ }
+
+ return color / sum;
+ }
+*/
+
+ vec4 convolutionFilter(){
+ vec4 sum = vec4(0.0);
+
+ float x = texCoord.x;
+ float y = texCoord.y;
+
+ float xScale = m_XScale;
+ float yScale = m_YScale;
+
+ float zsum = 1.0;
+ float Zp =readDepth(texCoord);
+
+
+ vec2 sample = vec2(x - 2.0 * xScale, y - 2.0 * yScale);
+ float zTmp =readDepth(sample);
+ float coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 0.0 * xScale, y - 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 2.0 * xScale, y - 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 1.0 * xScale, y - 1.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 1.0 * xScale, y - 1.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 2.0 * xScale, y - 0.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 2.0 * xScale, y - 0.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 1.0 * xScale, y + 1.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 1.0 * xScale, y + 1.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 2.0 * xScale, y + 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x - 0.0 * xScale, y + 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+ sample = vec2(x + 2.0 * xScale, y + 2.0 * yScale);
+ zTmp =readDepth(sample);
+ coefZ = 1.0 / (epsilon + abs(Zp - zTmp));
+ zsum += coefZ;
+ sum += coefZ* texture2D( m_SSAOMap, sample);
+
+
+ return sum / zsum;
+ }
+
+
+ void main(){
+ // float depth =texture2D(m_DepthTexture,uv).r;
+
+ gl_FragColor=getResult(convolutionFilter());
+ // gl_FragColor=getResult(bilateralFilter());
+ // gl_FragColor=getColor(m_SSAOMap,texCoord);
+
+ } \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Water/SimpleWater.j3md b/engine/src/core-effects/Common/MatDefs/Water/SimpleWater.j3md
new file mode 100644
index 0000000..1288324
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/SimpleWater.j3md
@@ -0,0 +1,34 @@
+MaterialDef Simple Water {
+
+ MaterialParameters {
+ Texture2D water_reflection
+ Texture2D water_refraction
+ Texture2D water_depthmap
+ Texture2D water_normalmap
+ Texture2D water_dudvmap
+ Vector4 waterColor
+ Vector3 lightPos
+ Float time
+ Float waterDepth
+ Vector4 distortionScale
+ Vector4 distortionMix
+ Vector4 texScale
+ Vector2 FrustumNearFar
+ Float waterTransparency
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Water/simple_water.vert
+ FragmentShader GLSL100: Common/MatDefs/Water/simple_water.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldViewMatrix
+ Resolution
+ CameraPosition
+ }
+ }
+
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/caustics.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/caustics.jpg
new file mode 100644
index 0000000..fb4f21c
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/caustics.jpg
Binary files differ
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/dudv_map.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/dudv_map.jpg
new file mode 100644
index 0000000..a2734bb
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/dudv_map.jpg
Binary files differ
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/foam.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam.jpg
new file mode 100644
index 0000000..fc17ac2
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam.jpg
Binary files differ
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/foam2.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam2.jpg
new file mode 100644
index 0000000..ef19b87
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam2.jpg
Binary files differ
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/foam3.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam3.jpg
new file mode 100644
index 0000000..8295b3f
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam3.jpg
Binary files differ
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/heightmap.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/heightmap.jpg
new file mode 100644
index 0000000..cfb5846
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/heightmap.jpg
Binary files differ
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/water_normalmap.dds b/engine/src/core-effects/Common/MatDefs/Water/Textures/water_normalmap.dds
new file mode 100644
index 0000000..13582e1
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/water_normalmap.dds
Binary files differ
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Water.frag b/engine/src/core-effects/Common/MatDefs/Water/Water.frag
new file mode 100644
index 0000000..928ee22
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Water.frag
@@ -0,0 +1,402 @@
+// Water pixel shader
+// Copyright (C) JMonkeyEngine 3.0
+// by Remy Bouquet (nehon) for JMonkeyEngine 3.0
+// original HLSL version by Wojciech Toman 2009
+
+uniform sampler2D m_HeightMap;
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+uniform sampler2D m_NormalMap;
+uniform sampler2D m_FoamMap;
+uniform sampler2D m_CausticsMap;
+uniform sampler2D m_ReflectionMap;
+
+uniform mat4 m_ViewProjectionMatrixInverse;
+uniform mat4 m_TextureProjMatrix;
+uniform vec3 m_CameraPosition;
+
+uniform float m_WaterHeight;
+uniform float m_Time;
+uniform float m_WaterTransparency;
+uniform float m_NormalScale;
+uniform float m_R0;
+uniform float m_MaxAmplitude;
+uniform vec3 m_LightDir;
+uniform vec4 m_LightColor;
+uniform float m_ShoreHardness;
+uniform float m_FoamHardness;
+uniform float m_RefractionStrength;
+uniform vec3 m_FoamExistence;
+uniform vec3 m_ColorExtinction;
+uniform float m_Shininess;
+uniform vec4 m_WaterColor;
+uniform vec4 m_DeepWaterColor;
+uniform vec2 m_WindDirection;
+uniform float m_SunScale;
+uniform float m_WaveScale;
+uniform float m_UnderWaterFogDistance;
+uniform float m_CausticsIntensity;
+
+vec2 scale = vec2(m_WaveScale, m_WaveScale);
+float refractionScale = m_WaveScale;
+
+// Modifies 4 sampled normals. Increase first values to have more
+// smaller "waves" or last to have more bigger "waves"
+const vec4 normalModifier = vec4(3.0, 2.0, 4.0, 10.0);
+// Strength of displacement along normal.
+// Strength of displacement along normal.
+uniform float m_ReflectionDisplace;
+// Water transparency along eye vector.
+const float visibility = 3.0;
+// foam intensity
+uniform float m_FoamIntensity ;
+
+varying vec2 texCoord;
+
+mat3 MatrixInverse(in mat3 inMatrix){
+ float det = dot(cross(inMatrix[0], inMatrix[1]), inMatrix[2]);
+ mat3 T = transpose(inMatrix);
+ return mat3(cross(T[1], T[2]),
+ cross(T[2], T[0]),
+ cross(T[0], T[1])) / det;
+}
+
+
+mat3 computeTangentFrame(in vec3 N, in vec3 P, in vec2 UV) {
+ vec3 dp1 = dFdx(P);
+ vec3 dp2 = dFdy(P);
+ vec2 duv1 = dFdx(UV);
+ vec2 duv2 = dFdy(UV);
+
+ // solve the linear system
+ mat3 M = mat3(dp1, dp2, cross(dp1, dp2));
+ //vec3 dp1xdp2 = cross(dp1, dp2);
+ mat3 inverseM = MatrixInverse(M);
+ //mat2x3 inverseM = mat2x3(cross(dp2, dp1xdp2), cross(dp1xdp2, dp1));
+
+ vec3 T = inverseM * vec3(duv1.x, duv2.x, 0.0);
+ vec3 B = inverseM * vec3(duv1.y, duv2.y, 0.0);
+
+ //vec3 T = inverseM * vec2(duv1.x, duv2.x);
+ //vec3 B = inverseM * vec2(duv1.y, duv2.y);
+
+ // construct tangent frame
+ float maxLength = max(length(T), length(B));
+ T = T / maxLength;
+ B = B / maxLength;
+
+ //vec3 tangent = normalize(T);
+ //vec3 binormal = normalize(B);
+
+ return mat3(T, B, N);
+}
+
+float saturate(in float val){
+ return clamp(val,0.0,1.0);
+}
+
+vec3 saturate(in vec3 val){
+ return clamp(val,vec3(0.0),vec3(1.0));
+}
+
+
+vec3 getPosition(in float depth, in vec2 uv){
+ vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0;
+ pos = m_ViewProjectionMatrixInverse * pos;
+ return pos.xyz / pos.w;
+}
+
+// Function calculating fresnel term.
+// - normal - normalized normal vector
+// - eyeVec - normalized eye vector
+float fresnelTerm(in vec3 normal,in vec3 eyeVec){
+ float angle = 1.0 - saturate(dot(normal, eyeVec));
+ float fresnel = angle * angle;
+ fresnel = fresnel * fresnel;
+ fresnel = fresnel * angle;
+ return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
+}
+
+vec2 m_FrustumNearFar=vec2(1.0,m_UnderWaterFogDistance);
+const float LOG2 = 1.442695;
+
+vec4 underWater(){
+
+
+ float sceneDepth = texture2D(m_DepthTexture, texCoord).r;
+ vec3 color2 = texture2D(m_Texture, texCoord).rgb;
+
+ vec3 position = getPosition(sceneDepth, texCoord);
+ float level = m_WaterHeight;
+
+ vec3 eyeVec = position - m_CameraPosition;
+
+ // Find intersection with water surface
+ vec3 eyeVecNorm = normalize(eyeVec);
+ float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+ vec2 texC = vec2(0.0);
+
+ float cameraDepth = length(m_CameraPosition - surfacePoint);
+ texC = (surfacePoint.xz + eyeVecNorm.xz) * scale + m_Time * 0.03 * m_WindDirection;
+ float bias = texture2D(m_HeightMap, texC).r;
+ level += bias * m_MaxAmplitude;
+ t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ surfacePoint = m_CameraPosition + eyeVecNorm * t;
+ eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+ // Find normal of water surface
+ float normal1 = texture2D(m_HeightMap, (texC + vec2(-1.0, 0.0) / 256.0)).r;
+ float normal2 = texture2D(m_HeightMap, (texC + vec2(1.0, 0.0) / 256.0)).r;
+ float normal3 = texture2D(m_HeightMap, (texC + vec2(0.0, -1.0) / 256.0)).r;
+ float normal4 = texture2D(m_HeightMap, (texC + vec2(0.0, 1.0) / 256.0)).r;
+
+ vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+ vec3 normal = myNormal*-1.0;
+ float fresnel = fresnelTerm(normal, eyeVecNorm);
+
+ vec3 refraction = color2;
+ #ifdef ENABLE_REFRACTION
+ texC = texCoord.xy *sin (fresnel+1.0);
+ refraction = texture2D(m_Texture, texC).rgb;
+ #endif
+
+ float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+ refraction = mix(mix(refraction, m_DeepWaterColor.rgb * waterCol, m_WaterTransparency), m_WaterColor.rgb* waterCol,m_WaterTransparency);
+
+ vec3 foam = vec3(0.0);
+ #ifdef ENABLE_FOAM
+ texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+ vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+ if(m_MaxAmplitude - m_FoamExistence.z> 0.0001){
+ foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity * m_FoamIntensity * 0.3 *
+ saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+ }
+ foam *= m_LightColor.rgb;
+ #endif
+
+
+
+ vec3 specular = vec3(0.0);
+ vec3 color ;
+ float fogFactor;
+
+ if(position.y>level){
+ #ifdef ENABLE_SPECULAR
+ if(step(0.9999,sceneDepth)==1.0){
+ vec3 lightDir=normalize(m_LightDir);
+ vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+ float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+ specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+ specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+ specular=specular * m_LightColor.rgb * 100.0;
+ }
+ #endif
+ float fogIntensity= 8.0 * m_WaterTransparency;
+ fogFactor = exp2( -fogIntensity * fogIntensity * cameraDepth * 0.03 * LOG2 );
+ fogFactor = clamp(fogFactor, 0.0, 1.0);
+ color =mix(m_DeepWaterColor.rgb,refraction,fogFactor);
+ specular=specular*fogFactor;
+ color = saturate(color + max(specular, foam ));
+ }else{
+ vec3 caustics = vec3(0.0);
+ #ifdef ENABLE_CAUSTICS
+ vec2 windDirection=m_WindDirection;
+ texC = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time + position.x) * 0.01;
+ vec2 texCoord2 = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time + position.z) * 0.01;
+ caustics += (texture2D(m_CausticsMap, texC)+ texture2D(m_CausticsMap, texCoord2)).rgb;
+ caustics=saturate(mix(m_WaterColor.rgb,caustics,m_CausticsIntensity));
+ color=mix(color2,caustics,m_CausticsIntensity);
+ #else
+ color=color2;
+ #endif
+
+ float fogDepth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - sceneDepth* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+ float fogIntensity= 18 * m_WaterTransparency;
+ fogFactor = exp2( -fogIntensity * fogIntensity * fogDepth * fogDepth * LOG2 );
+ fogFactor = clamp(fogFactor, 0.0, 1.0);
+ color =mix(m_DeepWaterColor.rgb,color,fogFactor);
+ }
+
+ return vec4(color, 1.0);
+}
+
+void main(){
+ float sceneDepth = texture2D(m_DepthTexture, texCoord).r;
+ float isAtFarPlane = step(0.99998, sceneDepth);
+
+ vec3 color2 = texture2D(m_Texture, texCoord).rgb;
+ vec3 color = color2;
+
+ vec3 position = getPosition(sceneDepth,texCoord);
+
+ float level = m_WaterHeight;
+
+ // If we are underwater let's go to under water function
+ if(level >= m_CameraPosition.y){
+ gl_FragColor = underWater();
+ return ;
+ }
+
+ //#ifndef ENABLE_RIPPLES
+ // This optimization won't work on NVIDIA cards if ripples are enabled
+ if(position.y > level + m_MaxAmplitude + isAtFarPlane * 100.0){
+ gl_FragColor = vec4(color2, 1.0);
+ return;
+ }
+ //#endif
+
+ vec3 eyeVec = position - m_CameraPosition;
+ float diff = level - position.y;
+ float cameraDepth = m_CameraPosition.y - position.y;
+
+ // Find intersection with water surface
+ vec3 eyeVecNorm = normalize(eyeVec);
+ float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+ vec2 texC;
+ int samples = 1;
+ #ifdef ENABLE_HQ_SHORELINE
+ samples = 10;
+ #endif
+ float biasFactor = 1.0/samples;
+ for (int i = 0; i < samples; i++){
+ texC = (surfacePoint.xz + eyeVecNorm.xz * biasFactor) * scale + m_Time * 0.03 * m_WindDirection;
+
+ float bias = texture2D(m_HeightMap, texC).r;
+
+ bias *= biasFactor;
+ level += bias * m_MaxAmplitude;
+ t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ surfacePoint = m_CameraPosition + eyeVecNorm * t;
+ }
+
+ float depth = length(position - surfacePoint);
+ float depth2 = surfacePoint.y - position.y;
+
+ // XXX: HACK ALERT: Increase water depth to infinity if at far plane
+ // Prevents "foam on horizon" issue
+ // For best results, replace the "100.0" below with the
+ // highest value in the m_ColorExtinction vec3
+ depth += isAtFarPlane * 100.0;
+ depth2 += isAtFarPlane * 100.0;
+
+ eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+ // Find normal of water surface
+ float normal1 = texture2D(m_HeightMap, (texC + vec2(-1.0, 0.0) / 256.0)).r;
+ float normal2 = texture2D(m_HeightMap, (texC + vec2(1.0, 0.0) / 256.0)).r;
+ float normal3 = texture2D(m_HeightMap, (texC + vec2(0.0, -1.0) / 256.0)).r;
+ float normal4 = texture2D(m_HeightMap, (texC + vec2(0.0, 1.0) / 256.0)).r;
+
+ vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+ vec3 normal = vec3(0.0);
+
+ #ifdef ENABLE_RIPPLES
+ texC = surfacePoint.xz * 0.8 + m_WindDirection * m_Time* 1.6;
+ mat3 tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal0a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+ texC = surfacePoint.xz * 0.4 + m_WindDirection * m_Time* 0.8;
+ tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal1a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+ texC = surfacePoint.xz * 0.2 + m_WindDirection * m_Time * 0.4;
+ tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal2a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+ texC = surfacePoint.xz * 0.1 + m_WindDirection * m_Time * 0.2;
+ tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal3a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+ normal = normalize(normal0a * normalModifier.x + normal1a * normalModifier.y +normal2a * normalModifier.z + normal3a * normalModifier.w);
+ // XXX: Here's another way to fix the terrain edge issue,
+ // But it requires GLSL 1.3 and still looks kinda incorrect
+ // around edges
+ // To make the shader 1.2 compatible we use a trick :
+ // we clamp the x value of the normal and compare it to it's former value instead of using isnan.
+ normal = clamp(normal.x,0.0,1.0)!=normal.x ? myNormal : normal;
+ //if (position.y > level){
+ // gl_FragColor = vec4(color2 + normal*0.0001, 1.0);
+ // return;
+ //}
+ #else
+ normal = myNormal;
+ #endif
+
+ vec3 refraction = color2;
+ #ifdef ENABLE_REFRACTION
+ texC = texCoord.xy;
+ texC += sin(m_Time*1.8 + 3.0 * abs(position.y)) * (refractionScale * min(depth2, 1.0));
+ refraction = texture2D(m_Texture, texC).rgb;
+ #endif
+
+ vec3 waterPosition = surfacePoint.xyz;
+ waterPosition.y -= (level - m_WaterHeight);
+ vec4 texCoordProj = m_TextureProjMatrix * vec4(waterPosition, 1.0);
+
+ texCoordProj.x = texCoordProj.x + m_ReflectionDisplace * normal.x;
+ texCoordProj.z = texCoordProj.z + m_ReflectionDisplace * normal.z;
+ texCoordProj /= texCoordProj.w;
+ texCoordProj.y = 1.0 - texCoordProj.y;
+
+ vec3 reflection = texture2D(m_ReflectionMap, texCoordProj.xy).rgb;
+
+ float fresnel = fresnelTerm(normal, eyeVecNorm);
+
+ float depthN = depth * m_WaterTransparency;
+ float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+ refraction = mix(mix(refraction, m_WaterColor.rgb * waterCol, saturate(depthN / visibility)),
+ m_DeepWaterColor.rgb * waterCol, saturate(depth2 / m_ColorExtinction));
+
+ vec3 foam = vec3(0.0);
+ #ifdef ENABLE_FOAM
+ texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+ vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+ if(depth2 < m_FoamExistence.x){
+ foam = (texture2D(m_FoamMap, texC).r + texture2D(m_FoamMap, texCoord2)).rgb * m_FoamIntensity;
+ }else if(depth2 < m_FoamExistence.y){
+ foam = mix((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity, vec4(0.0),
+ (depth2 - m_FoamExistence.x) / (m_FoamExistence.y - m_FoamExistence.x)).rgb;
+ }
+
+ if(m_MaxAmplitude - m_FoamExistence.z > 0.0001){
+ foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity * m_FoamIntensity * 0.3 *
+ saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+ }
+ foam *= m_LightColor.rgb;
+ #endif
+
+ vec3 specular =vec3(0.0);
+ #ifdef ENABLE_SPECULAR
+ vec3 lightDir=normalize(m_LightDir);
+ vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+ float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+ specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+ specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+ //foam does not shine
+ specular=specular * m_LightColor.rgb - (5.0 * foam);
+ #endif
+
+ color = mix(refraction, reflection, fresnel);
+ color = mix(refraction, color, saturate(depth * m_ShoreHardness));
+ color = saturate(color + max(specular, foam ));
+ color = mix(refraction, color, saturate(depth* m_FoamHardness));
+
+
+ // XXX: HACK ALERT:
+ // We trick the GeForces to think they have
+ // to calculate the derivatives for all these pixels by using step()!
+ // That way we won't get pixels around the edges of the terrain,
+ // Where the derivatives are undefined
+ if(position.y > level){
+ color = color2;
+ }
+
+ gl_FragColor = vec4(color,1.0);
+
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Water.j3md b/engine/src/core-effects/Common/MatDefs/Water/Water.j3md
new file mode 100644
index 0000000..160cadb
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Water.j3md
@@ -0,0 +1,90 @@
+MaterialDef Advanced Water {
+
+ MaterialParameters {
+ Int NumSamples
+ Int NumSamplesDepth
+ Texture2D FoamMap
+ Texture2D CausticsMap
+ Texture2D NormalMap
+ Texture2D ReflectionMap
+ Texture2D HeightMap
+ Texture2D Texture
+ Texture2D DepthTexture
+ Vector3 CameraPosition
+ Float Time
+ Vector3 frustumCorner
+ Matrix4 TextureProjMatrix
+ Matrix4 ViewProjectionMatrixInverse
+ Float WaterHeight
+ Vector3 LightDir
+ Float WaterTransparency
+ Float NormalScale
+ Float R0
+ Float MaxAmplitude
+ Color LightColor
+ Float ShoreHardness
+ Float FoamHardness
+ Float RefractionStrength
+ Float WaveScale
+ Vector3 FoamExistence
+ Float SunScale
+ Vector3 ColorExtinction
+ Float Shininess
+ Color WaterColor
+ Color DeepWaterColor
+ Vector2 WindDirection
+ Float ReflectionDisplace
+ Float FoamIntensity
+ Float CausticsIntensity
+ Float UnderWaterFogDistance
+
+ Boolean UseRipples
+ Boolean UseHQShoreline
+ Boolean UseSpecular
+ Boolean UseFoam
+ Boolean UseCaustics
+ Boolean UseRefraction
+
+ }
+
+ Technique {
+ VertexShader GLSL150 : Common/MatDefs/Post/Post15.vert
+ FragmentShader GLSL150 : Common/MatDefs/Water/Water15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ RESOLVE_MS : NumSamples
+ RESOLVE_DEPTH_MS : NumSamplesDepth
+ ENABLE_RIPPLES : UseRipples
+ ENABLE_HQ_SHORELINE : UseHQShoreline
+ ENABLE_SPECULAR : UseSpecular
+ ENABLE_FOAM : UseFoam
+ ENABLE_CAUSTICS : UseCaustics
+ ENABLE_REFRACTION : UseRefraction
+ }
+ }
+
+ Technique {
+ VertexShader GLSL100 : Common/MatDefs/Post/Post.vert
+ FragmentShader GLSL120 : Common/MatDefs/Water/Water.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ Defines {
+ ENABLE_RIPPLES : UseRipples
+ ENABLE_HQ_SHORELINE : UseHQShoreline
+ ENABLE_SPECULAR : UseSpecular
+ ENABLE_FOAM : UseFoam
+ ENABLE_CAUSTICS : UseCaustics
+ ENABLE_REFRACTION : UseRefraction
+
+ }
+ }
+
+ Technique FixedFunc {
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Water15.frag b/engine/src/core-effects/Common/MatDefs/Water/Water15.frag
new file mode 100644
index 0000000..64cf280
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Water15.frag
@@ -0,0 +1,419 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+// Water pixel shader
+// Copyright (C) JMonkeyEngine 3.0
+// by Remy Bouquet (nehon) for JMonkeyEngine 3.0
+// original HLSL version by Wojciech Toman 2009
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+
+uniform sampler2D m_HeightMap;
+uniform sampler2D m_NormalMap;
+uniform sampler2D m_FoamMap;
+uniform sampler2D m_CausticsMap;
+uniform sampler2D m_ReflectionMap;
+
+uniform mat4 m_ViewProjectionMatrixInverse;
+uniform mat4 m_TextureProjMatrix;
+uniform vec3 m_CameraPosition;
+
+uniform float m_WaterHeight;
+uniform float m_Time;
+uniform float m_WaterTransparency;
+uniform float m_NormalScale;
+uniform float m_R0;
+uniform float m_MaxAmplitude;
+uniform vec3 m_LightDir;
+uniform vec4 m_LightColor;
+uniform float m_ShoreHardness;
+uniform float m_FoamHardness;
+uniform float m_RefractionStrength;
+uniform vec3 m_FoamExistence;
+uniform vec3 m_ColorExtinction;
+uniform float m_Shininess;
+uniform vec4 m_WaterColor;
+uniform vec4 m_DeepWaterColor;
+uniform vec2 m_WindDirection;
+uniform float m_SunScale;
+uniform float m_WaveScale;
+uniform float m_UnderWaterFogDistance;
+uniform float m_CausticsIntensity;
+
+
+vec2 scale = vec2(m_WaveScale, m_WaveScale);
+float refractionScale = m_WaveScale;
+
+// Modifies 4 sampled normals. Increase first values to have more
+// smaller "waves" or last to have more bigger "waves"
+const vec4 normalModifier = vec4(3.0, 2.0, 4.0, 10.0);
+// Strength of displacement along normal.
+uniform float m_ReflectionDisplace;
+// Water transparency along eye vector.
+const float visibility = 3.0;
+// foam intensity
+uniform float m_FoamIntensity ;
+
+in vec2 texCoord;
+out vec4 outFragColor;
+
+mat3 MatrixInverse(in mat3 inMatrix){
+ float det = dot(cross(inMatrix[0], inMatrix[1]), inMatrix[2]);
+ mat3 T = transpose(inMatrix);
+ return mat3(cross(T[1], T[2]),
+ cross(T[2], T[0]),
+ cross(T[0], T[1])) / det;
+}
+
+
+mat3 computeTangentFrame(in vec3 N, in vec3 P, in vec2 UV) {
+ vec3 dp1 = dFdx(P);
+ vec3 dp2 = dFdy(P);
+ vec2 duv1 = dFdx(UV);
+ vec2 duv2 = dFdy(UV);
+
+ // solve the linear system
+ vec3 dp1xdp2 = cross(dp1, dp2);
+ mat2x3 inverseM = mat2x3(cross(dp2, dp1xdp2), cross(dp1xdp2, dp1));
+
+ vec3 T = inverseM * vec2(duv1.x, duv2.x);
+ vec3 B = inverseM * vec2(duv1.y, duv2.y);
+
+ // construct tangent frame
+ float maxLength = max(length(T), length(B));
+ T = T / maxLength;
+ B = B / maxLength;
+
+ return mat3(T, B, N);
+}
+
+float saturate(in float val){
+ return clamp(val,0.0,1.0);
+}
+
+vec3 saturate(in vec3 val){
+ return clamp(val,vec3(0.0),vec3(1.0));
+}
+
+vec3 getPosition(in float depth, in vec2 uv){
+ vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0;
+ pos = m_ViewProjectionMatrixInverse * pos;
+ return pos.xyz / pos.w;
+}
+
+// Function calculating fresnel term.
+// - normal - normalized normal vector
+// - eyeVec - normalized eye vector
+float fresnelTerm(in vec3 normal,in vec3 eyeVec){
+ float angle = 1.0 - max(0.0, dot(normal, eyeVec));
+ float fresnel = angle * angle;
+ fresnel = fresnel * fresnel;
+ fresnel = fresnel * angle;
+ return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
+}
+
+vec2 m_FrustumNearFar=vec2(1.0,m_UnderWaterFogDistance);
+const float LOG2 = 1.442695;
+
+vec4 underWater(int sampleNum){
+
+
+ float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r;
+ vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).rgb;
+
+ vec3 position = getPosition(sceneDepth, texCoord);
+ float level = m_WaterHeight;
+
+ vec3 eyeVec = position - m_CameraPosition;
+
+ // Find intersection with water surface
+ vec3 eyeVecNorm = normalize(eyeVec);
+ float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+ vec2 texC = vec2(0.0);
+
+ float cameraDepth = length(m_CameraPosition - surfacePoint);
+ texC = (surfacePoint.xz + eyeVecNorm.xz) * scale + m_Time * 0.03 * m_WindDirection;
+ float bias = texture(m_HeightMap, texC).r;
+ level += bias * m_MaxAmplitude;
+ t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ surfacePoint = m_CameraPosition + eyeVecNorm * t;
+ eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+ // Find normal of water surface
+ float normal1 = textureOffset(m_HeightMap, texC, ivec2(-1.0, 0.0)).r;
+ float normal2 = textureOffset(m_HeightMap, texC, ivec2( 1.0, 0.0)).r;
+ float normal3 = textureOffset(m_HeightMap, texC, ivec2( 0.0, -1.0)).r;
+ float normal4 = textureOffset(m_HeightMap, texC, ivec2( 0.0, 1.0)).r;
+
+ vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+ vec3 normal = myNormal*-1.0;
+ float fresnel = fresnelTerm(normal, eyeVecNorm);
+
+ vec3 refraction = color2;
+ #ifdef ENABLE_REFRACTION
+ texC = texCoord.xy *sin (fresnel+1.0);
+ #ifdef RESOLVE_MS
+ ivec2 iTexC = ivec2(texC * textureSize(m_Texture));
+ refraction = texelFetch(m_Texture, iTexC, sampleNum).rgb;
+ #else
+ ivec2 iTexC = ivec2(texC * textureSize(m_Texture, 0));
+ refraction = texelFetch(m_Texture, iTexC, 0).rgb;
+ #endif
+ #endif
+
+ float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+ refraction = mix(mix(refraction, m_DeepWaterColor.rgb * waterCol, m_WaterTransparency), m_WaterColor.rgb* waterCol,m_WaterTransparency);
+
+ vec3 foam = vec3(0.0);
+ #ifdef ENABLE_FOAM
+ texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+ vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+ if(m_MaxAmplitude - m_FoamExistence.z> 0.0001){
+ foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity * m_FoamIntensity * 0.3 *
+ saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+ }
+ foam *= m_LightColor.rgb;
+ #endif
+
+
+
+ vec3 specular = vec3(0.0);
+ vec3 color ;
+ float fogFactor;
+
+ if(position.y>level){
+ #ifdef ENABLE_SPECULAR
+ if(step(0.9999,sceneDepth)==1.0){
+ vec3 lightDir=normalize(m_LightDir);
+ vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+ float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+ specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+ specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+ specular=specular * m_LightColor.rgb * 100.0;
+ }
+ #endif
+ float fogIntensity= 8.0 * m_WaterTransparency;
+ fogFactor = exp2( -fogIntensity * fogIntensity * cameraDepth * 0.03 * LOG2 );
+ fogFactor = clamp(fogFactor, 0.0, 1.0);
+ color =mix(m_DeepWaterColor.rgb,refraction,fogFactor);
+ specular=specular*fogFactor;
+ color = saturate(color + max(specular, foam ));
+ }else{
+ vec3 caustics = vec3(0.0);
+ #ifdef ENABLE_CAUSTICS
+ vec2 windDirection=m_WindDirection;
+ texC = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time + position.x) * 0.01;
+ vec2 texCoord2 = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time + position.z) * 0.01;
+ caustics += (texture2D(m_CausticsMap, texC)+ texture2D(m_CausticsMap, texCoord2)).rgb;
+ caustics=saturate(mix(m_WaterColor.rgb,caustics,m_CausticsIntensity));
+ color=mix(color2,caustics,m_CausticsIntensity);
+ #else
+ color=color2;
+ #endif
+
+ float fogDepth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - sceneDepth* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+ float fogIntensity= 18 * m_WaterTransparency;
+ fogFactor = exp2( -fogIntensity * fogIntensity * fogDepth * fogDepth * LOG2 );
+ fogFactor = clamp(fogFactor, 0.0, 1.0);
+ color =mix(m_DeepWaterColor.rgb,color,fogFactor);
+ }
+
+ return vec4(color, 1.0);
+}
+// NOTE: This will be called even for single-sampling
+vec4 main_multiSample(int sampleNum){
+ // If we are underwater let's call the underwater function
+ if(m_WaterHeight >= m_CameraPosition.y){
+
+ return underWater(sampleNum);
+ }
+
+ float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r;
+ vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).rgb;
+
+ vec3 color = color2;
+ vec3 position = getPosition(sceneDepth, texCoord);
+
+ float level = m_WaterHeight;
+
+ float isAtFarPlane = step(0.99998, sceneDepth);
+ //#ifndef ENABLE_RIPPLES
+ // This optimization won't work on NVIDIA cards if ripples are enabled
+ if(position.y > level + m_MaxAmplitude + isAtFarPlane * 100.0){
+
+ return vec4(color2, 1.0);
+ }
+ //#endif
+
+ vec3 eyeVec = position - m_CameraPosition;
+ float cameraDepth = m_CameraPosition.y - position.y;
+
+ // Find intersection with water surface
+ vec3 eyeVecNorm = normalize(eyeVec);
+ float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+ vec2 texC = vec2(0.0);
+ int samples = 1;
+ #ifdef ENABLE_HQ_SHORELINE
+ samples = 10;
+ #endif
+
+ float biasFactor = 1.0 / samples;
+ for (int i = 0; i < samples; i++){
+ texC = (surfacePoint.xz + eyeVecNorm.xz * biasFactor) * scale + m_Time * 0.03 * m_WindDirection;
+
+ float bias = texture(m_HeightMap, texC).r;
+
+ bias *= biasFactor;
+ level += bias * m_MaxAmplitude;
+ t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ surfacePoint = m_CameraPosition + eyeVecNorm * t;
+ }
+
+ float depth = length(position - surfacePoint);
+ float depth2 = surfacePoint.y - position.y;
+
+ // XXX: HACK ALERT: Increase water depth to infinity if at far plane
+ // Prevents "foam on horizon" issue
+ // For best results, replace the "100.0" below with the
+ // highest value in the m_ColorExtinction vec3
+ depth += isAtFarPlane * 100.0;
+ depth2 += isAtFarPlane * 100.0;
+
+ eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+ // Find normal of water surface
+ float normal1 = textureOffset(m_HeightMap, texC, ivec2(-1.0, 0.0)).r;
+ float normal2 = textureOffset(m_HeightMap, texC, ivec2( 1.0, 0.0)).r;
+ float normal3 = textureOffset(m_HeightMap, texC, ivec2( 0.0, -1.0)).r;
+ float normal4 = textureOffset(m_HeightMap, texC, ivec2( 0.0, 1.0)).r;
+
+ vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+ vec3 normal = vec3(0.0);
+
+ #ifdef ENABLE_RIPPLES
+ texC = surfacePoint.xz * 0.8 + m_WindDirection * m_Time* 1.6;
+ mat3 tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal0a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
+
+ texC = surfacePoint.xz * 0.4 + m_WindDirection * m_Time* 0.8;
+ tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal1a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
+
+ texC = surfacePoint.xz * 0.2 + m_WindDirection * m_Time * 0.4;
+ tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal2a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
+
+ texC = surfacePoint.xz * 0.1 + m_WindDirection * m_Time * 0.2;
+ tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal3a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
+
+ normal = normalize(normal0a * normalModifier.x + normal1a * normalModifier.y +normal2a * normalModifier.z + normal3a * normalModifier.w);
+ // XXX: Here's another way to fix the terrain edge issue,
+ // But it requires GLSL 1.3 and still looks kinda incorrect
+ // around edges
+ normal = isnan(normal.x) ? myNormal : normal;
+ //if (position.y > level){
+ // gl_FragColor = vec4(color2 + normal*0.0001, 1.0);
+ // return;
+ //}
+ #else
+ normal = myNormal;
+ #endif
+
+ vec3 refraction = color2;
+ #ifdef ENABLE_REFRACTION
+ // texC = texCoord.xy+ m_ReflectionDisplace * normal.x;
+ texC = texCoord.xy;
+ texC += sin(m_Time*1.8 + 3.0 * abs(position.y)) * (refractionScale * min(depth2, 1.0));
+ #ifdef RESOLVE_MS
+ ivec2 iTexC = ivec2(texC * textureSize(m_Texture));
+ refraction = texelFetch(m_Texture, iTexC, sampleNum).rgb;
+ #else
+ ivec2 iTexC = ivec2(texC * textureSize(m_Texture, 0));
+ refraction = texelFetch(m_Texture, iTexC, 0).rgb;
+ #endif
+ #endif
+
+ vec3 waterPosition = surfacePoint.xyz;
+ waterPosition.y -= (level - m_WaterHeight);
+ vec4 texCoordProj = m_TextureProjMatrix * vec4(waterPosition, 1.0);
+
+ texCoordProj.x = texCoordProj.x + m_ReflectionDisplace * normal.x;
+ texCoordProj.z = texCoordProj.z + m_ReflectionDisplace * normal.z;
+ texCoordProj /= texCoordProj.w;
+ texCoordProj.y = 1.0 - texCoordProj.y;
+
+ vec3 reflection = texture(m_ReflectionMap, texCoordProj.xy).rgb;
+
+ float fresnel = fresnelTerm(normal, eyeVecNorm);
+
+ float depthN = depth * m_WaterTransparency;
+ float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+ refraction = mix(mix(refraction, m_WaterColor.rgb * waterCol, saturate(depthN / visibility)),
+ m_DeepWaterColor.rgb * waterCol, saturate(depth2 / m_ColorExtinction));
+
+
+
+
+ vec3 foam = vec3(0.0);
+ #ifdef ENABLE_FOAM
+ texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+ vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+ if(depth2 < m_FoamExistence.x){
+ foam = (texture2D(m_FoamMap, texC).r + texture2D(m_FoamMap, texCoord2)).rgb * vec3(m_FoamIntensity);
+ }else if(depth2 < m_FoamExistence.y){
+ foam = mix((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity , vec4(0.0),
+ (depth2 - m_FoamExistence.x) / (m_FoamExistence.y - m_FoamExistence.x)).rgb;
+ }
+
+
+ if(m_MaxAmplitude - m_FoamExistence.z> 0.0001){
+ foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity * m_FoamIntensity * 0.3 *
+ saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+ }
+ foam *= m_LightColor.rgb;
+ #endif
+
+ vec3 specular = vec3(0.0);
+ #ifdef ENABLE_SPECULAR
+ vec3 lightDir=normalize(m_LightDir);
+ vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+ float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+ specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+ specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+ //foam does not shine
+ specular=specular * m_LightColor.rgb - (5.0 * foam);
+ #endif
+
+ color = mix(refraction, reflection, fresnel);
+ color = mix(refraction, color, saturate(depth * m_ShoreHardness));
+ color = saturate(color + max(specular, foam ));
+ color = mix(refraction, color, saturate(depth* m_FoamHardness));
+
+
+ // XXX: HACK ALERT:
+ // We trick the GeForces to think they have
+ // to calculate the derivatives for all these pixels by using step()!
+ // That way we won't get pixels around the edges of the terrain,
+ // Where the derivatives are undefined
+ return vec4(mix(color, color2, step(level, position.y)), 1.0);
+}
+
+void main(){
+ #ifdef RESOLVE_MS
+ vec4 color = vec4(0.0);
+ for (int i = 0; i < m_NumSamples; i++){
+ color += main_multiSample(i);
+ }
+ outFragColor = color / m_NumSamples;
+ #else
+ outFragColor = main_multiSample(0);
+ #endif
+} \ No newline at end of file
diff --git a/engine/src/core-effects/Common/MatDefs/Water/simple_water.frag b/engine/src/core-effects/Common/MatDefs/Water/simple_water.frag
new file mode 100644
index 0000000..65a9c99
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/simple_water.frag
@@ -0,0 +1,126 @@
+/*
+GLSL conversion of Michael Horsch water demo
+http://www.bonzaisoftware.com/wfs.html
+Converted by Mars_999
+8/20/2005
+*/
+
+uniform sampler2D m_water_normalmap;
+uniform sampler2D m_water_reflection;
+uniform sampler2D m_water_refraction;
+uniform sampler2D m_water_dudvmap;
+uniform sampler2D m_water_depthmap;
+uniform vec4 m_waterColor;
+uniform float m_waterDepth;
+uniform vec4 m_distortionScale;
+uniform vec4 m_distortionMix;
+uniform vec4 m_texScale;
+uniform vec2 m_FrustumNearFar;
+uniform float m_waterTransparency;
+
+
+
+varying vec4 lightDir; //lightpos
+varying vec4 waterTex1; //moving texcoords
+varying vec4 waterTex2; //moving texcoords
+varying vec4 position; //for projection
+varying vec4 viewDir; //viewts
+varying vec4 viewLightDir;
+varying vec4 viewCamDir;
+
+//unit 0 = m_water_reflection
+//unit 1 = m_water_refraction
+//unit 2 = m_water_normalmap
+//unit 3 = m_water_dudvmap
+//unit 4 = m_water_depthmap
+
+ const vec4 two = vec4(2.0, 2.0, 2.0, 1.0);
+ const vec4 mone = vec4(-1.0, -1.0, -1.0, 1.0);
+
+ const vec4 ofive = vec4(0.5,0.5,0.5,1.0);
+
+ const float exponent = 64.0;
+
+float tangDot(in vec3 v1, in vec3 v2){
+ float d = dot(v1,v2);
+ #ifdef V_TANGENT
+ d = 1.0 - d*d;
+ return step(0.0, d) * sqrt(d);
+ #else
+ return d;
+ #endif
+}
+
+vec4 readDepth(vec2 uv){
+ float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - texture2D(m_water_depthmap, uv).r* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+ return vec4( depth);
+}
+
+void main(void)
+{
+
+
+ vec4 lightTS = normalize(lightDir);
+ vec4 viewt = normalize(viewDir);
+ vec4 disdis = texture2D(m_water_dudvmap, vec2(waterTex2 * m_texScale));
+ vec4 fdist = texture2D(m_water_dudvmap, vec2(waterTex1 + disdis*m_distortionMix));
+ fdist =normalize( fdist * 2.0 - 1.0)* m_distortionScale;
+
+
+ //load normalmap
+ vec4 nmap = texture2D(m_water_normalmap, vec2(waterTex1 + disdis*m_distortionMix));
+ nmap = (nmap-ofive) * two;
+ // nmap = nmap*2.0-1.0;
+ vec4 vNorm = normalize(nmap);
+
+
+ vec4 projCoord = position / position.w;
+ projCoord =(projCoord+1.0)*0.5 + fdist;
+ projCoord = clamp(projCoord, 0.001, 0.999);
+
+ //load reflection,refraction and depth texture
+ vec4 refl = texture2D(m_water_reflection, vec2(projCoord.x,1.0-projCoord.y));
+ vec4 refr = texture2D(m_water_refraction, vec2(projCoord));
+ vec4 wdepth =readDepth(vec2(projCoord));
+
+ wdepth = vec4(pow(wdepth.x, m_waterDepth));
+ vec4 invdepth = 1.0 - wdepth;
+
+
+ // Blinn - Phong
+ // vec4 H = (viewt - lightTS);
+ // vec4 specular =vec4(pow(max(dot(H, vNorm), 0.0), exponent));
+
+// Standard Phong
+
+ // vec4 R =reflect(-L, vNorm);
+ // vec4 specular =vec4( pow(max(dot(R, E), 0.0),exponent));
+
+
+ //calculate specular highlight
+ vec4 L=normalize(viewLightDir);
+ vec4 E=normalize(viewCamDir);
+ vec4 vRef = normalize(reflect(-L,vNorm));
+ float stemp =max(0.0, dot( vRef,E) );
+ //initializing to 0 to avoid artifacts on old intel cards
+ vec4 specular = vec4(0.0,0.0,0.0,0.0);
+ if(stemp>0.0){
+ stemp = pow(stemp, exponent);
+ specular = vec4(stemp);
+ }
+
+
+
+ vec4 fresnelTerm = vec4(0.02+0.97*pow((1.0-dot(normalize(viewt), vNorm)),5.0));
+
+
+
+ fresnelTerm=fresnelTerm*invdepth*m_waterTransparency;
+ fresnelTerm=clamp(fresnelTerm,0.0,1.0);
+
+ refr*=(fresnelTerm);
+ refr *= invdepth;
+ refr= refr+ m_waterColor*wdepth*fresnelTerm;
+
+ gl_FragColor =(refr+ refl*(1.0-fresnelTerm))+specular;
+}
diff --git a/engine/src/core-effects/Common/MatDefs/Water/simple_water.vert b/engine/src/core-effects/Common/MatDefs/Water/simple_water.vert
new file mode 100644
index 0000000..e6052d8
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/simple_water.vert
@@ -0,0 +1,87 @@
+/*
+GLSL conversion of Michael Horsch water demo
+http://www.bonzaisoftware.com/wfs.html
+Converted by Mars_999
+8/20/2005
+*/
+uniform vec3 m_lightPos;
+uniform float m_time;
+
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform mat4 g_WorldViewMatrix;
+uniform mat4 g_ViewMatrix;
+uniform vec3 g_CameraPosition;
+uniform mat3 g_NormalMatrix;
+
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+attribute vec3 inTangent;
+attribute vec3 inNormal;
+
+varying vec4 lightDir;
+varying vec4 waterTex1;
+varying vec4 waterTex2;
+varying vec4 position;
+varying vec4 viewDir;
+varying vec4 viewpos;
+varying vec4 viewLightDir;
+varying vec4 viewCamDir;
+
+
+//unit 0 = water_reflection
+//unit 1 = water_refraction
+//unit 2 = water_normalmap
+//unit 3 = water_dudvmap
+//unit 4 = water_depthmap
+
+void main(void)
+{
+ viewpos.x = g_CameraPosition.x;
+ viewpos.y = g_CameraPosition.y;
+ viewpos.z = g_CameraPosition.z;
+ viewpos.w = 1.0;
+
+ vec4 temp;
+ vec4 tangent = vec4(1.0, 0.0, 0.0, 0.0);
+ vec4 norm = vec4(0.0, 1.0, 0.0, 0.0);
+ vec4 binormal = vec4(0.0, 0.0, 1.0, 0.0);
+
+
+ temp = viewpos - inPosition;
+
+ viewDir.x = dot(temp, tangent);
+ viewDir.y = dot(temp, binormal);
+ viewDir.z = dot(temp, norm);
+ viewDir.w = 0.0;
+
+ temp = vec4(m_lightPos,1.0)- inPosition;
+ lightDir.x = dot(temp, tangent);
+ lightDir.y = dot(temp, binormal);
+ lightDir.z = dot(temp, norm);
+ lightDir.w = 0.0;
+
+ vec4 viewSpaceLightPos=g_ViewMatrix*vec4(m_lightPos,1.0);
+ vec4 viewSpacePos=g_WorldViewMatrix*inPosition;
+ vec3 wvNormal = normalize(g_NormalMatrix * inNormal);
+ vec3 wvTangent = normalize(g_NormalMatrix * inTangent);
+ vec3 wvBinormal = cross(wvNormal, wvTangent);
+ mat3 tbnMat = mat3(wvTangent, wvBinormal, wvNormal);
+
+ temp = viewSpaceLightPos - viewSpacePos;
+ viewLightDir.xyz=temp.xyz*tbnMat;
+ viewLightDir.w = 0.0;
+
+ temp = -viewSpacePos;
+ viewCamDir.xyz =temp.xyz*tbnMat;
+ viewCamDir.w = 0.0;
+
+
+ vec4 t1 = vec4(0.0, -m_time, 0.0,0.0);
+ vec4 t2 = vec4(0.0, m_time, 0.0,0.0);
+
+ waterTex1 =vec4(inTexCoord,0.0,0.0) + t1;
+ waterTex2 =vec4(inTexCoord ,0.0,0.0)+ t2;
+
+ position = g_WorldViewProjectionMatrix * inPosition;
+ gl_Position = position;
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/BloomFilter.java b/engine/src/core-effects/com/jme3/post/filters/BloomFilter.java
new file mode 100644
index 0000000..770e7f4
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/BloomFilter.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+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 com.jme3.texture.Image.Format;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * BloomFilter is used to make objects in the scene have a glow effect.<br>
+ * There are 2 mode : Scene and Objects.<br>
+ * Scene mode extracts the bright parts of the scene to make them glow<br>
+ * Object mode make objects glow according to their material's glowMap or their GlowColor<br>
+ * @see <a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:bloom_and_glow">advanced:bloom_and_glow</a> for more details
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class BloomFilter extends Filter {
+
+ /**
+ * GlowMode specifies if the glow will be applied to the whole scene,or to objects that have aglow color or a glow map
+ */
+ public enum GlowMode {
+
+ /**
+ * Apply bloom filter to bright areas in the scene.
+ */
+ Scene,
+ /**
+ * Apply bloom only to objects that have a glow map or a glow color.
+ */
+ Objects,
+ /**
+ * Apply bloom to both bright parts of the scene and objects with glow map.
+ */
+ SceneAndObjects;
+ }
+
+ private GlowMode glowMode = GlowMode.Scene;
+ //Bloom parameters
+ private float blurScale = 1.5f;
+ private float exposurePower = 5.0f;
+ private float exposureCutOff = 0.0f;
+ private float bloomIntensity = 2.0f;
+ private float downSamplingFactor = 1;
+ private Pass preGlowPass;
+ private Pass extractPass;
+ private Pass horizontalBlur = new Pass();
+ private Pass verticalalBlur = new Pass();
+ private Material extractMat;
+ private Material vBlurMat;
+ private Material hBlurMat;
+ private int screenWidth;
+ private int screenHeight;
+
+ /**
+ * Creates a Bloom filter
+ */
+ public BloomFilter() {
+ super("BloomFilter");
+ }
+
+ /**
+ * Creates the bloom filter with the specific glow mode
+ * @param glowMode
+ */
+ public BloomFilter(GlowMode glowMode) {
+ this();
+ this.glowMode = glowMode;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ screenWidth = (int) Math.max(1, (w / downSamplingFactor));
+ screenHeight = (int) Math.max(1, (h / downSamplingFactor));
+ // System.out.println(screenWidth + " " + screenHeight);
+ if (glowMode != GlowMode.Scene) {
+ preGlowPass = new Pass();
+ preGlowPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth);
+ }
+
+ postRenderPasses = new ArrayList<Pass>();
+ //configuring extractPass
+ extractMat = new Material(manager, "Common/MatDefs/Post/BloomExtract.j3md");
+ extractPass = new Pass() {
+
+ @Override
+ public boolean requiresSceneAsTexture() {
+ return true;
+ }
+
+ @Override
+ public void beforeRender() {
+ extractMat.setFloat("ExposurePow", exposurePower);
+ extractMat.setFloat("ExposureCutoff", exposureCutOff);
+ if (glowMode != GlowMode.Scene) {
+ extractMat.setTexture("GlowMap", preGlowPass.getRenderedTexture());
+ }
+ extractMat.setBoolean("Extract", glowMode != GlowMode.Objects);
+ }
+ };
+
+ extractPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, extractMat);
+ postRenderPasses.add(extractPass);
+
+ //configuring horizontal blur pass
+ hBlurMat = new Material(manager, "Common/MatDefs/Blur/HGaussianBlur.j3md");
+ horizontalBlur = new Pass() {
+
+ @Override
+ public void beforeRender() {
+ hBlurMat.setTexture("Texture", extractPass.getRenderedTexture());
+ hBlurMat.setFloat("Size", screenWidth);
+ hBlurMat.setFloat("Scale", blurScale);
+ }
+ };
+
+ horizontalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, hBlurMat);
+ postRenderPasses.add(horizontalBlur);
+
+ //configuring vertical blur pass
+ vBlurMat = new Material(manager, "Common/MatDefs/Blur/VGaussianBlur.j3md");
+ verticalalBlur = new Pass() {
+
+ @Override
+ public void beforeRender() {
+ vBlurMat.setTexture("Texture", horizontalBlur.getRenderedTexture());
+ vBlurMat.setFloat("Size", screenHeight);
+ vBlurMat.setFloat("Scale", blurScale);
+ }
+ };
+
+ verticalalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, vBlurMat);
+ postRenderPasses.add(verticalalBlur);
+
+
+ //final material
+ material = new Material(manager, "Common/MatDefs/Post/BloomFinal.j3md");
+ material.setTexture("BloomTex", verticalalBlur.getRenderedTexture());
+ }
+
+
+ @Override
+ protected Material getMaterial() {
+ material.setFloat("BloomIntensity", bloomIntensity);
+ return material;
+ }
+
+ @Override
+ protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+ if (glowMode != GlowMode.Scene) {
+ renderManager.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha);
+ renderManager.getRenderer().setFrameBuffer(preGlowPass.getRenderFrameBuffer());
+ renderManager.getRenderer().clearBuffers(true, true, true);
+ renderManager.setForcedTechnique("Glow");
+ renderManager.renderViewPortQueues(viewPort, false);
+ renderManager.setForcedTechnique(null);
+ renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+ }
+ }
+
+ /**
+ * returns the bloom intensity
+ * @return
+ */
+ public float getBloomIntensity() {
+ return bloomIntensity;
+ }
+
+ /**
+ * intensity of the bloom effect default is 2.0
+ * @param bloomIntensity
+ */
+ public void setBloomIntensity(float bloomIntensity) {
+ this.bloomIntensity = bloomIntensity;
+ }
+
+ /**
+ * returns the blur scale
+ * @return
+ */
+ public float getBlurScale() {
+ return blurScale;
+ }
+
+ /**
+ * sets The spread of the bloom default is 1.5f
+ * @param blurScale
+ */
+ public void setBlurScale(float blurScale) {
+ this.blurScale = blurScale;
+ }
+
+ /**
+ * returns the exposure cutoff<br>
+ * for more details see {@link setExposureCutOff(float exposureCutOff)}
+ * @return
+ */
+ public float getExposureCutOff() {
+ return exposureCutOff;
+ }
+
+ /**
+ * Define the color threshold on which the bloom will be applied (0.0 to 1.0)
+ * @param exposureCutOff
+ */
+ public void setExposureCutOff(float exposureCutOff) {
+ this.exposureCutOff = exposureCutOff;
+ }
+
+ /**
+ * returns the exposure power<br>
+ * form more details see {@link setExposurePower(float exposurePower)}
+ * @return
+ */
+ public float getExposurePower() {
+ return exposurePower;
+ }
+
+ /**
+ * defines how many time the bloom extracted color will be multiplied by itself. default id 5.0<br>
+ * a high value will reduce rough edges in the bloom and somhow the range of the bloom area *
+ * @param exposurePower
+ */
+ public void setExposurePower(float exposurePower) {
+ this.exposurePower = exposurePower;
+ }
+
+ /**
+ * returns the downSampling factor<br>
+ * form more details see {@link setDownSamplingFactor(float downSamplingFactor)}
+ * @return
+ */
+ public float getDownSamplingFactor() {
+ return downSamplingFactor;
+ }
+
+ /**
+ * Sets the downSampling factor : the size of the computed texture will be divided by this factor. default is 1 for no downsampling
+ * A 2 value is a good way of widening the blur
+ * @param downSamplingFactor
+ */
+ public void setDownSamplingFactor(float downSamplingFactor) {
+ this.downSamplingFactor = downSamplingFactor;
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(glowMode, "glowMode", GlowMode.Scene);
+ oc.write(blurScale, "blurScale", 1.5f);
+ oc.write(exposurePower, "exposurePower", 5.0f);
+ oc.write(exposureCutOff, "exposureCutOff", 0.0f);
+ oc.write(bloomIntensity, "bloomIntensity", 2.0f);
+ oc.write(downSamplingFactor, "downSamplingFactor", 1);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ glowMode = ic.readEnum("glowMode", GlowMode.class, GlowMode.Scene);
+ blurScale = ic.readFloat("blurScale", 1.5f);
+ exposurePower = ic.readFloat("exposurePower", 5.0f);
+ exposureCutOff = ic.readFloat("exposureCutOff", 0.0f);
+ bloomIntensity = ic.readFloat("bloomIntensity", 2.0f);
+ downSamplingFactor = ic.readFloat("downSamplingFactor", 1);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java b/engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java
new file mode 100644
index 0000000..3e9998b
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.post.Filter.Pass;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.texture.Image.Format;
+
+/**
+ * Applies a cartoon-style edge detection filter to all objects in the scene.
+ *
+ * @author Kirill Vainer
+ */
+public class CartoonEdgeFilter extends Filter {
+
+ private Pass normalPass;
+ private float edgeWidth = 1.0f;
+ private float edgeIntensity = 1.0f;
+ private float normalThreshold = 0.5f;
+ private float depthThreshold = 0.1f;
+ private float normalSensitivity = 1.0f;
+ private float depthSensitivity = 10.0f;
+ private ColorRGBA edgeColor = new ColorRGBA(0, 0, 0, 1);
+
+ /**
+ * Creates a CartoonEdgeFilter
+ */
+ public CartoonEdgeFilter() {
+ super("CartoonEdgeFilter");
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+ Renderer r = renderManager.getRenderer();
+ r.setFrameBuffer(normalPass.getRenderFrameBuffer());
+ renderManager.getRenderer().clearBuffers(true, true, true);
+ renderManager.setForcedTechnique("PreNormalPass");
+ renderManager.renderViewPortQueues(viewPort, false);
+ renderManager.setForcedTechnique(null);
+ renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+ }
+
+ @Override
+ protected Material getMaterial() {
+ material.setTexture("NormalsTexture", normalPass.getRenderedTexture());
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ normalPass = new Pass();
+ normalPass.init(renderManager.getRenderer(), w, h, Format.RGBA8, Format.Depth);
+ material = new Material(manager, "Common/MatDefs/Post/CartoonEdge.j3md");
+ material.setFloat("EdgeWidth", edgeWidth);
+ material.setFloat("EdgeIntensity", edgeIntensity);
+ material.setFloat("NormalThreshold", normalThreshold);
+ material.setFloat("DepthThreshold", depthThreshold);
+ material.setFloat("NormalSensitivity", normalSensitivity);
+ material.setFloat("DepthSensitivity", depthSensitivity);
+ material.setColor("EdgeColor", edgeColor);
+ }
+
+ /**
+ * Return the depth sensitivity<br>
+ * for more details see {@link setDepthSensitivity(float depthSensitivity)}
+ * @return
+ */
+ public float getDepthSensitivity() {
+ return depthSensitivity;
+ }
+
+ /**
+ * sets the depth sensitivity<br>
+ * defines how much depth will influence edges, default is 10
+ * @param depthSensitivity
+ */
+ public void setDepthSensitivity(float depthSensitivity) {
+ this.depthSensitivity = depthSensitivity;
+ if (material != null) {
+ material.setFloat("DepthSensitivity", depthSensitivity);
+ }
+ }
+
+ /**
+ * returns the depth threshold<br>
+ * for more details see {@link setDepthThreshold(float depthThreshold)}
+ * @return
+ */
+ public float getDepthThreshold() {
+ return depthThreshold;
+ }
+
+ /**
+ * sets the depth threshold<br>
+ * Defines at what threshold of difference of depth an edge is outlined default is 0.1f
+ * @param depthThreshold
+ */
+ public void setDepthThreshold(float depthThreshold) {
+ this.depthThreshold = depthThreshold;
+ if (material != null) {
+ material.setFloat("DepthThreshold", depthThreshold);
+ }
+ }
+
+ /**
+ * returns the edge intensity<br>
+ * for more details see {@link setEdgeIntensity(float edgeIntensity) }
+ * @return
+ */
+ public float getEdgeIntensity() {
+ return edgeIntensity;
+ }
+
+ /**
+ * sets the edge intensity<br>
+ * Defineshow visilble will be the outlined edges
+ * @param edgeIntensity
+ */
+ public void setEdgeIntensity(float edgeIntensity) {
+ this.edgeIntensity = edgeIntensity;
+ if (material != null) {
+ material.setFloat("EdgeIntensity", edgeIntensity);
+ }
+ }
+
+ /**
+ * returns the width of the edges
+ * @return
+ */
+ public float getEdgeWidth() {
+ return edgeWidth;
+ }
+
+ /**
+ * sets the witdh of the edge in pixels default is 1
+ * @param edgeWidth
+ */
+ public void setEdgeWidth(float edgeWidth) {
+ this.edgeWidth = edgeWidth;
+ if (material != null) {
+ material.setFloat("EdgeWidth", edgeWidth);
+ }
+
+ }
+
+ /**
+ * returns the normals sensitivity<br>
+ * form more details see {@link setNormalSensitivity(float normalSensitivity)}
+ * @return
+ */
+ public float getNormalSensitivity() {
+ return normalSensitivity;
+ }
+
+ /**
+ * sets the normals sensitivity default is 1
+ * @param normalSensitivity
+ */
+ public void setNormalSensitivity(float normalSensitivity) {
+ this.normalSensitivity = normalSensitivity;
+ if (material != null) {
+ material.setFloat("NormalSensitivity", normalSensitivity);
+ }
+ }
+
+ /**
+ * returns the normal threshold<br>
+ * for more details see {@link setNormalThreshold(float normalThreshold)}
+ *
+ * @return
+ */
+ public float getNormalThreshold() {
+ return normalThreshold;
+ }
+
+ /**
+ * sets the normal threshold default is 0.5
+ * @param normalThreshold
+ */
+ public void setNormalThreshold(float normalThreshold) {
+ this.normalThreshold = normalThreshold;
+ if (material != null) {
+ material.setFloat("NormalThreshold", normalThreshold);
+ }
+ }
+
+ /**
+ * returns the edge color
+ * @return
+ */
+ public ColorRGBA getEdgeColor() {
+ return edgeColor;
+ }
+
+ /**
+ * Sets the edge color, default is black
+ * @param edgeColor
+ */
+ public void setEdgeColor(ColorRGBA edgeColor) {
+ this.edgeColor = edgeColor;
+ if (material != null) {
+ material.setColor("EdgeColor", edgeColor);
+ }
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java b/engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java
new file mode 100644
index 0000000..a7f30f8
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+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;
+
+/**
+ * This filter simply multiply the whole scene by a color
+ * @author Rémy Bouquet aka Nehon
+ */
+public class ColorOverlayFilter extends Filter {
+
+ private ColorRGBA color = ColorRGBA.White;
+
+ /**
+ * creates a colorOverlayFilter with a white coor (transparent)
+ */
+ public ColorOverlayFilter() {
+ super("Color Overlay");
+ }
+
+ /**
+ * creates a colorOverlayFilter with the given color
+ * @param color
+ */
+ public ColorOverlayFilter(ColorRGBA color) {
+ this();
+ this.color = color;
+ }
+
+ @Override
+ protected Material getMaterial() {
+
+ material.setColor("Color", color);
+ return material;
+ }
+
+ /**
+ * returns the color
+ * @return color
+ */
+ public ColorRGBA getColor() {
+ return color;
+ }
+
+ /**
+ * sets the color
+ * @param color
+ */
+ public void setColor(ColorRGBA color) {
+ this.color = color;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(color, "color", ColorRGBA.White);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ color = (ColorRGBA) ic.readSavable("color", ColorRGBA.White);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java b/engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java
new file mode 100644
index 0000000..699a252
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+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;
+
+/**
+ * A Post Processing filter that makes the screen look like it was drawn as
+ * diagonal lines with a pen.
+ * Try combining this with a cartoon edge filter to obtain manga style visuals.
+ *
+ * Based on an article from Geeks3D:
+ * <a href="http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/" rel="nofollow">http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/</a>
+ *
+ * @author Roy Straver a.k.a. Baal Garnaal
+ */
+public class CrossHatchFilter extends Filter {
+
+ private ColorRGBA lineColor = ColorRGBA.Black.clone();
+ private ColorRGBA paperColor = ColorRGBA.White.clone();
+ private float colorInfluenceLine = 0.8f;
+ private float colorInfluencePaper = 0.1f;
+ private float fillValue = 0.9f;
+ private float luminance1 = 0.9f;
+ private float luminance2 = 0.7f;
+ private float luminance3 = 0.5f;
+ private float luminance4 = 0.3f;
+ private float luminance5 = 0.0f;
+ private float lineThickness = 1.0f;
+ private float lineDistance = 4.0f;
+
+ /**
+ * Creates a crossHatch filter
+ */
+ public CrossHatchFilter() {
+ super("CrossHatchFilter");
+ }
+
+ /**
+ * Creates a crossHatch filter
+ * @param lineColor the colors of the lines
+ * @param paperColor the paper color
+ */
+ public CrossHatchFilter(ColorRGBA lineColor, ColorRGBA paperColor) {
+ this();
+ this.lineColor = lineColor;
+ this.paperColor = paperColor;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return false;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/CrossHatch.j3md");
+ material.setColor("LineColor", lineColor);
+ material.setColor("PaperColor", paperColor);
+
+ material.setFloat("ColorInfluenceLine", colorInfluenceLine);
+ material.setFloat("ColorInfluencePaper", colorInfluencePaper);
+
+ material.setFloat("FillValue", fillValue);
+
+ material.setFloat("Luminance1", luminance1);
+ material.setFloat("Luminance2", luminance2);
+ material.setFloat("Luminance3", luminance3);
+ material.setFloat("Luminance4", luminance4);
+ material.setFloat("Luminance5", luminance5);
+
+ material.setFloat("LineThickness", lineThickness);
+ material.setFloat("LineDistance", lineDistance);
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ /**
+ * Sets color used to draw lines
+ * @param lineColor
+ */
+ public void setLineColor(ColorRGBA lineColor) {
+ this.lineColor = lineColor;
+ if (material != null) {
+ material.setColor("LineColor", lineColor);
+ }
+ }
+
+ /**
+ * Sets color used as background
+ * @param paperColor
+ */
+ public void setPaperColor(ColorRGBA paperColor) {
+ this.paperColor = paperColor;
+ if (material != null) {
+ material.setColor("PaperColor", paperColor);
+ }
+ }
+
+ /**
+ * Sets color influence of original image on lines drawn
+ * @param colorInfluenceLine
+ */
+ public void setColorInfluenceLine(float colorInfluenceLine) {
+ this.colorInfluenceLine = colorInfluenceLine;
+ if (material != null) {
+ material.setFloat("ColorInfluenceLine", colorInfluenceLine);
+ }
+ }
+
+ /**
+ * Sets color influence of original image on non-line areas
+ * @param colorInfluencePaper
+ */
+ public void setColorInfluencePaper(float colorInfluencePaper) {
+ this.colorInfluencePaper = colorInfluencePaper;
+ if (material != null) {
+ material.setFloat("ColorInfluencePaper", colorInfluencePaper);
+ }
+ }
+
+ /**
+ * Sets line/paper color ratio for areas with values < luminance5,
+ * really dark areas get no lines but a filled blob instead
+ * @param fillValue
+ */
+ public void setFillValue(float fillValue) {
+ this.fillValue = fillValue;
+ if (material != null) {
+ material.setFloat("FillValue", fillValue);
+ }
+ }
+
+ /**
+ *
+ * Sets minimum luminance levels for lines drawn
+ * @param luminance1 Top-left to down right 1
+ * @param luminance2 Top-right to bottom left 1
+ * @param luminance3 Top-left to down right 2
+ * @param luminance4 Top-right to bottom left 2
+ * @param luminance5 Blobs
+ */
+ public void setLuminanceLevels(float luminance1, float luminance2, float luminance3, float luminance4, float luminance5) {
+ this.luminance1 = luminance1;
+ this.luminance2 = luminance2;
+ this.luminance3 = luminance3;
+ this.luminance4 = luminance4;
+ this.luminance5 = luminance5;
+
+ if (material != null) {
+ material.setFloat("Luminance1", luminance1);
+ material.setFloat("Luminance2", luminance2);
+ material.setFloat("Luminance3", luminance3);
+ material.setFloat("Luminance4", luminance4);
+ material.setFloat("Luminance5", luminance5);
+ }
+ }
+
+ /**
+ * Sets the thickness of lines drawn
+ * @param lineThickness
+ */
+ public void setLineThickness(float lineThickness) {
+ this.lineThickness = lineThickness;
+ if (material != null) {
+ material.setFloat("LineThickness", lineThickness);
+ }
+ }
+
+ /**
+ * Sets minimum distance between lines drawn
+ * Primary lines are drawn at 2*lineDistance
+ * Secondary lines are drawn at lineDistance
+ * @param lineDistance
+ */
+ public void setLineDistance(float lineDistance) {
+ this.lineDistance = lineDistance;
+ if (material != null) {
+ material.setFloat("LineDistance", lineDistance);
+ }
+ }
+
+ /**
+ * Returns line color
+ * @return
+ */
+ public ColorRGBA getLineColor() {
+ return lineColor;
+ }
+
+ /**
+ * Returns paper background color
+ * @return
+ */
+ public ColorRGBA getPaperColor() {
+ return paperColor;
+ }
+
+ /**
+ * Returns current influence of image colors on lines
+ */
+ public float getColorInfluenceLine() {
+ return colorInfluenceLine;
+ }
+
+ /**
+ * Returns current influence of image colors on paper background
+ */
+ public float getColorInfluencePaper() {
+ return colorInfluencePaper;
+ }
+
+ /**
+ * Returns line/paper color ratio for blobs
+ */
+ public float getFillValue() {
+ return fillValue;
+ }
+
+ /**
+ * Returns the thickness of the lines drawn
+ */
+ public float getLineThickness() {
+ return lineThickness;
+ }
+
+ /**
+ * Returns minimum distance between lines
+ */
+ public float getLineDistance() {
+ return lineDistance;
+ }
+
+ /**
+ * Returns treshold for lines 1
+ */
+ public float getLuminance1() {
+ return luminance1;
+ }
+
+ /**
+ * Returns treshold for lines 2
+ */
+ public float getLuminance2() {
+ return luminance2;
+ }
+
+ /**
+ * Returns treshold for lines 3
+ */
+ public float getLuminance3() {
+ return luminance3;
+ }
+
+ /**
+ * Returns treshold for lines 4
+ */
+ public float getLuminance4() {
+ return luminance4;
+ }
+
+ /**
+ * Returns treshold for blobs
+ */
+ public float getLuminance5() {
+ return luminance5;
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java b/engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java
new file mode 100644
index 0000000..55591c9
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * A post-processing filter that performs a depth range
+ * blur using a scaled convolution filter.
+ *
+ * @version $Revision: 779 $
+ * @author Paul Speed
+ */
+public class DepthOfFieldFilter extends Filter {
+
+ private float focusDistance = 50f;
+ private float focusRange = 10f;
+ private float blurScale = 1f;
+ // These values are set internally based on the
+ // viewport size.
+ private float xScale;
+ private float yScale;
+
+ /**
+ * Creates a DepthOfField filter
+ */
+ public DepthOfFieldFilter() {
+ super("Depth Of Field");
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected Material getMaterial() {
+
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager assets, RenderManager renderManager,
+ ViewPort vp, int w, int h) {
+ material = new Material(assets, "Common/MatDefs/Post/DepthOfField.j3md");
+ material.setFloat("FocusDistance", focusDistance);
+ material.setFloat("FocusRange", focusRange);
+
+
+ xScale = 1.0f / w;
+ yScale = 1.0f / h;
+
+ material.setFloat("XScale", blurScale * xScale);
+ material.setFloat("YScale", blurScale * yScale);
+ }
+
+ /**
+ * Sets the distance at which objects are purely in focus.
+ */
+ public void setFocusDistance(float f) {
+
+ this.focusDistance = f;
+ if (material != null) {
+ material.setFloat("FocusDistance", focusDistance);
+ }
+
+ }
+
+ /**
+ * returns the focus distance
+ * @return
+ */
+ public float getFocusDistance() {
+ return focusDistance;
+ }
+
+ /**
+ * Sets the range to either side of focusDistance where the
+ * objects go gradually out of focus. Less than focusDistance - focusRange
+ * and greater than focusDistance + focusRange, objects are maximally "blurred".
+ */
+ public void setFocusRange(float f) {
+ this.focusRange = f;
+ if (material != null) {
+ material.setFloat("FocusRange", focusRange);
+ }
+
+ }
+
+ /**
+ * returns the focus range
+ * @return
+ */
+ public float getFocusRange() {
+ return focusRange;
+ }
+
+ /**
+ * Sets the blur amount by scaling the convolution filter up or
+ * down. A value of 1 (the default) performs a sparse 5x5 evenly
+ * distribubted convolution at pixel level accuracy. Higher values skip
+ * more pixels, and so on until you are no longer blurring the image
+ * but simply hashing it.
+ *
+ * The sparse convolution is as follows:
+ *%MINIFYHTMLc3d0cd9fab65de6875a381fd3f83e1b338%*
+ * Where 'x' is the texel being modified. Setting blur scale higher
+ * than 1 spaces the samples out.
+ */
+ public void setBlurScale(float f) {
+ this.blurScale = f;
+ if (material != null) {
+ material.setFloat("XScale", blurScale * xScale);
+ material.setFloat("YScale", blurScale * yScale);
+ }
+ }
+
+ /**
+ * returns the blur scale
+ * @return
+ */
+ public float getBlurScale() {
+ return blurScale;
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java b/engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java
new file mode 100644
index 0000000..8ba3c16
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java
@@ -0,0 +1,95 @@
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * <a href="http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-opengl-test-radeon-geforce/3/" rel="nofollow">http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-<span class="domtooltips" title="OpenGL (Open Graphics Library) is a standard specification defining a cross-language, cross-platform API for writing applications that produce 2D and 3D computer graphics." id="domtooltipsspan11">opengl</span>-test-radeon-geforce/3/</a>
+ * <a href="http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf" rel="nofollow">http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf</a>
+ *
+ * @author Phate666 (adapted to jme3)
+ *
+ */
+public class FXAAFilter extends Filter {
+
+ private float subPixelShift = 1.0f / 4.0f;
+ private float vxOffset = 0.0f;
+ private float spanMax = 8.0f;
+ private float reduceMul = 1.0f / 8.0f;
+
+ public FXAAFilter() {
+ super("FXAAFilter");
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager,
+ RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/FXAA.j3md");
+ material.setFloat("SubPixelShift", subPixelShift);
+ material.setFloat("VxOffset", vxOffset);
+ material.setFloat("SpanMax", spanMax);
+ material.setFloat("ReduceMul", reduceMul);
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ public void setSpanMax(float spanMax) {
+ this.spanMax = spanMax;
+ if (material != null) {
+ material.setFloat("SpanMax", this.spanMax);
+ }
+ }
+
+ /**
+ * set to 0.0f for higher quality
+ *
+ * @param subPixelShift
+ */
+ public void setSubPixelShift(float subPixelShift) {
+ this.subPixelShift = subPixelShift;
+ if (material != null) {
+ material.setFloat("SubPixelShif", this.subPixelShift);
+ }
+ }
+
+ /**
+ * set to 0.0f for higher quality
+ *
+ * @param reduceMul
+ */
+ public void setReduceMul(float reduceMul) {
+ this.reduceMul = reduceMul;
+ if (material != null) {
+ material.setFloat("ReduceMul", this.reduceMul);
+ }
+ }
+
+ public void setVxOffset(float vxOffset) {
+ this.vxOffset = vxOffset;
+ if (material != null) {
+ material.setFloat("VxOffset", this.vxOffset);
+ }
+ }
+
+ public float getReduceMul() {
+ return reduceMul;
+ }
+
+ public float getSpanMax() {
+ return spanMax;
+ }
+
+ public float getSubPixelShift() {
+ return subPixelShift;
+ }
+
+ public float getVxOffset() {
+ return vxOffset;
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/com/jme3/post/filters/FadeFilter.java b/engine/src/core-effects/com/jme3/post/filters/FadeFilter.java
new file mode 100644
index 0000000..1fb2340
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/FadeFilter.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+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.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/**
+ *
+ * Fade Filter allows you to make an animated fade effect on a scene.
+ * @author Rémy Bouquet aka Nehon
+ * implemented from boxjar implementation
+ * @see <a href="http://jmonkeyengine.org/groups/graphics/forum/topic/newbie-question-general-fade-inout-effect/#post-105559">http://jmonkeyengine.org/groups/graphics/forum/topic/newbie-question-general-fade-inout-effect/#post-105559</a>
+ */
+public class FadeFilter extends Filter {
+
+ private float value = 1;
+ private boolean playing = false;
+ private float direction = 1;
+ private float duration = 1;
+
+ /**
+ * Creates a FadeFilter
+ */
+ public FadeFilter() {
+ super("Fade In/Out");
+ }
+
+ /**
+ * Creates a FadeFilter with the given duration
+ * @param duration
+ */
+ public FadeFilter(float duration) {
+ this();
+ this.duration = duration;
+ }
+
+ @Override
+ protected Material getMaterial() {
+ material.setFloat("Value", value);
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/Fade.j3md");
+ }
+
+ @Override
+ protected void preFrame(float tpf) {
+ if (playing) {
+ value += tpf * direction / duration;
+
+ if (direction > 0 && value > 1) {
+ value = 1;
+ playing = false;
+ setEnabled(false);
+ }
+ if (direction < 0 && value < 0) {
+ value = 0;
+ playing = false;
+ setEnabled(false);
+ }
+ }
+ }
+
+ /**
+ * returns the duration of the effect
+ * @return
+ */
+ public float getDuration() {
+ return duration;
+ }
+
+ /**
+ * Sets the duration of the filter default is 1 second
+ * @param duration
+ */
+ public void setDuration(float duration) {
+ this.duration = duration;
+ }
+
+ /**
+ * fades the scene in (black to scene)
+ */
+ public void fadeIn() {
+ setEnabled(true);
+ direction = 1;
+ playing = true;
+ }
+
+ /**
+ * fades the scene out (scene to black)
+ */
+ public void fadeOut() {
+ setEnabled(true);
+ direction = -1;
+ playing = true;
+
+ }
+
+ public void pause() {
+ playing = false;
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(duration, "duration", 1);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ duration = ic.readFloat("duration", 1);
+ }
+
+ /**
+ * return the current value of the fading
+ * can be used to chack if fade is complete (eg value=1)
+ * @return
+ */
+ public float getValue() {
+ return value;
+ }
+
+ /**
+ * sets the fade value
+ * can be used to force complete black or compete scene
+ * @param value
+ */
+ public void setValue(float value) {
+ this.value = value;
+ if (material != null) {
+ material.setFloat("Value", value);
+ }
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/FogFilter.java b/engine/src/core-effects/com/jme3/post/filters/FogFilter.java
new file mode 100644
index 0000000..c1df3b7
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/FogFilter.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+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 a fog effect
+ * @author Rémy Bouquet aka Nehon
+ */
+public class FogFilter extends Filter {
+
+ private ColorRGBA fogColor = ColorRGBA.White.clone();
+ private float fogDensity = 0.7f;
+ private float fogDistance = 1000;
+
+ /**
+ * Creates a FogFilter
+ */
+ public FogFilter() {
+ super("FogFilter");
+ }
+
+ /**
+ * Create a fog filter
+ * @param fogColor the color of the fog (default is white)
+ * @param fogDensity the density of the fog (default is 0.7)
+ * @param fogDistance the distance of the fog (default is 1000)
+ */
+ public FogFilter(ColorRGBA fogColor, float fogDensity, float fogDistance) {
+ this();
+ this.fogColor = fogColor;
+ this.fogDensity = fogDensity;
+ this.fogDistance = fogDistance;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/Fog.j3md");
+ material.setColor("FogColor", fogColor);
+ material.setFloat("FogDensity", fogDensity);
+ material.setFloat("FogDistance", fogDistance);
+ }
+
+ @Override
+ protected Material getMaterial() {
+
+ return material;
+ }
+
+
+ /**
+ * returns the fog color
+ * @return
+ */
+ 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 distance
+ * @return
+ */
+ public float getFogDistance() {
+ return fogDistance;
+ }
+
+ /**
+ * the distance of the fog. the higer the value the distant the fog looks
+ * @param fogDistance
+ */
+ public void setFogDistance(float fogDistance) {
+ if (material != null) {
+ material.setFloat("FogDistance", fogDistance);
+ }
+ this.fogDistance = fogDistance;
+ }
+
+ @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(fogDistance, "fogDistance", 1000);
+ }
+
+ @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);
+ fogDistance = ic.readFloat("fogDistance", 1000);
+ }
+
+
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java b/engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java
new file mode 100644
index 0000000..9e283ca
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java
@@ -0,0 +1,78 @@
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ *
+ * @author Phate666
+ * @version 1.0 initial version
+ * @version 1.1 added luma
+ */
+public class GammaCorrectionFilter extends Filter
+{
+ private float gamma = 2.0f;
+ private boolean computeLuma = false;
+
+ public GammaCorrectionFilter()
+ {
+ super("GammaCorrectionFilter");
+ }
+
+ public GammaCorrectionFilter(float gamma)
+ {
+ this();
+ this.setGamma(gamma);
+ }
+
+ @Override
+ protected Material getMaterial()
+ {
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager,
+ RenderManager renderManager, ViewPort vp, int w, int h)
+ {
+ material = new Material(manager,
+ "Common/MatDefs/Post/GammaCorrection.j3md");
+ material.setFloat("gamma", gamma);
+ material.setBoolean("computeLuma", computeLuma);
+ }
+
+ public float getGamma()
+ {
+ return gamma;
+ }
+
+ /**
+ * set to 0.0 to disable gamma correction
+ * @param gamma
+ */
+ public void setGamma(float gamma)
+ {
+ if (material != null)
+ {
+ material.setFloat("gamma", gamma);
+ }
+ this.gamma = gamma;
+ }
+
+ public boolean isComputeLuma()
+ {
+ return computeLuma;
+ }
+
+ public void setComputeLuma(boolean computeLuma)
+ {
+ if (material != null)
+ {
+ material.setBoolean("computeLuma", computeLuma);
+ }
+ this.computeLuma = computeLuma;
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java b/engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java
new file mode 100644
index 0000000..953f10a
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+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.Vector3f;
+import com.jme3.post.Filter;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/**
+ * LightScattering filters creates rays comming from a light sources
+ * This is often reffered as god rays.
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class LightScatteringFilter extends Filter {
+
+ private Vector3f lightPosition;
+ private Vector3f screenLightPos = new Vector3f();
+ private int nbSamples = 50;
+ private float blurStart = 0.02f;
+ private float blurWidth = 0.9f;
+ private float lightDensity = 1.4f;
+ private boolean adaptative = true;
+ Vector3f viewLightPos = new Vector3f();
+ private boolean display = true;
+ private float innerLightDensity;
+
+ /**
+ * creates a lightScaterring filter
+ */
+ public LightScatteringFilter() {
+ super("Light Scattering");
+ }
+
+ /**
+ * Creates a lightScatteringFilter
+ * @param lightPosition
+ */
+ public LightScatteringFilter(Vector3f lightPosition) {
+ this();
+ this.lightPosition = lightPosition;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected Material getMaterial() {
+ material.setVector3("LightPosition", screenLightPos);
+ material.setInt("NbSamples", nbSamples);
+ material.setFloat("BlurStart", blurStart);
+ material.setFloat("BlurWidth", blurWidth);
+ material.setFloat("LightDensity", innerLightDensity);
+ material.setBoolean("Display", display);
+ return material;
+ }
+
+ @Override
+ protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+ getClipCoordinates(lightPosition, screenLightPos, viewPort.getCamera());
+ // screenLightPos.x = screenLightPos.x / viewPort.getCamera().getWidth();
+ // screenLightPos.y = screenLightPos.y / viewPort.getCamera().getHeight();
+
+ viewPort.getCamera().getViewMatrix().mult(lightPosition, viewLightPos);
+ //System.err.println("viewLightPos "+viewLightPos);
+ display = screenLightPos.x < 1.6f && screenLightPos.x > -0.6f && screenLightPos.y < 1.6f && screenLightPos.y > -0.6f && viewLightPos.z < 0;
+//System.err.println("camdir "+viewPort.getCamera().getDirection());
+//System.err.println("lightPos "+lightPosition);
+//System.err.println("screenLightPos "+screenLightPos);
+ if (adaptative) {
+ innerLightDensity = Math.max(lightDensity - Math.max(screenLightPos.x, screenLightPos.y), 0.0f);
+ } else {
+ innerLightDensity = lightDensity;
+ }
+ }
+
+ private Vector3f getClipCoordinates(Vector3f worldPosition, Vector3f store, Camera cam) {
+
+ float w = cam.getViewProjectionMatrix().multProj(worldPosition, store);
+ store.divideLocal(w);
+
+ store.x = ((store.x + 1f) * (cam.getViewPortRight() - cam.getViewPortLeft()) / 2f + cam.getViewPortLeft());
+ store.y = ((store.y + 1f) * (cam.getViewPortTop() - cam.getViewPortBottom()) / 2f + cam.getViewPortBottom());
+ store.z = (store.z + 1f) / 2f;
+
+ return store;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/LightScattering.j3md");
+ }
+
+ /**
+ * returns the blur start of the scattering
+ * see {@link setBlurStart(float blurStart)}
+ * @return
+ */
+ public float getBlurStart() {
+ return blurStart;
+ }
+
+ /**
+ * sets the blur start<br>
+ * at which distance from the light source the effect starts default is 0.02
+ * @param blurStart
+ */
+ public void setBlurStart(float blurStart) {
+ this.blurStart = blurStart;
+ }
+
+ /**
+ * returns the blur width<br>
+ * see {@link setBlurWidth(float blurWidth)}
+ * @return
+ */
+ public float getBlurWidth() {
+ return blurWidth;
+ }
+
+ /**
+ * sets the blur width default is 0.9
+ * @param blurWidth
+ */
+ public void setBlurWidth(float blurWidth) {
+ this.blurWidth = blurWidth;
+ }
+
+ /**
+ * retiurns the light density<br>
+ * see {@link setLightDensity(float lightDensity)}
+ *
+ * @return
+ */
+ public float getLightDensity() {
+ return lightDensity;
+ }
+
+ /**
+ * sets how much the effect is visible over the rendered scene default is 1.4
+ * @param lightDensity
+ */
+ public void setLightDensity(float lightDensity) {
+ this.lightDensity = lightDensity;
+ }
+
+ /**
+ * returns the light position
+ * @return
+ */
+ public Vector3f getLightPosition() {
+ return lightPosition;
+ }
+
+ /**
+ * sets the light position
+ * @param lightPosition
+ */
+ public void setLightPosition(Vector3f lightPosition) {
+ this.lightPosition = lightPosition;
+ }
+
+ /**
+ * returns the nmber of samples for the radial blur
+ * @return
+ */
+ public int getNbSamples() {
+ return nbSamples;
+ }
+
+ /**
+ * sets the number of samples for the radial blur default is 50
+ * the higher the value the higher the quality, but the slower the performances.
+ * @param nbSamples
+ */
+ public void setNbSamples(int nbSamples) {
+ this.nbSamples = nbSamples;
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(lightPosition, "lightPosition", Vector3f.ZERO);
+ oc.write(nbSamples, "nbSamples", 50);
+ oc.write(blurStart, "blurStart", 0.02f);
+ oc.write(blurWidth, "blurWidth", 0.9f);
+ oc.write(lightDensity, "lightDensity", 1.4f);
+ oc.write(adaptative, "adaptative", true);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ lightPosition = (Vector3f) ic.readSavable("lightPosition", Vector3f.ZERO);
+ nbSamples = ic.readInt("nbSamples", 50);
+ blurStart = ic.readFloat("blurStart", 0.02f);
+ blurWidth = ic.readFloat("blurWidth", 0.9f);
+ lightDensity = ic.readFloat("lightDensity", 1.4f);
+ adaptative = ic.readBoolean("adaptative", true);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java b/engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java
new file mode 100644
index 0000000..c980eda
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * A Post Processing filter to change colors appear with sharp edges as if the
+ * available amount of colors available was not enough to draw the true image.
+ * Possibly useful in cartoon styled games. Use the strength variable to lessen
+ * influence of this filter on the total result. Values from 0.2 to 0.7 appear
+ * to give nice results.
+ *
+ * Based on an article from Geeks3D:
+ * <a href="http://www.geeks3d.com/20091027/shader-library-posterization-post-processing-effect-glsl/" rel="nofollow">http://www.geeks3d.com/20091027/shader-library-posterization-post-processing-effect-glsl/</a>
+ *
+ * @author: Roy Straver a.k.a. Baal Garnaal
+ */
+public class PosterizationFilter extends Filter {
+
+ private int numColors = 8;
+ private float gamma = 0.6f;
+ private float strength = 1.0f;
+
+ /**
+ * Creates a posterization Filter
+ */
+ public PosterizationFilter() {
+ super("PosterizationFilter");
+ }
+
+ /**
+ * Creates a posterization Filter with the given number of colors
+ * @param numColors
+ */
+ public PosterizationFilter(int numColors) {
+ this();
+ this.numColors = numColors;
+ }
+
+ /**
+ * Creates a posterization Filter with the given number of colors and gamma
+ * @param numColors
+ * @param gamma
+ */
+ public PosterizationFilter(int numColors, float gamma) {
+ this(numColors);
+ this.gamma = gamma;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/Posterization.j3md");
+ material.setInt("NumColors", numColors);
+ material.setFloat("Gamma", gamma);
+ material.setFloat("Strength", strength);
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ /**
+ * Sets number of color levels used to draw the screen
+ */
+ public void setNumColors(int numColors) {
+ this.numColors = numColors;
+ if (material != null) {
+ material.setInt("NumColors", numColors);
+ }
+ }
+
+ /**
+ * Sets gamma level used to enhange visual quality
+ */
+ public void setGamma(float gamma) {
+ this.gamma = gamma;
+ if (material != null) {
+ material.setFloat("Gamma", gamma);
+ }
+ }
+
+ /**
+ * Sets urrent strength value, i.e. influence on final image
+ */
+ public void setStrength(float strength) {
+ this.strength = strength;
+ if (material != null) {
+ material.setFloat("Strength", strength);
+ }
+ }
+
+ /**
+ * Returns number of color levels used
+ */
+ public int getNumColors() {
+ return numColors;
+ }
+
+ /**
+ * Returns current gamma value
+ */
+ public float getGamma() {
+ return gamma;
+ }
+
+ /**
+ * Returns current strength value, i.e. influence on final image
+ */
+ public float getStrength() {
+ return strength;
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java b/engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java
new file mode 100644
index 0000000..0bcae5f
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+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.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.shader.VarType;
+import java.io.IOException;
+
+/**
+ * Radially blurs the scene from the center of it
+ * @author Rémy Bouquet aka Nehon
+ */
+public class RadialBlurFilter extends Filter {
+
+ private float sampleDist = 1.0f;
+ private float sampleStrength = 2.2f;
+ private float[] samples = {-0.08f, -0.05f, -0.03f, -0.02f, -0.01f, 0.01f, 0.02f, 0.03f, 0.05f, 0.08f};
+
+ /**
+ * Creates a RadialBlurFilter
+ */
+ public RadialBlurFilter() {
+ super("Radial blur");
+ }
+
+ /**
+ * Creates a RadialBlurFilter
+ * @param sampleDist the distance between samples
+ * @param sampleStrength the strenght of each sample
+ */
+ public RadialBlurFilter(float sampleDist, float sampleStrength) {
+ this();
+ this.sampleDist = sampleDist;
+ this.sampleStrength = sampleStrength;
+ }
+
+ @Override
+ protected Material getMaterial() {
+
+ material.setFloat("SampleDist", sampleDist);
+ material.setFloat("SampleStrength", sampleStrength);
+ material.setParam("Samples", VarType.FloatArray, samples);
+
+ return material;
+ }
+
+ /**
+ * return the sample distance
+ * @return
+ */
+ public float getSampleDistance() {
+ return sampleDist;
+ }
+
+ /**
+ * sets the samples distances default is 1
+ * @param sampleDist
+ */
+ public void setSampleDistance(float sampleDist) {
+ this.sampleDist = sampleDist;
+ }
+
+ /**
+ *
+ * @return
+ * @deprecated use {@link #getSampleDistance()}
+ */
+ @Deprecated
+ public float getSampleDist() {
+ return sampleDist;
+ }
+
+ /**
+ *
+ * @param sampleDist
+ * @deprecated use {@link #setSampleDistance(float sampleDist)}
+ */
+ @Deprecated
+ public void setSampleDist(float sampleDist) {
+ this.sampleDist = sampleDist;
+ }
+
+ /**
+ * Returns the sample Strength
+ * @return
+ */
+ public float getSampleStrength() {
+ return sampleStrength;
+ }
+
+ /**
+ * sets the sample streanght default is 2.2
+ * @param sampleStrength
+ */
+ public void setSampleStrength(float sampleStrength) {
+ this.sampleStrength = sampleStrength;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Blur/RadialBlur.j3md");
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(sampleDist, "sampleDist", 1.0f);
+ oc.write(sampleStrength, "sampleStrength", 2.2f);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ sampleDist = ic.readFloat("sampleDist", 1.0f);
+ sampleStrength = ic.readFloat("sampleStrength", 2.2f);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java b/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java
new file mode 100644
index 0000000..47be413
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java
@@ -0,0 +1,80 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Texture2D;
+
+/**
+ * A filter to handle translucent objects when rendering a scene with filters that uses depth like WaterFilter and SSAOFilter
+ * just create a TranslucentBucketFilter and add it to the Filter list of a FilterPostPorcessor
+ * @author Nehon
+ */
+public final class TranslucentBucketFilter extends Filter {
+
+ private RenderManager renderManager;
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager rm, ViewPort vp, int w, int h) {
+ this.renderManager = rm;
+ material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
+ material.setColor("Color", ColorRGBA.White);
+ Texture2D tex = processor.getFilterTexture();
+ material.setTexture("Texture", tex);
+ if (tex.getImage().getMultiSamples() > 1) {
+ material.setInt("NumSamples", tex.getImage().getMultiSamples());
+ } else {
+ material.clearParam("NumSamples");
+ }
+ renderManager.setHandleTranslucentBucket(false);
+ }
+
+ /**
+ * Override this method and return false if your Filter does not need the scene texture
+ * @return
+ */
+ @Override
+ protected boolean isRequiresSceneTexture() {
+ return false;
+ }
+
+ @Override
+ protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
+ renderManager.setCamera(viewPort.getCamera(), false);
+ if (prevFilterBuffer != sceneBuffer) {
+ renderManager.getRenderer().copyFrameBuffer(prevFilterBuffer, sceneBuffer, false);
+ }
+ renderManager.getRenderer().setFrameBuffer(sceneBuffer);
+ viewPort.getQueue().renderQueue(RenderQueue.Bucket.Translucent, renderManager, viewPort.getCamera());
+ }
+
+ @Override
+ protected void cleanUpFilter(Renderer r) {
+ if (renderManager != null) {
+ renderManager.setHandleTranslucentBucket(true);
+ }
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ if (renderManager != null) {
+ renderManager.setHandleTranslucentBucket(!enabled);
+ }
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java b/engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java
new file mode 100644
index 0000000..cb0c037
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.ssao;
+
+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.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.post.Filter;
+import com.jme3.post.Filter.Pass;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.shader.VarType;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * SSAO stands for screen space ambient occlusion
+ * It's a technique that fake ambient lighting by computing shadows that near by objects would casts on each others
+ * under the effect of an ambient light
+ * more info on this in this blog post <a href="http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/">http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/</a>
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class SSAOFilter extends Filter {
+
+ private Pass normalPass;
+ private Vector3f frustumCorner;
+ private Vector2f frustumNearFar;
+ private Vector2f[] samples = {new Vector2f(1.0f, 0.0f), new Vector2f(-1.0f, 0.0f), new Vector2f(0.0f, 1.0f), new Vector2f(0.0f, -1.0f)};
+ private float sampleRadius = 5.1f;
+ private float intensity = 1.5f;
+ private float scale = 0.2f;
+ private float bias = 0.1f;
+ private boolean useOnlyAo = false;
+ private boolean useAo = true;
+ private Material ssaoMat;
+ private Pass ssaoPass;
+// private Material downSampleMat;
+// private Pass downSamplePass;
+ private float downSampleFactor = 1f;
+
+ /**
+ * Create a Screen Space Ambient Occlusion Filter
+ */
+ public SSAOFilter() {
+ super("SSAOFilter");
+ }
+
+ /**
+ * Create a Screen Space Ambient Occlusion Filter
+ * @param sampleRadius The radius of the area where random samples will be picked. default 5.1f
+ * @param intensity intensity of the resulting AO. default 1.2f
+ * @param scale distance between occluders and occludee. default 0.2f
+ * @param bias the width of the occlusion cone considered by the occludee. default 0.1f
+ */
+ public SSAOFilter(float sampleRadius, float intensity, float scale, float bias) {
+ this();
+ this.sampleRadius = sampleRadius;
+ this.intensity = intensity;
+ this.scale = scale;
+ this.bias = bias;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+ Renderer r = renderManager.getRenderer();
+ r.setFrameBuffer(normalPass.getRenderFrameBuffer());
+ renderManager.getRenderer().clearBuffers(true, true, true);
+ renderManager.setForcedTechnique("PreNormalPass");
+ renderManager.renderViewPortQueues(viewPort, false);
+ renderManager.setForcedTechnique(null);
+ renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ int screenWidth = w;
+ int screenHeight = h;
+ postRenderPasses = new ArrayList<Pass>();
+
+ normalPass = new Pass();
+ normalPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth);
+
+
+ frustumNearFar = new Vector2f();
+
+ float farY = (vp.getCamera().getFrustumTop() / vp.getCamera().getFrustumNear()) * vp.getCamera().getFrustumFar();
+ float farX = farY * ((float) screenWidth / (float) screenHeight);
+ frustumCorner = new Vector3f(farX, farY, vp.getCamera().getFrustumFar());
+ frustumNearFar.x = vp.getCamera().getFrustumNear();
+ frustumNearFar.y = vp.getCamera().getFrustumFar();
+
+
+
+
+
+ //ssao Pass
+ ssaoMat = new Material(manager, "Common/MatDefs/SSAO/ssao.j3md");
+ ssaoMat.setTexture("Normals", normalPass.getRenderedTexture());
+ Texture random = manager.loadTexture("Common/MatDefs/SSAO/Textures/random.png");
+ random.setWrap(Texture.WrapMode.Repeat);
+ ssaoMat.setTexture("RandomMap", random);
+
+ ssaoPass = new Pass() {
+
+ @Override
+ public boolean requiresDepthAsTexture() {
+ return true;
+ }
+ };
+
+ ssaoPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth, 1, ssaoMat);
+ ssaoPass.getRenderedTexture().setMinFilter(Texture.MinFilter.Trilinear);
+ ssaoPass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear);
+ postRenderPasses.add(ssaoPass);
+ material = new Material(manager, "Common/MatDefs/SSAO/ssaoBlur.j3md");
+ material.setTexture("SSAOMap", ssaoPass.getRenderedTexture());
+
+ ssaoMat.setVector3("FrustumCorner", frustumCorner);
+ ssaoMat.setFloat("SampleRadius", sampleRadius);
+ ssaoMat.setFloat("Intensity", intensity);
+ ssaoMat.setFloat("Scale", scale);
+ ssaoMat.setFloat("Bias", bias);
+ material.setBoolean("UseAo", useAo);
+ material.setBoolean("UseOnlyAo", useOnlyAo);
+ ssaoMat.setVector2("FrustumNearFar", frustumNearFar);
+ material.setVector2("FrustumNearFar", frustumNearFar);
+ ssaoMat.setParam("Samples", VarType.Vector2Array, samples);
+
+ float xScale = 1.0f / w;
+ float yScale = 1.0f / h;
+
+ float blurScale = 2f;
+ material.setFloat("XScale", blurScale * xScale);
+ material.setFloat("YScale", blurScale * yScale);
+
+ }
+
+ /**
+ * Return the bias<br>
+ * see {@link #setBias(float bias)}
+ * @return
+ */
+ public float getBias() {
+ return bias;
+ }
+
+ /**
+ * Sets the the width of the occlusion cone considered by the occludee default is 0.1f
+ * @param bias
+ */
+ public void setBias(float bias) {
+ this.bias = bias;
+ if (ssaoMat != null) {
+ ssaoMat.setFloat("Bias", bias);
+ }
+ }
+
+ /**
+ * returns the ambient occlusion intensity
+ * @return
+ */
+ public float getIntensity() {
+ return intensity;
+ }
+
+ /**
+ * Sets the Ambient occlusion intensity default is 1.2f
+ * @param intensity
+ */
+ public void setIntensity(float intensity) {
+ this.intensity = intensity;
+ if (ssaoMat != null) {
+ ssaoMat.setFloat("Intensity", intensity);
+ }
+
+ }
+
+ /**
+ * returns the sample radius<br>
+ * see {link setSampleRadius(float sampleRadius)}
+ * @return
+ */
+ public float getSampleRadius() {
+ return sampleRadius;
+ }
+
+ /**
+ * Sets the radius of the area where random samples will be picked dafault 5.1f
+ * @param sampleRadius
+ */
+ public void setSampleRadius(float sampleRadius) {
+ this.sampleRadius = sampleRadius;
+ if (ssaoMat != null) {
+ ssaoMat.setFloat("SampleRadius", sampleRadius);
+ }
+
+ }
+
+ /**
+ * returns the scale<br>
+ * see {@link #setScale(float scale)}
+ * @return
+ */
+ public float getScale() {
+ return scale;
+ }
+
+ /**
+ *
+ * Returns the distance between occluders and occludee. default 0.2f
+ * @param scale
+ */
+ public void setScale(float scale) {
+ this.scale = scale;
+ if (ssaoMat != null) {
+ ssaoMat.setFloat("Scale", scale);
+ }
+ }
+
+ /**
+ * debugging only , will be removed
+ * @return
+ */
+ public boolean isUseAo() {
+ return useAo;
+ }
+
+ /**
+ * debugging only , will be removed
+ */
+ public void setUseAo(boolean useAo) {
+ this.useAo = useAo;
+ if (material != null) {
+ material.setBoolean("UseAo", useAo);
+ }
+
+ }
+
+ /**
+ * debugging only , will be removed
+ * @return
+ */
+ public boolean isUseOnlyAo() {
+ return useOnlyAo;
+ }
+
+ /**
+ * debugging only , will be removed
+ */
+ public void setUseOnlyAo(boolean useOnlyAo) {
+ this.useOnlyAo = useOnlyAo;
+ if (material != null) {
+ material.setBoolean("UseOnlyAo", useOnlyAo);
+ }
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(sampleRadius, "sampleRadius", 5.1f);
+ oc.write(intensity, "intensity", 1.5f);
+ oc.write(scale, "scale", 0.2f);
+ oc.write(bias, "bias", 0.1f);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ sampleRadius = ic.readFloat("sampleRadius", 5.1f);
+ intensity = ic.readFloat("intensity", 1.5f);
+ scale = ic.readFloat("scale", 0.2f);
+ bias = ic.readFloat("bias", 0.1f);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/water/ReflectionProcessor.java b/engine/src/core-effects/com/jme3/water/ReflectionProcessor.java
new file mode 100644
index 0000000..9a14df8
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/water/ReflectionProcessor.java
@@ -0,0 +1,125 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.water;
+
+import com.jme3.math.Plane;
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.texture.FrameBuffer;
+
+/**
+ * Reflection Processor
+ * Used to render the reflected scene in an off view port
+ */
+public class ReflectionProcessor implements SceneProcessor {
+
+ private RenderManager rm;
+ private ViewPort vp;
+ private Camera reflectionCam;
+ private FrameBuffer reflectionBuffer;
+ private Plane reflectionClipPlane;
+
+ /**
+ * Creates a ReflectionProcessor
+ * @param reflectionCam the cam to use for reflection
+ * @param reflectionBuffer the FrameBuffer to render to
+ * @param reflectionClipPlane the clipping plane
+ */
+ public ReflectionProcessor(Camera reflectionCam, FrameBuffer reflectionBuffer, Plane reflectionClipPlane) {
+ this.reflectionCam = reflectionCam;
+ this.reflectionBuffer = reflectionBuffer;
+ this.reflectionClipPlane = reflectionClipPlane;
+ }
+
+ public void initialize(RenderManager rm, ViewPort vp) {
+ this.rm = rm;
+ this.vp = vp;
+ }
+
+ public void reshape(ViewPort vp, int w, int h) {
+ }
+
+ public boolean isInitialized() {
+ return rm != null;
+ }
+
+ public void preFrame(float tpf) {
+ }
+
+ public void postQueue(RenderQueue rq) {
+ //we need special treatement for the sky because it must not be clipped
+ rm.getRenderer().setFrameBuffer(reflectionBuffer);
+ reflectionCam.setProjectionMatrix(null);
+ rm.setCamera(reflectionCam, false);
+ rm.getRenderer().clearBuffers(true, true, true);
+ //Rendering the sky whithout clipping
+ rm.getRenderer().setDepthRange(1, 1);
+ vp.getQueue().renderQueue(RenderQueue.Bucket.Sky, rm, reflectionCam, true);
+ rm.getRenderer().setDepthRange(0, 1);
+ //setting the clip plane to the cam
+ reflectionCam.setClipPlane(reflectionClipPlane, Plane.Side.Positive);//,1
+ rm.setCamera(reflectionCam, false);
+
+ }
+
+ public void postFrame(FrameBuffer out) {
+ }
+
+ public void cleanup() {
+ }
+
+ /**
+ * Internal use only<br>
+ * returns the frame buffer
+ * @return
+ */
+ public FrameBuffer getReflectionBuffer() {
+ return reflectionBuffer;
+ }
+
+ /**
+ * Internal use only<br>
+ * sets the frame buffer
+ * @param reflectionBuffer
+ */
+ public void setReflectionBuffer(FrameBuffer reflectionBuffer) {
+ this.reflectionBuffer = reflectionBuffer;
+ }
+
+ /**
+ * returns the reflection cam
+ * @return
+ */
+ public Camera getReflectionCam() {
+ return reflectionCam;
+ }
+
+ /**
+ * sets the reflection cam
+ * @param reflectionCam
+ */
+ public void setReflectionCam(Camera reflectionCam) {
+ this.reflectionCam = reflectionCam;
+ }
+
+ /**
+ * returns the reflection clip plane
+ * @return
+ */
+ public Plane getReflectionClipPlane() {
+ return reflectionClipPlane;
+ }
+
+ /**
+ * Sets the reflection clip plane
+ * @param reflectionClipPlane
+ */
+ public void setReflectionClipPlane(Plane reflectionClipPlane) {
+ this.reflectionClipPlane = reflectionClipPlane;
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java b/engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java
new file mode 100644
index 0000000..70ccd11
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.water;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Quad;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.texture.Texture2D;
+import com.jme3.ui.Picture;
+
+/**
+ *
+ * Simple Water renders a simple plane that use reflection and refraction to look like water.
+ * It's pretty basic, but much faster than the WaterFilter
+ * It's useful if you aim low specs hardware and still want a good looking water.
+ * Usage is :
+ * <code>
+ * SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(assetManager);
+ * //setting the scene to use for reflection
+ * waterProcessor.setReflectionScene(mainScene);
+ * //setting the light position
+ * waterProcessor.setLightPosition(lightPos);
+ *
+ * //setting the water plane
+ * Vector3f waterLocation=new Vector3f(0,-20,0);
+ * waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y)));
+ * //setting the water color
+ * waterProcessor.setWaterColor(ColorRGBA.Brown);
+ *
+ * //creating a quad to render water to
+ * Quad quad = new Quad(400,400);
+ *
+ * //the texture coordinates define the general size of the waves
+ * quad.scaleTextureCoordinates(new Vector2f(6f,6f));
+ *
+ * //creating a geom to attach the water material
+ * Geometry water=new Geometry("water", quad);
+ * water.setLocalTranslation(-200, -20, 250);
+ * water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ * //finally setting the material
+ * water.setMaterial(waterProcessor.getMaterial());
+ *
+ * //attaching the water to the root node
+ * rootNode.attachChild(water);
+ * </code>
+ * @author Normen Hansen & Rémy Bouquet
+ */
+public class SimpleWaterProcessor implements SceneProcessor {
+
+ protected RenderManager rm;
+ protected ViewPort vp;
+ protected Spatial reflectionScene;
+ protected ViewPort reflectionView;
+ protected ViewPort refractionView;
+ protected FrameBuffer reflectionBuffer;
+ protected FrameBuffer refractionBuffer;
+ protected Camera reflectionCam;
+ protected Camera refractionCam;
+ protected Texture2D reflectionTexture;
+ protected Texture2D refractionTexture;
+ protected Texture2D depthTexture;
+ protected Texture2D normalTexture;
+ protected Texture2D dudvTexture;
+ protected int renderWidth = 512;
+ protected int renderHeight = 512;
+ protected Plane plane = new Plane(Vector3f.UNIT_Y, Vector3f.ZERO.dot(Vector3f.UNIT_Y));
+ protected float speed = 0.05f;
+ protected Ray ray = new Ray();
+ protected Vector3f targetLocation = new Vector3f();
+ protected AssetManager manager;
+ protected Material material;
+ protected float waterDepth = 1;
+ protected float waterTransparency = 0.4f;
+ protected boolean debug = false;
+ private Picture dispRefraction;
+ private Picture dispReflection;
+ private Picture dispDepth;
+ private Plane reflectionClipPlane;
+ private Plane refractionClipPlane;
+ private float refractionClippingOffset = 0.3f;
+ private float reflectionClippingOffset = -5f;
+ private Vector3f vect1 = new Vector3f();
+ private Vector3f vect2 = new Vector3f();
+ private Vector3f vect3 = new Vector3f();
+
+ /**
+ * Creates a SimpleWaterProcessor
+ * @param manager the asset manager
+ */
+ public SimpleWaterProcessor(AssetManager manager) {
+ this.manager = manager;
+ material = new Material(manager, "Common/MatDefs/Water/SimpleWater.j3md");
+ material.setFloat("waterDepth", waterDepth);
+ material.setFloat("waterTransparency", waterTransparency / 10);
+ material.setColor("waterColor", ColorRGBA.White);
+ material.setVector3("lightPos", new Vector3f(1, -1, 1));
+
+ material.setColor("distortionScale", new ColorRGBA(0.2f, 0.2f, 0.2f, 0.2f));
+ material.setColor("distortionMix", new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f));
+ material.setColor("texScale", new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
+ updateClipPlanes();
+
+ }
+
+ public void initialize(RenderManager rm, ViewPort vp) {
+ this.rm = rm;
+ this.vp = vp;
+
+ loadTextures(manager);
+ createTextures();
+ applyTextures(material);
+
+ createPreViews();
+
+ material.setVector2("FrustumNearFar", new Vector2f(vp.getCamera().getFrustumNear(), vp.getCamera().getFrustumFar()));
+
+ if (debug) {
+ dispRefraction = new Picture("dispRefraction");
+ dispRefraction.setTexture(manager, refractionTexture, false);
+ dispReflection = new Picture("dispRefraction");
+ dispReflection.setTexture(manager, reflectionTexture, false);
+ dispDepth = new Picture("depthTexture");
+ dispDepth.setTexture(manager, depthTexture, false);
+ }
+ }
+
+ public void reshape(ViewPort vp, int w, int h) {
+ }
+
+ public boolean isInitialized() {
+ return rm != null;
+ }
+ float time = 0;
+ float savedTpf = 0;
+
+ public void preFrame(float tpf) {
+ time = time + (tpf * speed);
+ if (time > 1f) {
+ time = 0;
+ }
+ material.setFloat("time", time);
+ savedTpf = tpf;
+ }
+
+ public void postQueue(RenderQueue rq) {
+ Camera sceneCam = rm.getCurrentCamera();
+
+ //update ray
+ ray.setOrigin(sceneCam.getLocation());
+ ray.setDirection(sceneCam.getDirection());
+
+ //update refraction cam
+ refractionCam.setLocation(sceneCam.getLocation());
+ refractionCam.setRotation(sceneCam.getRotation());
+ refractionCam.setFrustum(sceneCam.getFrustumNear(),
+ sceneCam.getFrustumFar(),
+ sceneCam.getFrustumLeft(),
+ sceneCam.getFrustumRight(),
+ sceneCam.getFrustumTop(),
+ sceneCam.getFrustumBottom());
+
+ //update reflection cam
+ boolean inv = false;
+ if (!ray.intersectsWherePlane(plane, targetLocation)) {
+ ray.setDirection(ray.getDirection().negateLocal());
+ ray.intersectsWherePlane(plane, targetLocation);
+ inv = true;
+ }
+ Vector3f loc = plane.reflect(sceneCam.getLocation(), new Vector3f());
+ reflectionCam.setLocation(loc);
+ reflectionCam.setFrustum(sceneCam.getFrustumNear(),
+ sceneCam.getFrustumFar(),
+ sceneCam.getFrustumLeft(),
+ sceneCam.getFrustumRight(),
+ sceneCam.getFrustumTop(),
+ sceneCam.getFrustumBottom());
+ // tempVec and calcVect are just temporary vector3f objects
+ vect1.set(sceneCam.getLocation()).addLocal(sceneCam.getUp());
+ float planeDistance = plane.pseudoDistance(vect1);
+ vect2.set(plane.getNormal()).multLocal(planeDistance * 2.0f);
+ vect3.set(vect1.subtractLocal(vect2)).subtractLocal(loc).normalizeLocal().negateLocal();
+ // now set the up vector
+ reflectionCam.lookAt(targetLocation, vect3);
+ if (inv) {
+ reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
+ }
+
+ //Rendering reflection and refraction
+ rm.renderViewPort(reflectionView, savedTpf);
+ rm.renderViewPort(refractionView, savedTpf);
+ rm.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer());
+ rm.setCamera(sceneCam, false);
+
+ }
+
+ public void postFrame(FrameBuffer out) {
+ if (debug) {
+ displayMap(rm.getRenderer(), dispRefraction, 64);
+ displayMap(rm.getRenderer(), dispReflection, 256);
+ displayMap(rm.getRenderer(), dispDepth, 448);
+ }
+ }
+
+ public void cleanup() {
+ }
+
+ //debug only : displays maps
+ protected void displayMap(Renderer r, Picture pic, int left) {
+ Camera cam = vp.getCamera();
+ rm.setCamera(cam, true);
+ int h = cam.getHeight();
+
+ pic.setPosition(left, h / 20f);
+
+ pic.setWidth(128);
+ pic.setHeight(128);
+ pic.updateGeometricState();
+ rm.renderGeometry(pic);
+ rm.setCamera(cam, false);
+ }
+
+ protected void loadTextures(AssetManager manager) {
+ normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
+ dudvTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/dudv_map.jpg");
+ normalTexture.setWrap(WrapMode.Repeat);
+ dudvTexture.setWrap(WrapMode.Repeat);
+ }
+
+ protected void createTextures() {
+ reflectionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
+ refractionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
+ depthTexture = new Texture2D(renderWidth, renderHeight, Format.Depth);
+ }
+
+ protected void applyTextures(Material mat) {
+ mat.setTexture("water_reflection", reflectionTexture);
+ mat.setTexture("water_refraction", refractionTexture);
+ mat.setTexture("water_depthmap", depthTexture);
+ mat.setTexture("water_normalmap", normalTexture);
+ mat.setTexture("water_dudvmap", dudvTexture);
+ }
+
+ protected void createPreViews() {
+ reflectionCam = new Camera(renderWidth, renderHeight);
+ refractionCam = new Camera(renderWidth, renderHeight);
+
+ // create a pre-view. a view that is rendered before the main view
+ reflectionView = new ViewPort("Reflection View", reflectionCam);
+ reflectionView.setClearFlags(true, true, true);
+ reflectionView.setBackgroundColor(ColorRGBA.Black);
+ // create offscreen framebuffer
+ reflectionBuffer = new FrameBuffer(renderWidth, renderHeight, 1);
+ //setup framebuffer to use texture
+ reflectionBuffer.setDepthBuffer(Format.Depth);
+ reflectionBuffer.setColorTexture(reflectionTexture);
+
+ //set viewport to render to offscreen framebuffer
+ reflectionView.setOutputFrameBuffer(reflectionBuffer);
+ reflectionView.addProcessor(new ReflectionProcessor(reflectionCam, reflectionBuffer, reflectionClipPlane));
+ // attach the scene to the viewport to be rendered
+ reflectionView.attachScene(reflectionScene);
+
+ // create a pre-view. a view that is rendered before the main view
+ refractionView = new ViewPort("Refraction View", refractionCam);
+ refractionView.setClearFlags(true, true, true);
+ refractionView.setBackgroundColor(ColorRGBA.Black);
+ // create offscreen framebuffer
+ refractionBuffer = new FrameBuffer(renderWidth, renderHeight, 1);
+ //setup framebuffer to use texture
+ refractionBuffer.setDepthBuffer(Format.Depth);
+ refractionBuffer.setColorTexture(refractionTexture);
+ refractionBuffer.setDepthTexture(depthTexture);
+ //set viewport to render to offscreen framebuffer
+ refractionView.setOutputFrameBuffer(refractionBuffer);
+ refractionView.addProcessor(new RefractionProcessor());
+ // attach the scene to the viewport to be rendered
+ refractionView.attachScene(reflectionScene);
+ }
+
+ protected void destroyViews() {
+ // rm.removePreView(reflectionView);
+ rm.removePreView(refractionView);
+ }
+
+ /**
+ * Get the water material from this processor, apply this to your water quad.
+ * @return
+ */
+ public Material getMaterial() {
+ return material;
+ }
+
+ /**
+ * Sets the reflected scene, should not include the water quad!
+ * Set before adding processor.
+ * @param spat
+ */
+ public void setReflectionScene(Spatial spat) {
+ reflectionScene = spat;
+ }
+
+ /**
+ * returns the width of the reflection and refraction textures
+ * @return
+ */
+ public int getRenderWidth() {
+ return renderWidth;
+ }
+
+ /**
+ * returns the height of the reflection and refraction textures
+ * @return
+ */
+ public int getRenderHeight() {
+ return renderHeight;
+ }
+
+ /**
+ * Set the reflection Texture render size,
+ * set before adding the processor!
+ * @param with
+ * @param height
+ */
+ public void setRenderSize(int width, int height) {
+ renderWidth = width;
+ renderHeight = height;
+ }
+
+ /**
+ * returns the water plane
+ * @return
+ */
+ public Plane getPlane() {
+ return plane;
+ }
+
+ /**
+ * Set the water plane for this processor.
+ * @param plane
+ */
+ public void setPlane(Plane plane) {
+ this.plane.setConstant(plane.getConstant());
+ this.plane.setNormal(plane.getNormal());
+ updateClipPlanes();
+ }
+
+ /**
+ * Set the water plane using an origin (location) and a normal (reflection direction).
+ * @param origin Set to 0,-6,0 if your water quad is at that location for correct reflection
+ * @param normal Set to 0,1,0 (Vector3f.UNIT_Y) for normal planar water
+ */
+ public void setPlane(Vector3f origin, Vector3f normal) {
+ this.plane.setOriginNormal(origin, normal);
+ updateClipPlanes();
+ }
+
+ private void updateClipPlanes() {
+ reflectionClipPlane = plane.clone();
+ reflectionClipPlane.setConstant(reflectionClipPlane.getConstant() + reflectionClippingOffset);
+ refractionClipPlane = plane.clone();
+ refractionClipPlane.setConstant(refractionClipPlane.getConstant() + refractionClippingOffset);
+
+ }
+
+ /**
+ * Set the light Position for the processor
+ * @param position
+ */
+ //TODO maybe we should provide a convenient method to compute position from direction
+ public void setLightPosition(Vector3f position) {
+ material.setVector3("lightPos", position);
+ }
+
+ /**
+ * Set the color that will be added to the refraction texture.
+ * @param color
+ */
+ public void setWaterColor(ColorRGBA color) {
+ material.setColor("waterColor", color);
+ }
+
+ /**
+ * Higher values make the refraction texture shine through earlier.
+ * Default is 4
+ * @param depth
+ */
+ public void setWaterDepth(float depth) {
+ waterDepth = depth;
+ material.setFloat("waterDepth", depth);
+ }
+
+ /**
+ * return the water depth
+ * @return
+ */
+ public float getWaterDepth() {
+ return waterDepth;
+ }
+
+ /**
+ * returns water transparency
+ * @return
+ */
+ public float getWaterTransparency() {
+ return waterTransparency;
+ }
+
+ /**
+ * sets the water transparency default os 0.1f
+ * @param waterTransparency
+ */
+ public void setWaterTransparency(float waterTransparency) {
+ this.waterTransparency = Math.max(0, waterTransparency);
+ material.setFloat("waterTransparency", waterTransparency / 10);
+ }
+
+ /**
+ * Sets the speed of the wave animation, default = 0.05f.
+ * @param speed
+ */
+ public void setWaveSpeed(float speed) {
+ this.speed = speed;
+ }
+
+ /**
+ * Sets the scale of distortion by the normal map, default = 0.2
+ */
+ public void setDistortionScale(float value) {
+ material.setColor("distortionScale", new ColorRGBA(value, value, value, value));
+ }
+
+ /**
+ * Sets how the normal and dudv map are mixed to create the wave effect, default = 0.5
+ */
+ public void setDistortionMix(float value) {
+ material.setColor("distortionMix", new ColorRGBA(value, value, value, value));
+ }
+
+ /**
+ * Sets the scale of the normal/dudv texture, default = 1.
+ * Note that the waves should be scaled by the texture coordinates of the quad to avoid animation artifacts,
+ * use mesh.scaleTextureCoordinates(Vector2f) for that.
+ */
+ public void setTexScale(float value) {
+ material.setColor("texScale", new ColorRGBA(value, value, value, value));
+ }
+
+ /**
+ * retruns true if the waterprocessor is in debug mode
+ * @return
+ */
+ public boolean isDebug() {
+ return debug;
+ }
+
+ /**
+ * set to true to display reflection and refraction textures in the GUI for debug purpose
+ * @param debug
+ */
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ /**
+ * Creates a quad with the water material applied to it.
+ * @param width
+ * @param height
+ * @return
+ */
+ public Geometry createWaterGeometry(float width, float height) {
+ Quad quad = new Quad(width, height);
+ Geometry geom = new Geometry("WaterGeometry", quad);
+ geom.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ geom.setMaterial(material);
+ return geom;
+ }
+
+ /**
+ * returns the reflection clipping plane offset
+ * @return
+ */
+ public float getReflectionClippingOffset() {
+ return reflectionClippingOffset;
+ }
+
+ /**
+ * sets the reflection clipping plane offset
+ * set a nagetive value to lower the clipping plane for relection texture rendering.
+ * @param reflectionClippingOffset
+ */
+ public void setReflectionClippingOffset(float reflectionClippingOffset) {
+ this.reflectionClippingOffset = reflectionClippingOffset;
+ updateClipPlanes();
+ }
+
+ /**
+ * returns the refraction clipping plane offset
+ * @return
+ */
+ public float getRefractionClippingOffset() {
+ return refractionClippingOffset;
+ }
+
+ /**
+ * Sets the refraction clipping plane offset
+ * set a positive value to raise the clipping plane for refraction texture rendering
+ * @param refractionClippingOffset
+ */
+ public void setRefractionClippingOffset(float refractionClippingOffset) {
+ this.refractionClippingOffset = refractionClippingOffset;
+ updateClipPlanes();
+ }
+
+ /**
+ * Refraction Processor
+ */
+ public class RefractionProcessor implements SceneProcessor {
+
+ RenderManager rm;
+ ViewPort vp;
+
+ public void initialize(RenderManager rm, ViewPort vp) {
+ this.rm = rm;
+ this.vp = vp;
+ }
+
+ public void reshape(ViewPort vp, int w, int h) {
+ }
+
+ public boolean isInitialized() {
+ return rm != null;
+ }
+
+ public void preFrame(float tpf) {
+ refractionCam.setClipPlane(refractionClipPlane, Plane.Side.Negative);//,-1
+
+ }
+
+ public void postQueue(RenderQueue rq) {
+ }
+
+ public void postFrame(FrameBuffer out) {
+ }
+
+ public void cleanup() {
+ }
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/water/WaterFilter.java b/engine/src/core-effects/com/jme3/water/WaterFilter.java
new file mode 100644
index 0000000..2943dce
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/water/WaterFilter.java
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.water;
+
+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.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.Filter;
+import com.jme3.post.Filter.Pass;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.texture.Texture2D;
+import com.jme3.util.TempVars;
+import java.io.IOException;
+
+/**
+ * The WaterFilter is a 2D post process that simulate water.
+ * It renders water above and under water.
+ * See this blog post for more info <a href="http://jmonkeyengine.org/2011/01/15/new-advanced-water-effect-for-jmonkeyengine-3/">http://jmonkeyengine.org/2011/01/15/new-advanced-water-effect-for-jmonkeyengine-3/</a>
+ *
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class WaterFilter extends Filter {
+
+ private Pass reflectionPass;
+ protected Spatial reflectionScene;
+ protected ViewPort reflectionView;
+ private Texture2D normalTexture;
+ private Texture2D foamTexture;
+ private Texture2D causticsTexture;
+ private Texture2D heightTexture;
+ private Plane plane;
+ private Camera reflectionCam;
+ protected Ray ray = new Ray();
+ private Vector3f targetLocation = new Vector3f();
+ private ReflectionProcessor reflectionProcessor;
+ private Matrix4f biasMatrix = new Matrix4f(0.5f, 0.0f, 0.0f, 0.5f,
+ 0.0f, 0.5f, 0.0f, 0.5f,
+ 0.0f, 0.0f, 0.0f, 0.5f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+ private Matrix4f textureProjMatrix = new Matrix4f();
+ private boolean underWater;
+ private RenderManager renderManager;
+ private ViewPort viewPort;
+ private float time = 0;
+ //properties
+ private float speed = 1;
+ private Vector3f lightDirection = new Vector3f(0, -1, 0);
+ private ColorRGBA lightColor = ColorRGBA.White;
+ private float waterHeight = 0.0f;
+ private ColorRGBA waterColor = new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f);
+ private ColorRGBA deepWaterColor = new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f);
+ private Vector3f colorExtinction = new Vector3f(5.0f, 20.0f, 30.0f);
+ private float waterTransparency = 0.1f;
+ private float maxAmplitude = 1.5f;
+ private float shoreHardness = 0.1f;
+ private boolean useFoam = true;
+ private float foamIntensity = 0.5f;
+ private float foamHardness = 1.0f;
+ private Vector3f foamExistence = new Vector3f(0.45f, 4.35f, 1.5f);
+ private float waveScale = 0.005f;
+ private float sunScale = 3.0f;
+ private float shininess = 0.7f;
+ private Vector2f windDirection = new Vector2f(0.0f, -1.0f);
+ private int reflectionMapSize = 512;
+ private boolean useRipples = true;
+ private float normalScale = 3.0f;
+ private boolean useHQShoreline = true;
+ private boolean useSpecular = true;
+ private boolean useRefraction = true;
+ private float refractionStrength = 0.0f;
+ private float refractionConstant = 0.5f;
+ private float reflectionDisplace = 30;
+ private float underWaterFogDistance = 120;
+ private boolean useCaustics = true;
+ private float causticsIntensity = 0.5f;
+
+ /**
+ * Create a Water Filter
+ */
+ public WaterFilter() {
+ super("WaterFilter");
+ }
+
+ public WaterFilter(Node reflectionScene, Vector3f lightDirection) {
+ super("WaterFilter");
+ this.reflectionScene = reflectionScene;
+ this.lightDirection = lightDirection;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected void preFrame(float tpf) {
+ time = time + (tpf * speed);
+ material.setFloat("Time", time);
+ Camera sceneCam = viewPort.getCamera();
+ biasMatrix.mult(sceneCam.getViewProjectionMatrix(), textureProjMatrix);
+ material.setMatrix4("TextureProjMatrix", textureProjMatrix);
+ material.setVector3("CameraPosition", sceneCam.getLocation());
+ material.setMatrix4("ViewProjectionMatrixInverse", sceneCam.getViewProjectionMatrix().invert());
+
+ material.setFloat("WaterHeight", waterHeight);
+
+ //update reflection cam
+ ray.setOrigin(sceneCam.getLocation());
+ ray.setDirection(sceneCam.getDirection());
+ plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
+ reflectionProcessor.setReflectionClipPlane(plane);
+ boolean inv = false;
+ if (!ray.intersectsWherePlane(plane, targetLocation)) {
+ ray.setDirection(ray.getDirection().negateLocal());
+ ray.intersectsWherePlane(plane, targetLocation);
+ inv = true;
+ }
+ Vector3f loc = plane.reflect(sceneCam.getLocation(), new Vector3f());
+ reflectionCam.setLocation(loc);
+ reflectionCam.setFrustum(sceneCam.getFrustumNear(),
+ sceneCam.getFrustumFar(),
+ sceneCam.getFrustumLeft(),
+ sceneCam.getFrustumRight(),
+ sceneCam.getFrustumTop(),
+ sceneCam.getFrustumBottom());
+ TempVars vars = TempVars.get();
+
+
+ vars.vect1.set(sceneCam.getLocation()).addLocal(sceneCam.getUp());
+ float planeDistance = plane.pseudoDistance(vars.vect1);
+ vars.vect2.set(plane.getNormal()).multLocal(planeDistance * 2.0f);
+ vars.vect3.set(vars.vect1.subtractLocal(vars.vect2)).subtractLocal(loc).normalizeLocal().negateLocal();
+
+ reflectionCam.lookAt(targetLocation, vars.vect3);
+ vars.release();
+
+ if (inv) {
+ reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
+ }
+
+ //if we're under water no need to compute reflection
+ if (sceneCam.getLocation().y >= waterHeight) {
+ boolean rtb = true;
+ if (!renderManager.isHandleTranslucentBucket()) {
+ renderManager.setHandleTranslucentBucket(true);
+ rtb = false;
+ }
+ renderManager.renderViewPort(reflectionView, tpf);
+ if (!rtb) {
+ renderManager.setHandleTranslucentBucket(false);
+ }
+ renderManager.setCamera(sceneCam, false);
+ renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+
+
+ underWater = false;
+ } else {
+ underWater = true;
+ }
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ private DirectionalLight findLight(Node node) {
+ for (Light light : node.getWorldLightList()) {
+ if (light instanceof DirectionalLight) {
+ return (DirectionalLight) light;
+ }
+ }
+ for (Spatial child : node.getChildren()) {
+ if (child instanceof Node) {
+ return findLight((Node) child);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+
+ if (reflectionScene == null) {
+ reflectionScene = vp.getScenes().get(0);
+ DirectionalLight l = findLight((Node) reflectionScene);
+ if (l != null) {
+ lightDirection = l.getDirection();
+ }
+
+ }
+
+ this.renderManager = renderManager;
+ this.viewPort = vp;
+ reflectionPass = new Pass();
+ reflectionPass.init(renderManager.getRenderer(), reflectionMapSize, reflectionMapSize, Format.RGBA8, Format.Depth);
+ reflectionCam = new Camera(reflectionMapSize, reflectionMapSize);
+ reflectionView = new ViewPort("reflectionView", reflectionCam);
+ reflectionView.setClearFlags(true, true, true);
+ reflectionView.attachScene(reflectionScene);
+ reflectionView.setOutputFrameBuffer(reflectionPass.getRenderFrameBuffer());
+ plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
+ reflectionProcessor = new ReflectionProcessor(reflectionCam, reflectionPass.getRenderFrameBuffer(), plane);
+ reflectionView.addProcessor(reflectionProcessor);
+
+ normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
+ if (foamTexture == null) {
+ foamTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg");
+ }
+ if (causticsTexture == null) {
+ causticsTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/caustics.jpg");
+ }
+ heightTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/heightmap.jpg");
+
+ normalTexture.setWrap(WrapMode.Repeat);
+ foamTexture.setWrap(WrapMode.Repeat);
+ causticsTexture.setWrap(WrapMode.Repeat);
+ heightTexture.setWrap(WrapMode.Repeat);
+
+ material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
+ material.setTexture("HeightMap", heightTexture);
+ material.setTexture("CausticsMap", causticsTexture);
+ material.setTexture("FoamMap", foamTexture);
+ material.setTexture("NormalMap", normalTexture);
+ material.setTexture("ReflectionMap", reflectionPass.getRenderedTexture());
+
+ material.setFloat("WaterTransparency", waterTransparency);
+ material.setFloat("NormalScale", normalScale);
+ material.setFloat("R0", refractionConstant);
+ material.setFloat("MaxAmplitude", maxAmplitude);
+ material.setVector3("LightDir", lightDirection);
+ material.setColor("LightColor", lightColor);
+ material.setFloat("ShoreHardness", shoreHardness);
+ material.setFloat("RefractionStrength", refractionStrength);
+ material.setFloat("WaveScale", waveScale);
+ material.setVector3("FoamExistence", foamExistence);
+ material.setFloat("SunScale", sunScale);
+ material.setVector3("ColorExtinction", colorExtinction);
+ material.setFloat("Shininess", shininess);
+ material.setColor("WaterColor", waterColor);
+ material.setColor("DeepWaterColor", deepWaterColor);
+ material.setVector2("WindDirection", windDirection);
+ material.setFloat("FoamHardness", foamHardness);
+ material.setBoolean("UseRipples", useRipples);
+ material.setBoolean("UseHQShoreline", useHQShoreline);
+ material.setBoolean("UseSpecular", useSpecular);
+ material.setBoolean("UseFoam", useFoam);
+ material.setBoolean("UseCaustics", useCaustics);
+ material.setBoolean("UseRefraction", useRefraction);
+ material.setFloat("ReflectionDisplace", reflectionDisplace);
+ material.setFloat("FoamIntensity", foamIntensity);
+ material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
+ material.setFloat("CausticsIntensity", causticsIntensity);
+
+
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+
+ oc.write(speed, "speed", 1f);
+ oc.write(lightDirection, "lightDirection", new Vector3f(0, -1, 0));
+ oc.write(lightColor, "lightColor", ColorRGBA.White);
+ oc.write(waterHeight, "waterHeight", 0.0f);
+ oc.write(waterColor, "waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
+ oc.write(deepWaterColor, "deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
+
+ oc.write(colorExtinction, "colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
+ oc.write(waterTransparency, "waterTransparency", 0.1f);
+ oc.write(maxAmplitude, "maxAmplitude", 1.5f);
+ oc.write(shoreHardness, "shoreHardness", 0.1f);
+ oc.write(useFoam, "useFoam", true);
+
+ oc.write(foamIntensity, "foamIntensity", 0.5f);
+ oc.write(foamHardness, "foamHardness", 1.0f);
+
+ oc.write(foamExistence, "foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
+ oc.write(waveScale, "waveScale", 0.005f);
+
+ oc.write(sunScale, "sunScale", 3.0f);
+ oc.write(shininess, "shininess", 0.7f);
+ oc.write(windDirection, "windDirection", new Vector2f(0.0f, -1.0f));
+ oc.write(reflectionMapSize, "reflectionMapSize", 512);
+ oc.write(useRipples, "useRipples", true);
+
+ oc.write(normalScale, "normalScale", 3.0f);
+ oc.write(useHQShoreline, "useHQShoreline", true);
+
+ oc.write(useSpecular, "useSpecular", true);
+
+ oc.write(useRefraction, "useRefraction", true);
+ oc.write(refractionStrength, "refractionStrength", 0.0f);
+ oc.write(refractionConstant, "refractionConstant", 0.5f);
+ oc.write(reflectionDisplace, "reflectionDisplace", 30f);
+ oc.write(underWaterFogDistance, "underWaterFogDistance", 120f);
+ oc.write(causticsIntensity, "causticsIntensity", 0.5f);
+
+ oc.write(useCaustics, "useCaustics", true);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ speed = ic.readFloat("speed", 1f);
+ lightDirection = (Vector3f) ic.readSavable("lightDirection", new Vector3f(0, -1, 0));
+ lightColor = (ColorRGBA) ic.readSavable("lightColor", ColorRGBA.White);
+ waterHeight = ic.readFloat("waterHeight", 0.0f);
+ waterColor = (ColorRGBA) ic.readSavable("waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
+ deepWaterColor = (ColorRGBA) ic.readSavable("deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
+
+ colorExtinction = (Vector3f) ic.readSavable("colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
+ waterTransparency = ic.readFloat("waterTransparency", 0.1f);
+ maxAmplitude = ic.readFloat("maxAmplitude", 1.5f);
+ shoreHardness = ic.readFloat("shoreHardness", 0.1f);
+ useFoam = ic.readBoolean("useFoam", true);
+
+ foamIntensity = ic.readFloat("foamIntensity", 0.5f);
+ foamHardness = ic.readFloat("foamHardness", 1.0f);
+
+ foamExistence = (Vector3f) ic.readSavable("foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
+ waveScale = ic.readFloat("waveScale", 0.005f);
+
+ sunScale = ic.readFloat("sunScale", 3.0f);
+ shininess = ic.readFloat("shininess", 0.7f);
+ windDirection = (Vector2f) ic.readSavable("windDirection", new Vector2f(0.0f, -1.0f));
+ reflectionMapSize = ic.readInt("reflectionMapSize", 512);
+ useRipples = ic.readBoolean("useRipples", true);
+
+ normalScale = ic.readFloat("normalScale", 3.0f);
+ useHQShoreline = ic.readBoolean("useHQShoreline", true);
+
+ useSpecular = ic.readBoolean("useSpecular", true);
+
+ useRefraction = ic.readBoolean("useRefraction", true);
+ refractionStrength = ic.readFloat("refractionStrength", 0.0f);
+ refractionConstant = ic.readFloat("refractionConstant", 0.5f);
+ reflectionDisplace = ic.readFloat("reflectionDisplace", 30f);
+ underWaterFogDistance = ic.readFloat("underWaterFogDistance", 120f);
+ causticsIntensity = ic.readFloat("causticsIntensity", 0.5f);
+
+ useCaustics = ic.readBoolean("useCaustics", true);
+
+ }
+
+ /**
+ * gets the height of the water plane
+ * @return
+ */
+ public float getWaterHeight() {
+ return waterHeight;
+ }
+
+ /**
+ * Sets the height of the water plane
+ * default is 0.0
+ * @param waterHeight
+ */
+ public void setWaterHeight(float waterHeight) {
+ this.waterHeight = waterHeight;
+ }
+
+ /**
+ * sets the scene to render in the reflection map
+ * @param reflectionScene
+ */
+ public void setReflectionScene(Spatial reflectionScene) {
+ this.reflectionScene = reflectionScene;
+ }
+
+ /**
+ * returns the waterTransparency value
+ * @return
+ */
+ public float getWaterTransparency() {
+ return waterTransparency;
+ }
+
+ /**
+ * Sets how fast will colours fade out. You can also think about this
+ * values as how clear water is. Therefore use smaller values (eg. 0.05)
+ * to have crystal clear water and bigger to achieve "muddy" water.
+ * default is 0.1f
+ * @param waterTransparency
+ */
+ public void setWaterTransparency(float waterTransparency) {
+ this.waterTransparency = waterTransparency;
+ if (material != null) {
+ material.setFloat("WaterTransparency", waterTransparency);
+ }
+ }
+
+ /**
+ * Returns the normal scales applied to the normal map
+ * @return
+ */
+ public float getNormalScale() {
+ return normalScale;
+ }
+
+ /**
+ * Sets the normal scaling factors to apply to the normal map.
+ * the higher the value the more small ripples will be visible on the waves.
+ * default is 1.0
+ * @param normalScale
+ */
+ public void setNormalScale(float normalScale) {
+ this.normalScale = normalScale;
+ if (material != null) {
+ material.setFloat("NormalScale", normalScale);
+ }
+ }
+
+ /**
+ * returns the refractoin constant
+ * @return
+ */
+ public float getRefractionConstant() {
+ return refractionConstant;
+ }
+
+ /**
+ * This is a constant related to the index of refraction (IOR) used to compute the fresnel term.
+ * F = R0 + (1-R0)( 1 - N.V)^5
+ * where F is the fresnel term, R0 the constant, N the normal vector and V tne view vector.
+ * It usually depend on the material you are lookinh through (here water).
+ * Default value is 0.3f
+ * In practice, the lowest the value and the less the reflection can be seen on water
+ * @param refractionConstant
+ */
+ public void setRefractionConstant(float refractionConstant) {
+ this.refractionConstant = refractionConstant;
+ if (material != null) {
+ material.setFloat("R0", refractionConstant);
+ }
+ }
+
+ /**
+ * return the maximum wave amplitude
+ * @return
+ */
+ public float getMaxAmplitude() {
+ return maxAmplitude;
+ }
+
+ /**
+ * Sets the maximum waves amplitude
+ * default is 1.0
+ * @param maxAmplitude
+ */
+ public void setMaxAmplitude(float maxAmplitude) {
+ this.maxAmplitude = maxAmplitude;
+ if (material != null) {
+ material.setFloat("MaxAmplitude", maxAmplitude);
+ }
+ }
+
+ /**
+ * gets the light direction
+ * @return
+ */
+ public Vector3f getLightDirection() {
+ return lightDirection;
+ }
+
+ /**
+ * Sets the light direction
+ * @param lightDirection
+ */
+ public void setLightDirection(Vector3f lightDirection) {
+ this.lightDirection = lightDirection;
+ if (material != null) {
+ material.setVector3("LightDir", lightDirection);
+ }
+ }
+
+ /**
+ * returns the light color
+ * @return
+ */
+ public ColorRGBA getLightColor() {
+ return lightColor;
+ }
+
+ /**
+ * Sets the light color to use
+ * default is white
+ * @param lightColor
+ */
+ public void setLightColor(ColorRGBA lightColor) {
+ this.lightColor = lightColor;
+ if (material != null) {
+ material.setColor("LightColor", lightColor);
+ }
+ }
+
+ /**
+ * Return the shoreHardeness
+ * @return
+ */
+ public float getShoreHardness() {
+ return shoreHardness;
+ }
+
+ /**
+ * The smaller this value is, the softer the transition between
+ * shore and water. If you want hard edges use very big value.
+ * Default is 0.1f.
+ * @param shoreHardness
+ */
+ public void setShoreHardness(float shoreHardness) {
+ this.shoreHardness = shoreHardness;
+ if (material != null) {
+ material.setFloat("ShoreHardness", shoreHardness);
+ }
+ }
+
+ /**
+ * returns the foam hardness
+ * @return
+ */
+ public float getFoamHardness() {
+ return foamHardness;
+ }
+
+ /**
+ * Sets the foam hardness : How much the foam will blend with the shore to avoid hard edged water plane.
+ * Default is 1.0
+ * @param foamHardness
+ */
+ public void setFoamHardness(float foamHardness) {
+ this.foamHardness = foamHardness;
+ if (material != null) {
+ material.setFloat("FoamHardness", foamHardness);
+ }
+ }
+
+ /**
+ * returns the refractionStrenght
+ * @return
+ */
+ public float getRefractionStrength() {
+ return refractionStrength;
+ }
+
+ /**
+ * This value modifies current fresnel term. If you want to weaken
+ * reflections use bigger value. If you want to empasize them use
+ * value smaller then 0. Default is 0.0f.
+ * @param refractionStrength
+ */
+ public void setRefractionStrength(float refractionStrength) {
+ this.refractionStrength = refractionStrength;
+ if (material != null) {
+ material.setFloat("RefractionStrength", refractionStrength);
+ }
+ }
+
+ /**
+ * returns the scale factor of the waves height map
+ * @return
+ */
+ public float getWaveScale() {
+ return waveScale;
+ }
+
+ /**
+ * Sets the scale factor of the waves height map
+ * the smaller the value the bigger the waves
+ * default is 0.005f
+ * @param waveScale
+ */
+ public void setWaveScale(float waveScale) {
+ this.waveScale = waveScale;
+ if (material != null) {
+ material.setFloat("WaveScale", waveScale);
+ }
+ }
+
+ /**
+ * returns the foam existance vector
+ * @return
+ */
+ public Vector3f getFoamExistence() {
+ return foamExistence;
+ }
+
+ /**
+ * Describes at what depth foam starts to fade out and
+ * at what it is completely invisible. The third value is at
+ * what height foam for waves appear (+ waterHeight).
+ * default is (0.45, 4.35, 1.0);
+ * @param foamExistence
+ */
+ public void setFoamExistence(Vector3f foamExistence) {
+ this.foamExistence = foamExistence;
+ if (material != null) {
+ material.setVector3("FoamExistence", foamExistence);
+ }
+ }
+
+ /**
+ * gets the scale of the sun
+ * @return
+ */
+ public float getSunScale() {
+ return sunScale;
+ }
+
+ /**
+ * Sets the scale of the sun for specular effect
+ * @param sunScale
+ */
+ public void setSunScale(float sunScale) {
+ this.sunScale = sunScale;
+ if (material != null) {
+ material.setFloat("SunScale", sunScale);
+ }
+ }
+
+ /**
+ * Returns the color exctinction vector of the water
+ * @return
+ */
+ public Vector3f getColorExtinction() {
+ return colorExtinction;
+ }
+
+ /**
+ * Return at what depth the refraction color extinct
+ * the first value is for red
+ * the second is for green
+ * the third is for blue
+ * Play with thos parameters to "trouble" the water
+ * default is (5.0, 20.0, 30.0f);
+ * @param colorExtinction
+ */
+ public void setColorExtinction(Vector3f colorExtinction) {
+ this.colorExtinction = colorExtinction;
+ if (material != null) {
+ material.setVector3("ColorExtinction", colorExtinction);
+ }
+ }
+
+ /**
+ * Sets the foam texture
+ * @param foamTexture
+ */
+ public void setFoamTexture(Texture2D foamTexture) {
+ this.foamTexture = foamTexture;
+ foamTexture.setWrap(WrapMode.Repeat);
+ if (material != null) {
+ material.setTexture("FoamMap", foamTexture);
+ }
+ }
+
+ /**
+ * Sets the height texture
+ * @param heightTexture
+ */
+ public void setHeightTexture(Texture2D heightTexture) {
+ this.heightTexture = heightTexture;
+ heightTexture.setWrap(WrapMode.Repeat);
+ }
+
+ /**
+ * Sets the normal Texture
+ * @param normalTexture
+ */
+ public void setNormalTexture(Texture2D normalTexture) {
+ this.normalTexture = normalTexture;
+ normalTexture.setWrap(WrapMode.Repeat);
+ }
+
+ /**
+ * return the shininess factor of the water
+ * @return
+ */
+ public float getShininess() {
+ return shininess;
+ }
+
+ /**
+ * Sets the shinines factor of the water
+ * default is 0.7f
+ * @param shininess
+ */
+ public void setShininess(float shininess) {
+ this.shininess = shininess;
+ if (material != null) {
+ material.setFloat("Shininess", shininess);
+ }
+ }
+
+ /**
+ * retruns the speed of the waves
+ * @return
+ */
+ public float getSpeed() {
+ return speed;
+ }
+
+ /**
+ * Set the speed of the waves (0.0 is still) default is 1.0
+ * @param speed
+ */
+ public void setSpeed(float speed) {
+ this.speed = speed;
+ }
+
+ /**
+ * returns the color of the water
+ *
+ * @return
+ */
+ public ColorRGBA getWaterColor() {
+ return waterColor;
+ }
+
+ /**
+ * Sets the color of the water
+ * see setDeepWaterColor for deep water color
+ * default is (0.0078f, 0.5176f, 0.5f,1.0f) (greenish blue)
+ * @param waterColor
+ */
+ public void setWaterColor(ColorRGBA waterColor) {
+ this.waterColor = waterColor;
+ if (material != null) {
+ material.setColor("WaterColor", waterColor);
+ }
+ }
+
+ /**
+ * returns the deep water color
+ * @return
+ */
+ public ColorRGBA getDeepWaterColor() {
+ return deepWaterColor;
+ }
+
+ /**
+ * sets the deep water color
+ * see setWaterColor for general color
+ * default is (0.0039f, 0.00196f, 0.145f,1.0f) (very dark blue)
+ * @param deepWaterColor
+ */
+ public void setDeepWaterColor(ColorRGBA deepWaterColor) {
+ this.deepWaterColor = deepWaterColor;
+ if (material != null) {
+ material.setColor("DeepWaterColor", deepWaterColor);
+ }
+ }
+
+ /**
+ * returns the wind direction
+ * @return
+ */
+ public Vector2f getWindDirection() {
+ return windDirection;
+ }
+
+ /**
+ * sets the wind direction
+ * the direction where the waves move
+ * default is (0.0f, -1.0f)
+ * @param windDirection
+ */
+ public void setWindDirection(Vector2f windDirection) {
+ this.windDirection = windDirection;
+ if (material != null) {
+ material.setVector2("WindDirection", windDirection);
+ }
+ }
+
+ /**
+ * returns the size of the reflection map
+ * @return
+ */
+ public int getReflectionMapSize() {
+ return reflectionMapSize;
+ }
+
+ /**
+ * Sets the size of the reflection map
+ * default is 512, the higher, the better quality, but the slower the effect.
+ * @param reflectionMapSize
+ */
+ public void setReflectionMapSize(int reflectionMapSize) {
+ this.reflectionMapSize = reflectionMapSize;
+ }
+
+ /**
+ * returns true if the water uses foam
+ * @return
+ */
+ public boolean isUseFoam() {
+ return useFoam;
+ }
+
+ /**
+ * set to true to use foam with water
+ * default true
+ * @param useFoam
+ */
+ public void setUseFoam(boolean useFoam) {
+ this.useFoam = useFoam;
+ if (material != null) {
+ material.setBoolean("UseFoam", useFoam);
+ }
+
+ }
+
+ /**
+ * sets the texture to use to render caustics on the ground underwater
+ * @param causticsTexture
+ */
+ public void setCausticsTexture(Texture2D causticsTexture) {
+ this.causticsTexture = causticsTexture;
+ if (material != null) {
+ material.setTexture("causticsMap", causticsTexture);
+ }
+ }
+
+ /**
+ * returns true if caustics are rendered
+ * @return
+ */
+ public boolean isUseCaustics() {
+ return useCaustics;
+ }
+
+ /**
+ * set to true if you want caustics to be rendered on the ground underwater, false otherwise
+ * @param useCaustics
+ */
+ public void setUseCaustics(boolean useCaustics) {
+ this.useCaustics = useCaustics;
+ if (material != null) {
+ material.setBoolean("UseCaustics", useCaustics);
+ }
+ }
+
+ /**
+ * return true
+ * @return
+ */
+ public boolean isUseHQShoreline() {
+ return useHQShoreline;
+ }
+
+ public void setUseHQShoreline(boolean useHQShoreline) {
+ this.useHQShoreline = useHQShoreline;
+ if (material != null) {
+ material.setBoolean("UseHQShoreline", useHQShoreline);
+ }
+
+ }
+
+ /**
+ * returns true if the water use the refraction
+ * @return
+ */
+ public boolean isUseRefraction() {
+ return useRefraction;
+ }
+
+ /**
+ * set to true to use refraction (default is true)
+ * @param useRefraction
+ */
+ public void setUseRefraction(boolean useRefraction) {
+ this.useRefraction = useRefraction;
+ if (material != null) {
+ material.setBoolean("UseRefraction", useRefraction);
+ }
+
+ }
+
+ /**
+ * returns true if the ater use ripples
+ * @return
+ */
+ public boolean isUseRipples() {
+ return useRipples;
+ }
+
+ /**
+ *
+ * Set to true tu use ripples
+ * @param useRipples
+ */
+ public void setUseRipples(boolean useRipples) {
+ this.useRipples = useRipples;
+ if (material != null) {
+ material.setBoolean("UseRipples", useRipples);
+ }
+
+ }
+
+ /**
+ * returns true if the water use specular
+ * @return
+ */
+ public boolean isUseSpecular() {
+ return useSpecular;
+ }
+
+ /**
+ * Set to true to use specular lightings on the water
+ * @param useSpecular
+ */
+ public void setUseSpecular(boolean useSpecular) {
+ this.useSpecular = useSpecular;
+ if (material != null) {
+ material.setBoolean("UseSpecular", useSpecular);
+ }
+ }
+
+ /**
+ * returns the foam intensity
+ * @return
+ */
+ public float getFoamIntensity() {
+ return foamIntensity;
+ }
+
+ /**
+ * sets the foam intensity default is 0.5f
+ * @param foamIntensity
+ */
+ public void setFoamIntensity(float foamIntensity) {
+ this.foamIntensity = foamIntensity;
+ if (material != null) {
+ material.setFloat("FoamIntensity", foamIntensity);
+
+ }
+ }
+
+ /**
+ * returns the reflection displace
+ * see {@link setReflectionDisplace(float reflectionDisplace)}
+ * @return
+ */
+ public float getReflectionDisplace() {
+ return reflectionDisplace;
+ }
+
+ /**
+ * Sets the reflection displace. define how troubled will look the reflection in the water. default is 30
+ * @param reflectionDisplace
+ */
+ public void setReflectionDisplace(float reflectionDisplace) {
+ this.reflectionDisplace = reflectionDisplace;
+ if (material != null) {
+ material.setFloat("m_ReflectionDisplace", reflectionDisplace);
+ }
+ }
+
+ /**
+ * returns true if the camera is under the water level
+ * @return
+ */
+ public boolean isUnderWater() {
+ return underWater;
+ }
+
+ /**
+ * returns the distance of the fog when under water
+ * @return
+ */
+ public float getUnderWaterFogDistance() {
+ return underWaterFogDistance;
+ }
+
+ /**
+ * sets the distance of the fog when under water.
+ * default is 120 (120 world units) use a high value to raise the view range under water
+ * @param underWaterFogDistance
+ */
+ public void setUnderWaterFogDistance(float underWaterFogDistance) {
+ this.underWaterFogDistance = underWaterFogDistance;
+ if (material != null) {
+ material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
+ }
+ }
+
+ /**
+ * get the intensity of caustics under water
+ * @return
+ */
+ public float getCausticsIntensity() {
+ return causticsIntensity;
+ }
+
+ /**
+ * sets the intensity of caustics under water. goes from 0 to 1, default is 0.5f
+ * @param causticsIntensity
+ */
+ public void setCausticsIntensity(float causticsIntensity) {
+ this.causticsIntensity = causticsIntensity;
+ if (material != null) {
+ material.setFloat("CausticsIntensity", causticsIntensity);
+ }
+ }
+}