diff --git a/engine/src/core-data/Common/MatDefs/Post/FXAA.frag b/engine/src/core-data/Common/MatDefs/Post/FXAA.frag
new file mode 100644
index 000000000..679e9d2cf
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Post/FXAA.frag
@@ -0,0 +1,73 @@
+#extension GL_EXT_gpu_shader4 : enable
+uniform sampler2D m_Texture;
+uniform vec2 g_Resolution;
+varying vec2 texCoord;
+uniform float m_VxOffset;
+uniform float m_SpanMax;
+uniform float m_ReduceMul;
+varying vec4 posPos;
+#define FxaaInt2 ivec2
+#define FxaaFloat2 vec2
+#define FxaaTexLod0(t, p) texture2DLod(t, p, 0.0)
+#define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o)
+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 = FxaaTexLod0(tex, posPos.zw).xyz;
+ vec3 rgbNE = FxaaTexOff(tex, posPos.zw, FxaaInt2(1,0), rcpFrame.xy).xyz;
+ vec3 rgbSW = FxaaTexOff(tex, posPos.zw, FxaaInt2(0,1), rcpFrame.xy).xyz;
+ vec3 rgbSE = FxaaTexOff(tex, posPos.zw, FxaaInt2(1,1), rcpFrame.xy).xyz;
+ vec3 rgbM = FxaaTexLod0(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(FxaaFloat2( m_SpanMax, m_SpanMax),
+ max(FxaaFloat2(-m_SpanMax, -m_SpanMax),
+ dir * rcpDirMin)) * rcpFrame.xy;
+/*--------------------------------------------------------*/
+ vec3 rgbA = (1.0/2.0) * (
+ FxaaTexLod0(tex, posPos.xy + dir * (1.0/3.0 - 0.5)).xyz +
+ FxaaTexLod0(tex, posPos.xy + dir * (2.0/3.0 - 0.5)).xyz);
+ vec3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (
+ FxaaTexLod0(tex, posPos.xy + dir * (0.0/3.0 - 0.5)).xyz +
+ FxaaTexLod0(tex, posPos.xy + dir * (3.0/3.0 - 0.5)).xyz);
+ float lumaB = dot(rgbB, luma);
+ if((lumaB < lumaMin) || (lumaB > lumaMax)) return rgbA;
+ return rgbB; }
+vec4 PostFX(sampler2D tex, vec2 uv, float time)
+{
+ vec4 c = vec4(0.0);
+ vec2 rcpFrame = vec2(1.0/g_Resolution.x, 1.0/g_Resolution.y);
+ c.rgb = FxaaPixelShader(posPos, tex, rcpFrame);
+ //c.rgb = 1.0 - texture2D(tex, posPos.xy).rgb;
+ c.a = 1.0;
+ return c;
+}
+void main()
+{
+ vec2 uv = texCoord.st;
+ gl_FragColor = PostFX(m_Texture, uv, 0.0);
+}
\ No newline at end of file
diff --git a/engine/src/core-data/Common/MatDefs/Post/FXAA.j3md b/engine/src/core-data/Common/MatDefs/Post/FXAA.j3md
new file mode 100644
index 000000000..88401f529
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Post/FXAA.j3md
@@ -0,0 +1,20 @@
+MaterialDef FXAA {
+ MaterialParameters {
+ Int NumSamples
+ Texture2D Texture
+ Float SubPixelShif
+ Float VxOffset
+ Float SpanMax
+ Float ReduceMul
+ }
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Post/FXAA.vert
+ FragmentShader GLSL120: Common/MatDefs/Post/FXAA.frag
+ WorldParameters {
+ WorldViewProjectionMatrix
+ Resolution
+ }
+ }
+ Technique FixedFunc {
+ }
+}
\ No newline at end of file
diff --git a/engine/src/core-data/Common/MatDefs/Post/FXAA.vert b/engine/src/core-data/Common/MatDefs/Post/FXAA.vert
new file mode 100644
index 000000000..659492634
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Post/FXAA.vert
@@ -0,0 +1,15 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform vec2 g_Resolution;
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+varying vec2 texCoord;
+uniform float m_SubPixelShif;
+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.x, 1.0/g_Resolution.y);
+ posPos.xy = inTexCoord.xy;
+ posPos.zw = inTexCoord.xy -
+ (rcpFrame * (0.5 + m_SubPixelShif));
+}
\ No newline at end of file
diff --git a/engine/src/desktop-fx/com/jme3/post/filters/FXAAFilter.java b/engine/src/desktop-fx/com/jme3/post/filters/FXAAFilter.java
new file mode 100644
index 000000000..27de14569
--- /dev/null
+++ b/engine/src/desktop-fx/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;
+
+/**
+ * http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-opengl-test-radeon-geforce/3/
+ * http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf
+ *
+ * @author Phate666 (adapted to jme3)
+ *
+ */
+public class FXAAFilter extends Filter {
+
+ private float subPixelShif = 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("SubPixelShif", subPixelShif);
+ 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) {
+ subPixelShif = subPixelShift;
+ if (material != null) {
+ material.setFloat("SubPixelShif", subPixelShif);
+ }
+ }
+
+ /**
+ * 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 getSubPixelShif() {
+ return subPixelShif;
+ }
+
+ public float getVxOffset() {
+ return vxOffset;
+ }
+}
\ No newline at end of file