diff --git a/engine/src/core/com/jme3/post/Filter.java b/engine/src/core/com/jme3/post/Filter.java index f78b7024a..8e7187c8b 100644 --- a/engine/src/core/com/jme3/post/Filter.java +++ b/engine/src/core/com/jme3/post/Filter.java @@ -81,17 +81,17 @@ public abstract class Filter implements Savable { if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample) && caps.contains(Caps.OpenGL31)) { renderFrameBuffer = new FrameBuffer(width, height, numSamples); renderedTexture = new Texture2D(width, height, numSamples, textureFormat); - // depthTexture = new Texture2D(width, height, numSamples, depthBufferFormat); + // depthTexture = new Texture2D(width, height, numSamples, depthBufferFormat); } else { renderFrameBuffer = new FrameBuffer(width, height, 1); - renderedTexture = new Texture2D(width, height, textureFormat); + renderedTexture = new Texture2D(width, height, textureFormat); // depthTexture = new Texture2D(width, height, depthBufferFormat); } - + renderFrameBuffer.setColorTexture(renderedTexture); renderFrameBuffer.setDepthBuffer(depthBufferFormat); - // renderFrameBuffer.setDepthTexture(depthTexture); - + // renderFrameBuffer.setDepthTexture(depthTexture); + } public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat) { @@ -111,7 +111,6 @@ public abstract class Filter implements Savable { return false; } - public void beforeRender() { } @@ -126,7 +125,6 @@ public abstract class Filter implements Savable { public Texture2D getDepthTexture() { return depthTexture; } - public Texture2D getRenderedTexture() { return renderedTexture; @@ -160,15 +158,15 @@ public abstract class Filter implements Savable { this("filter"); } - public void init(FilterPostProcessor parentProcessor, AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { + public void init(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { // cleanup(renderManager.getRenderer()); defaultPass = new Pass(); - defaultPass.init(renderManager.getRenderer(),w, h, getDefaultPassTextureFormat(), getDefaultPassDepthFormat()); - processor = parentProcessor; + defaultPass.init(renderManager.getRenderer(), w, h, getDefaultPassTextureFormat(), getDefaultPassDepthFormat()); initFilter(manager, renderManager, vp, w, h); } public void cleanup(Renderer r) { + processor = null; if (defaultPass != null) { defaultPass.cleanup(r); } @@ -279,9 +277,9 @@ public abstract class Filter implements Savable { } public void setEnabled(boolean enabled) { - if(processor!=null){ + if (processor != null) { processor.setFilterState(this, enabled); - }else{ + } else { this.enabled = enabled; } } @@ -289,5 +287,8 @@ public abstract class Filter implements Savable { public boolean isEnabled() { return enabled; } - + + protected void setProcessor(FilterPostProcessor proc) { + processor = proc; + } } diff --git a/engine/src/core/com/jme3/post/FilterPostProcessor.java b/engine/src/core/com/jme3/post/FilterPostProcessor.java index 3e6131961..3be4a7d84 100644 --- a/engine/src/core/com/jme3/post/FilterPostProcessor.java +++ b/engine/src/core/com/jme3/post/FilterPostProcessor.java @@ -72,9 +72,14 @@ public class FilterPostProcessor implements SceneProcessor, Savable { private FrameBuffer outputBuffer; private int width; private int height; - private int bottom; - private int left; + private float bottom; + private float left; + private float right; + private float top; + private int originalWidth; + private int originalHeight; private int lastFilterIndex = -1; + private boolean cameraInit = false; /** * Create a FilterProcessor constructor @@ -92,13 +97,14 @@ public class FilterPostProcessor implements SceneProcessor, Savable { public void addFilter(Filter filter) { filters.add(filter); + filter.setProcessor(this); if (isInitialized()) { initFilter(filter, viewPort); } - if (filter.isEnabled()) { - lastFilterIndex = filters.size() - 1; - } + + setFilterState(filter, filter.isEnabled()); + } public void removeFilter(Filter filter) { @@ -118,14 +124,19 @@ public class FilterPostProcessor implements SceneProcessor, Savable { fsQuad = new Picture("filter full screen quad"); Camera cam = vp.getCamera(); + left = cam.getViewPortLeft(); + right = cam.getViewPortRight(); + top = cam.getViewPortTop(); + bottom = cam.getViewPortBottom(); //Changing the viewPort to the filter cam an reseting the viewport of the viewport cam - filterCam.setViewPort(cam.getViewPortLeft(), cam.getViewPortRight(), cam.getViewPortBottom(), cam.getViewPortTop()); + originalWidth = cam.getWidth(); + originalHeight = cam.getHeight(); cam.setViewPort(0, 1, 0, 1); reshape(vp, cam.getWidth(), cam.getHeight()); } private void initFilter(Filter filter, ViewPort vp) { - filter.init(this, assetManager, renderManager, vp, width, height); + filter.init(assetManager, renderManager, vp, width, height); if (filter.isRequiresDepthTexture()) { if (!computeDepth && renderFrameBuffer != null) { depthTexture = new Texture2D(width, height, Format.Depth24); @@ -137,24 +148,25 @@ public class FilterPostProcessor implements SceneProcessor, Savable { } private void renderProcessing(Renderer r, FrameBuffer buff, Material mat) { - if (buff == null) { + if (buff == outputBuffer) { fsQuad.setWidth(width); fsQuad.setHeight(height); - filterCam.resize(width, height, true); + filterCam.resize(originalWidth, originalHeight, true); + fsQuad.setPosition(left * originalWidth, bottom * originalHeight); } else { fsQuad.setWidth(buff.getWidth()); fsQuad.setHeight(buff.getHeight()); filterCam.resize(buff.getWidth(), buff.getHeight(), true); + fsQuad.setPosition(0, 0); } fsQuad.setMaterial(mat); fsQuad.updateGeometricState(); - filterCam.setName("filterCam"); - //fsQuad.setPosition(640, 360); + renderManager.setCamera(filterCam, true); r.setFrameBuffer(buff); - r.clearBuffers(true, true, true); + r.clearBuffers(false, true, true); renderManager.renderGeometry(fsQuad); } @@ -163,12 +175,14 @@ public class FilterPostProcessor implements SceneProcessor, Savable { } public void postQueue(RenderQueue rq) { + for (Iterator it = filters.iterator(); it.hasNext();) { Filter filter = it.next(); if (filter.isEnabled()) { filter.preRender(renderManager, viewPort); } } + } public void renderFilterChain(Renderer r) { @@ -225,31 +239,45 @@ public class FilterPostProcessor implements SceneProcessor, Savable { } public void postFrame(FrameBuffer out) { - //Added this to fix the issue where the filter were not rendered when an object in the scene had a DepthWrite to false. (particles for example) - //there should be a better way... - // renderer.applyRenderState(RenderState.DEFAULT); + + if (renderFrameBufferMS != null && !renderer.getCaps().contains(Caps.OpenGL31)) { renderer.copyFrameBuffer(renderFrameBufferMS, renderFrameBuffer); } renderFilterChain(renderer); + } public void preFrame(float tpf) { if (filters.isEmpty() || lastFilterIndex == -1) { - viewPort.setOutputFrameBuffer(outputBuffer); + //If the camera is initialized and there are no filter to render, the camera viewport is restored as it was + if (cameraInit) { + viewPort.getCamera().resize(originalWidth, originalHeight, true); + viewPort.getCamera().setViewPort(left, right, bottom, top); + viewPort.setOutputFrameBuffer(outputBuffer); + cameraInit = false; + } + } else { if (renderFrameBufferMS != null) { viewPort.setOutputFrameBuffer(renderFrameBufferMS); } else { viewPort.setOutputFrameBuffer(renderFrameBuffer); } + //init of the camera if it wasn't already + if (!cameraInit) { + viewPort.getCamera().resize(width, height, true); + viewPort.getCamera().setViewPort(0, 1, 0, 1); + } } + for (Iterator it = filters.iterator(); it.hasNext();) { Filter filter = it.next(); if (filter.isEnabled()) { filter.preFrame(tpf); } } + } protected void setFilterState(Filter filter, boolean enabled) { @@ -267,25 +295,29 @@ public class FilterPostProcessor implements SceneProcessor, Savable { return; } } - + if (lastFilterIndex == -1) { + cleanup(); + } } public void cleanup() { if (viewPort != null) { //reseting the viewport camera viewport to its initial value - viewPort.getCamera().setViewPort(filterCam.getViewPortLeft(), filterCam.getViewPortRight(), filterCam.getViewPortBottom(), filterCam.getViewPortTop()); + viewPort.getCamera().resize(originalWidth, originalHeight, true); + viewPort.getCamera().setViewPort(left, right, bottom, top); viewPort.setOutputFrameBuffer(outputBuffer); viewPort = null; } + } public void reshape(ViewPort vp, int w, int h) { - Camera cam = vp.getCamera(); - width = (int) (w * (Math.abs(cam.getViewPortRight() - cam.getViewPortLeft()))); - height = (int) (h * (Math.abs(cam.getViewPortBottom() - cam.getViewPortTop()))); + width = (int) (w * (Math.abs(right - left))); + height = (int) (h * (Math.abs(bottom - top))); width = Math.max(1, width); height = Math.max(1, height); - // vp.getCamera().resize(width, height, true); + vp.getCamera().resize(width, height, true); + cameraInit = true; computeDepth = false; if (renderFrameBuffer == null) { diff --git a/engine/src/desktop-fx/com/jme3/water/WaterFilter.java b/engine/src/desktop-fx/com/jme3/water/WaterFilter.java index 12782b87e..d82a8e1ca 100644 --- a/engine/src/desktop-fx/com/jme3/water/WaterFilter.java +++ b/engine/src/desktop-fx/com/jme3/water/WaterFilter.java @@ -233,8 +233,8 @@ public class WaterFilter extends Filter { material.setBoolean("UseSpecular", useSpecular); material.setBoolean("UseFoam", useFoam); material.setBoolean("UseRefraction", useRefraction); - material.setFloat("m_ReflectionDisplace", reflectionDisplace); - material.setFloat("m_FoamIntensity", foamIntensity); + material.setFloat("ReflectionDisplace", reflectionDisplace); + material.setFloat("FoamIntensity", foamIntensity); } diff --git a/engine/src/test/jme3test/post/TestMultiViewsFilters.java b/engine/src/test/jme3test/post/TestMultiViewsFilters.java index 48a62337b..71aa7ab3c 100644 --- a/engine/src/test/jme3test/post/TestMultiViewsFilters.java +++ b/engine/src/test/jme3test/post/TestMultiViewsFilters.java @@ -31,22 +31,24 @@ */ package jme3test.post; -import jme3test.renderer.*; import com.jme3.app.SimpleApplication; import com.jme3.input.KeyInput; import com.jme3.input.controls.ActionListener; -import com.jme3.input.controls.InputListener; import com.jme3.input.controls.KeyTrigger; import com.jme3.light.DirectionalLight; import com.jme3.math.ColorRGBA; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; -import com.jme3.post.Filter; import com.jme3.post.FilterPostProcessor; -import com.jme3.post.filters.ColorOverlayFilter; +import com.jme3.post.filters.BloomFilter; +import com.jme3.post.filters.CartoonEdgeFilter; +import com.jme3.post.filters.FogFilter; +import com.jme3.post.filters.RadialBlurFilter; +import com.jme3.post.ssao.SSAOFilter; import com.jme3.renderer.Camera; import com.jme3.renderer.ViewPort; import com.jme3.scene.Geometry; +import com.jme3.util.SkyFactory; public class TestMultiViewsFilters extends SimpleApplication { @@ -79,7 +81,7 @@ public class TestMultiViewsFilters extends SimpleApplication { cam2.setLocation(new Vector3f(-0.10947256f, 1.5760219f, 4.81758f)); cam2.setRotation(new Quaternion(0.0010108891f, 0.99857414f, -0.04928594f, 0.020481428f)); - ViewPort view2 = renderManager.createMainView("Bottom Left", cam2); + final ViewPort view2 = renderManager.createMainView("Bottom Left", cam2); view2.setClearFlags(true, true, true); view2.attachScene(rootNode); @@ -90,7 +92,7 @@ public class TestMultiViewsFilters extends SimpleApplication { cam3.setLocation(new Vector3f(0.2846221f, 6.4271426f, 0.23380789f)); cam3.setRotation(new Quaternion(0.004381671f, 0.72363687f, -0.69015175f, 0.0045953835f)); - ViewPort view3 = renderManager.createMainView("Top Left", cam3); + final ViewPort view3 = renderManager.createMainView("Top Left", cam3); view3.setClearFlags(true, true, true); view3.attachScene(rootNode); @@ -103,42 +105,67 @@ public class TestMultiViewsFilters extends SimpleApplication { cam4.setLocation(new Vector3f(4.775564f, 1.4548365f, 0.11491505f)); cam4.setRotation(new Quaternion(0.02356979f, -0.74957186f, 0.026729556f, 0.66096294f)); - ViewPort view4 = renderManager.createMainView("Top Right", cam4); + final ViewPort view4 = renderManager.createMainView("Top Right", cam4); view4.setClearFlags(true, true, true); view4.attachScene(rootNode); + rootNode.attachChild(SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", false)); + final FilterPostProcessor fpp = new FilterPostProcessor(assetManager); - FilterPostProcessor fpp2 = new FilterPostProcessor(assetManager); - FilterPostProcessor fpp3 = new FilterPostProcessor(assetManager); - FilterPostProcessor fpp4 = new FilterPostProcessor(assetManager); + final FilterPostProcessor fpp2 = new FilterPostProcessor(assetManager); + final FilterPostProcessor fpp3 = new FilterPostProcessor(assetManager); + final FilterPostProcessor fpp4 = new FilterPostProcessor(assetManager); + + + // fpp.addFilter(new WaterFilter(rootNode, Vector3f.UNIT_Y.mult(-1))); + fpp3.addFilter(new CartoonEdgeFilter()); + + fpp2.addFilter(new BloomFilter()); + final FogFilter ff = new FogFilter(ColorRGBA.Yellow, 0.7f, 2); + fpp.addFilter(ff); - fpp.addFilter(new ColorOverlayFilter(ColorRGBA.Red)); - fpp2.addFilter(new ColorOverlayFilter(ColorRGBA.Green)); - fpp3.addFilter(new ColorOverlayFilter(ColorRGBA.Blue)); - fpp4.addFilter(new ColorOverlayFilter(ColorRGBA.Yellow)); + final RadialBlurFilter rbf = new RadialBlurFilter(1, 10); + // rbf.setEnabled(false); + fpp.addFilter(rbf); + SSAOFilter f = new SSAOFilter(1.8899765f, 20.490374f, 0.4699998f, 0.1f);; + fpp4.addFilter(f); + SSAOUI ui = new SSAOUI(inputManager, f); + viewPort.addProcessor(fpp); view2.addProcessor(fpp2); view3.addProcessor(fpp3); view4.addProcessor(fpp4); + inputManager.addListener(new ActionListener() { public void onAction(String name, boolean isPressed, float tpf) { if (name.equals("press") && isPressed) { if (filterEnabled) { viewPort.removeProcessor(fpp); + view2.removeProcessor(fpp2); + view3.removeProcessor(fpp3); + view4.removeProcessor(fpp4); } else { viewPort.addProcessor(fpp); + view2.addProcessor(fpp2); + view3.addProcessor(fpp3); + view4.addProcessor(fpp4); } filterEnabled = !filterEnabled; } + if (name.equals("filter") && isPressed) { + ff.setEnabled(!ff.isEnabled()); + rbf.setEnabled(!rbf.isEnabled()); + } } - }, "press"); + }, "press", "filter"); inputManager.addMapping("press", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("filter", new KeyTrigger(KeyInput.KEY_F)); } }