diff options
author | Scott Barta <sbarta@google.com> | 2012-03-01 12:35:35 -0800 |
---|---|---|
committer | Scott Barta <sbarta@google.com> | 2012-03-01 12:40:08 -0800 |
commit | 59b2e6871c65f58fdad78cd7229c292f6a177578 (patch) | |
tree | 2d4e7bfc05b93f40b34675d77e403dd1c25efafd /engine/src/core-effects | |
parent | f9b30489e75ac1eabc365064959804e99534f7ab (diff) | |
download | jmonkeyengine-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')
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 Binary files differnew file mode 100644 index 0000000..e19b7f5 --- /dev/null +++ b/engine/src/core-effects/Common/MatDefs/SSAO/Textures/random.png 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 Binary files differnew file mode 100644 index 0000000..fb4f21c --- /dev/null +++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/caustics.jpg 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 Binary files differnew file mode 100644 index 0000000..a2734bb --- /dev/null +++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/dudv_map.jpg diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/foam.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam.jpg Binary files differnew file mode 100644 index 0000000..fc17ac2 --- /dev/null +++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam.jpg diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/foam2.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam2.jpg Binary files differnew file mode 100644 index 0000000..ef19b87 --- /dev/null +++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam2.jpg diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/foam3.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam3.jpg Binary files differnew file mode 100644 index 0000000..8295b3f --- /dev/null +++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/foam3.jpg diff --git a/engine/src/core-effects/Common/MatDefs/Water/Textures/heightmap.jpg b/engine/src/core-effects/Common/MatDefs/Water/Textures/heightmap.jpg Binary files differnew file mode 100644 index 0000000..cfb5846 --- /dev/null +++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/heightmap.jpg 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 Binary files differnew file mode 100644 index 0000000..13582e1 --- /dev/null +++ b/engine/src/core-effects/Common/MatDefs/Water/Textures/water_normalmap.dds 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); + } + } +} |