From 6ed646656dde6c01f819fdbbb45859ed2a494d60 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sun, 17 Mar 2024 20:47:59 -0400 Subject: [PATCH 01/18] added pbr bloom filter --- .../com/jme3/post/filters/PBRBloomFilter.java | 117 ++++++++++++++ .../Common/MatDefs/Post/Downsample.frag | 60 +++++++ .../Common/MatDefs/Post/Downsample.j3md | 22 +++ .../Common/MatDefs/Post/PBRBloomFinal.frag | 14 ++ .../Common/MatDefs/Post/PBRBloomFinal.j3md | 22 +++ .../Common/MatDefs/Post/Upsample.frag | 49 ++++++ .../Common/MatDefs/Post/Upsample.j3md | 23 +++ .../main/java/jme3test/post/TestBloom.java | 2 - .../main/java/jme3test/post/TestPBRBloom.java | 149 ++++++++++++++++++ 9 files changed, 456 insertions(+), 2 deletions(-) create mode 100644 jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Downsample.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Downsample.j3md create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.j3md create mode 100644 jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java new file mode 100644 index 0000000000..e1952a06ca --- /dev/null +++ b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java @@ -0,0 +1,117 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package com.jme3.post.filters; + +import com.jme3.asset.AssetManager; +import com.jme3.material.Material; +import com.jme3.math.Vector2f; +import com.jme3.post.Filter; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.ViewPort; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import java.util.LinkedList; + +/** + * + * @author codex + */ +public class PBRBloomFilter extends Filter { + + private AssetManager assetManager; + private RenderManager renderManager; + private ViewPort viewPort; + private Pass[] downsamplingPasses = new Pass[4]; + private Pass[] upsamplingPasses = new Pass[4]; + private Image.Format format = Image.Format.RGBA16F; + + @Override + protected void initFilter(AssetManager am, RenderManager rm, ViewPort vp, int width, int height) { + + assetManager = am; + renderManager = rm; + viewPort = vp; + postRenderPasses = new LinkedList<>(); + Renderer renderer = renderManager.getRenderer(); + + int w = width; + int h = height; + + // downsampling passes + Material downsampleMat = new Material(assetManager, "Common/MatDefs/Post/Downsample.j3md"); + Vector2f initTexelSize = new Vector2f(1f/w, 1f/h); + w /= 2; h /= 2; + Pass initialPass = new Pass() { + @Override + public boolean requiresSceneAsTexture() { + return true; + } + @Override + public void beforeRender() { + downsampleMat.setVector2("TexelSize", initTexelSize); + } + }; + initialPass.init(renderer, w, h, format, Image.Format.Depth, 1, downsampleMat); + postRenderPasses.add(initialPass); + downsamplingPasses[0] = initialPass; + for (int i = 1; i < downsamplingPasses.length; i++) { + int wi = w, hi = h; + Vector2f texelSize = new Vector2f(1f/w, 1f/h); + w /= 2; h /= 2; + Pass prev = downsamplingPasses[i-1]; + Pass pass = new Pass() { + @Override + public void beforeRender() { + //renderManager.getRenderer().setViewPort(0, 0, wi, hi); + downsampleMat.setTexture("Texture", prev.getRenderedTexture()); + downsampleMat.setVector2("TexelSize", texelSize); + } + }; + pass.init(renderer, w, h, format, Image.Format.Depth, 1, downsampleMat); + postRenderPasses.add(pass); + downsamplingPasses[i] = pass; + } + + // upsampling passes + Material upsampleMat = new Material(assetManager, "Common/MatDefs/Post/Upsample.j3md"); + for (int i = 0; i < upsamplingPasses.length; i++) { + int wi = w, hi = h; + Vector2f texelSize = new Vector2f(1f/w, 1f/h); + w *= 2; h *= 2; + Pass prev; + if (i == 0) { + prev = downsamplingPasses[downsamplingPasses.length-1]; + } else { + prev = upsamplingPasses[i-1]; + } + Pass pass = new Pass() { + @Override + public void beforeRender() { + //renderManager.getRenderer().setViewPort(0, 0, wi, hi); + upsampleMat.setTexture("Texture", prev.getRenderedTexture()); + upsampleMat.setVector2("TexelSize", texelSize); + } + }; + pass.init(renderer, w, h, format, Image.Format.Depth, 1, upsampleMat); + postRenderPasses.add(pass); + upsamplingPasses[i] = pass; + } + + material = new Material(assetManager, "Common/MatDefs/Post/PBRBloomFinal.j3md"); + material.setTexture("GlowMap", upsamplingPasses[upsamplingPasses.length-1].getRenderedTexture()); + + } + @Override + protected Material getMaterial() { + return material; + } + @Override + protected void postFilter(Renderer r, FrameBuffer buffer) { + //renderManager.getRenderer().setV + } + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Downsample.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/Downsample.frag new file mode 100644 index 0000000000..2803a95d87 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/Downsample.frag @@ -0,0 +1,60 @@ + +#import "Common/ShaderLib/GLSLCompat.glsllib" +#import "Common/ShaderLib/MultiSample.glsllib" + +uniform COLORTEXTURE m_Texture; +uniform vec2 m_TexelSize; +varying vec2 texCoord; + +void main() { + + // downsampling code: https://learnopengl.com/Guest-Articles/2022/Phys.-Based-Bloom + + float x = m_TexelSize.x; + float y = m_TexelSize.y; + + // Take 13 samples around current texel + // a - b - c + // - j - k - + // d - e - f + // - l - m - + // g - h - i + // === ('e' is the current texel) === + vec3 a = getColor(m_Texture, vec2(texCoord.x - 2*x, texCoord.y + 2*y)).rgb; + vec3 b = getColor(m_Texture, vec2(texCoord.x, texCoord.y + 2*y)).rgb; + vec3 c = getColor(m_Texture, vec2(texCoord.x + 2*x, texCoord.y + 2*y)).rgb; + + vec3 d = getColor(m_Texture, vec2(texCoord.x - 2*x, texCoord.y)).rgb; + vec3 e = getColor(m_Texture, vec2(texCoord.x, texCoord.y)).rgb; + vec3 f = getColor(m_Texture, vec2(texCoord.x + 2*x, texCoord.y)).rgb; + + vec3 g = getColor(m_Texture, vec2(texCoord.x - 2*x, texCoord.y - 2*y)).rgb; + vec3 h = getColor(m_Texture, vec2(texCoord.x, texCoord.y - 2*y)).rgb; + vec3 i = getColor(m_Texture, vec2(texCoord.x + 2*x, texCoord.y - 2*y)).rgb; + + vec3 j = getColor(m_Texture, vec2(texCoord.x - x, texCoord.y + y)).rgb; + vec3 k = getColor(m_Texture, vec2(texCoord.x + x, texCoord.y + y)).rgb; + vec3 l = getColor(m_Texture, vec2(texCoord.x - x, texCoord.y - y)).rgb; + vec3 m = getColor(m_Texture, vec2(texCoord.x + x, texCoord.y - y)).rgb; + + // Apply weighted distribution: + // 0.5 + 0.125 + 0.125 + 0.125 + 0.125 = 1 + // a,b,d,e * 0.125 + // b,c,e,f * 0.125 + // d,e,g,h * 0.125 + // e,f,h,i * 0.125 + // j,k,l,m * 0.5 + // This shows 5 square areas that are being sampled. But some of them overlap, + // so to have an energy preserving downsample we need to make some adjustments. + // The weights are the distributed, so that the sum of j,k,l,m (e.g.) + // contribute 0.5 to the final color output. The code below is written + // to effectively yield this sum. We get: + // 0.125*5 + 0.03125*4 + 0.0625*4 = 1 + vec3 downsample = e*0.125; + downsample += (a+c+g+i)*0.03125; + downsample += (b+d+f+h)*0.0625; + downsample += (j+k+l+m)*0.125; + + gl_FragColor = vec4(downsample, 1.0); + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Downsample.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/Downsample.j3md new file mode 100644 index 0000000000..595a918eb3 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/Downsample.j3md @@ -0,0 +1,22 @@ +MaterialDef Downsample { + + MaterialParameters { + Texture2D Texture + Vector2 TexelSize + Int BoundDrawBuffer + Int NumSamples + } + + Technique { + VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Post/Post.vert + FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Post/Downsample.frag + + WorldParameters { + } + + Defines { + BOUND_DRAW_BUFFER: BoundDrawBuffer + RESOLVE_MS : NumSamples + } + } +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag new file mode 100644 index 0000000000..7b54e9828d --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag @@ -0,0 +1,14 @@ + +#import "Common/ShaderLib/GLSLCompat.glsllib" +#import "Common/ShaderLib/MultiSample.glsllib" + +uniform COLORTEXTURE m_Texture; +uniform sampler2D m_GlowMap; +varying vec2 texCoord; + +void main() { + + gl_FragColor = mix(getColor(m_Texture, texCoord), texture2D(m_GlowMap, texCoord), 0.05); + +} + diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md new file mode 100644 index 0000000000..10510cdcde --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md @@ -0,0 +1,22 @@ +MaterialDef PBRBloomFinal { + + MaterialParameters { + Texture2D Texture + Texture2D GlowMap + Int BoundDrawBuffer + Int NumSamples + } + + Technique { + VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Post/Post.vert + FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Post/PBRBloomFinal.frag + + WorldParameters { + } + + Defines { + BOUND_DRAW_BUFFER: BoundDrawBuffer + RESOLVE_MS : NumSamples + } + } +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.frag new file mode 100644 index 0000000000..897c55f04b --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.frag @@ -0,0 +1,49 @@ + +#import "Common/ShaderLib/GLSLCompat.glsllib" +#import "Common/ShaderLib/MultiSample.glsllib" + +uniform COLORTEXTURE m_Texture; +uniform float m_FilterRadius; +uniform vec2 m_TexelSize; +varying vec2 texCoord; + +void main() { + + // upsampling code: https://learnopengl.com/Guest-Articles/2022/Phys.-Based-Bloom + + // The filter kernel is applied with a radius, specified in texture + // coordinates, so that the radius will vary across mip resolutions. + //float x = m_FilterRadius; + //float y = m_FilterRadius; + float x = m_TexelSize.x; + float y = m_TexelSize.y; + + // Take 9 samples around current texel: + // a - b - c + // d - e - f + // g - h - i + // === ('e' is the current texel) === + vec3 a = getColor(m_Texture, vec2(texCoord.x - x, texCoord.y + y)).rgb; + vec3 b = getColor(m_Texture, vec2(texCoord.x, texCoord.y + y)).rgb; + vec3 c = getColor(m_Texture, vec2(texCoord.x + x, texCoord.y + y)).rgb; + + vec3 d = getColor(m_Texture, vec2(texCoord.x - x, texCoord.y)).rgb; + vec3 e = getColor(m_Texture, vec2(texCoord.x, texCoord.y)).rgb; + vec3 f = getColor(m_Texture, vec2(texCoord.x + x, texCoord.y)).rgb; + + vec3 g = getColor(m_Texture, vec2(texCoord.x - x, texCoord.y - y)).rgb; + vec3 h = getColor(m_Texture, vec2(texCoord.x, texCoord.y - y)).rgb; + vec3 i = getColor(m_Texture, vec2(texCoord.x + x, texCoord.y - y)).rgb; + + // Apply weighted distribution, by using a 3x3 tent filter: + // 1 | 1 2 1 | + // -- * | 2 4 2 | + // 16 | 1 2 1 | + vec3 upsample = e*4.0; + upsample += (b+d+f+h)*2.0; + upsample += (a+c+g+i); + upsample /= 16.0; + + gl_FragColor = vec4(upsample, 1.0); + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.j3md new file mode 100644 index 0000000000..2ce2cc9976 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.j3md @@ -0,0 +1,23 @@ +MaterialDef Upsample { + + MaterialParameters { + Texture2D Texture + Vector2 TexelSize + Float FilterRadius : 0.01 + Int BoundDrawBuffer + Int NumSamples + } + + Technique { + VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Post/Post.vert + FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Post/Upsample.frag + + WorldParameters { + } + + Defines { + BOUND_DRAW_BUFFER: BoundDrawBuffer + RESOLVE_MS : NumSamples + } + } +} diff --git a/jme3-examples/src/main/java/jme3test/post/TestBloom.java b/jme3-examples/src/main/java/jme3test/post/TestBloom.java index faef6ac8e7..5608890801 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestBloom.java +++ b/jme3-examples/src/main/java/jme3test/post/TestBloom.java @@ -75,8 +75,6 @@ public void simpleInitApp() { mat.setColor("Diffuse", ColorRGBA.Yellow.mult(0.2f)); mat.setColor("Specular", ColorRGBA.Yellow.mult(0.8f)); - - Material matSoil = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md"); matSoil.setFloat("Shininess", 15f); diff --git a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java new file mode 100644 index 0000000000..479da377d4 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2009-2021 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 jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.asset.TextureKey; +import com.jme3.asset.plugins.FileLocator; +import com.jme3.environment.EnvironmentProbeControl; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.PBRBloomFilter; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.util.SkyFactory; +import com.jme3.util.SkyFactory.EnvMapType; + +public class TestPBRBloom extends SimpleApplication { + + private FilterPostProcessor fpp; + + public static void main(String[] args){ + TestPBRBloom app = new TestPBRBloom(); + app.start(); + } + + @Override + public void simpleInitApp() { + + assetManager.registerLocator("../jmonkeyengine/jme3-effects/src/main/resources", FileLocator.class); + assetManager.registerLocator("../jmonkeyengine/jme3-testdata/src/main/resources", FileLocator.class); + + // put the camera in a bad position + //cam.setLocation(new Vector3f(-2.336393f, 11.91392f, -7.139601f)); + //cam.setRotation(new Quaternion(0.23602544f, 0.11321983f, -0.027698677f, 0.96473104f)); + //cam.setFrustumFar(1000); + flyCam.setMoveSpeed(20); + + Material mat = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md"); + mat.setFloat("Shininess", 15f); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Ambient", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Diffuse", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Specular", ColorRGBA.Yellow.mult(0.8f)); + + + Material matSoil = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md"); + matSoil.setFloat("Shininess", 15f); + matSoil.setBoolean("UseMaterialColors", true); + matSoil.setColor("Ambient", ColorRGBA.Gray); + matSoil.setColor("Diffuse", ColorRGBA.Black); + matSoil.setColor("Specular", ColorRGBA.Gray); + + + Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + teapot.setLocalTranslation(0,0,10); + + teapot.setMaterial(mat); + teapot.setShadowMode(ShadowMode.CastAndReceive); + teapot.setLocalScale(10.0f); + rootNode.attachChild(teapot); + + Geometry soil = new Geometry("soil", new Box(800, 10, 700)); + soil.setLocalTranslation(0, -13, 550); + soil.setMaterial(matSoil); + soil.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(soil); + + Material tankMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md"); + tankMat.setTexture("BaseColorMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_diffuse.jpg", !true))); + tankMat.setTexture("SpecularMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_specular.jpg", !true))); + tankMat.setTexture("NormalMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_normals.png", !true))); + tankMat.setTexture("EmissiveMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_glow_map.jpg", !true))); + tankMat.setFloat("EmissivePower", 100); + tankMat.setFloat("EmissiveIntensity", 100); + tankMat.setFloat("Metallic", .5f); + Spatial tank = assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); + tank.setLocalTranslation(-10, 5, -10); + tank.setMaterial(tankMat); + rootNode.attachChild(tank); + + DirectionalLight light=new DirectionalLight(); + light.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + light.setColor(ColorRGBA.White); + //rootNode.addLight(light); + + PointLight pl = new PointLight(); + pl.setPosition(new Vector3f(5, 5, 5)); + pl.setRadius(1000); + pl.setColor(ColorRGBA.White); + rootNode.addLight(pl); + + // load sky + Spatial sky = SkyFactory.createSky(assetManager, + "Textures/Sky/Bright/FullskiesBlueClear03.dds", + EnvMapType.CubeMap); + sky.setCullHint(Spatial.CullHint.Never); + rootNode.attachChild(sky); + EnvironmentProbeControl.tagGlobal(sky); + + rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); + + fpp=new FilterPostProcessor(assetManager); + PBRBloomFilter bloom=new PBRBloomFilter(); + fpp.addFilter(bloom); + //ToneMapFilter toneMap = new ToneMapFilter(); + //fpp.addFilter(toneMap); + viewPort.addProcessor(fpp); + + } + + + +} From 902acd203f6df2d54e072df296a4e70389c91753 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 19 Mar 2024 11:50:46 -0400 Subject: [PATCH 02/18] add javadoc and license --- .../com/jme3/post/filters/PBRBloomFilter.java | 176 ++++++++++++++++-- .../Common/MatDefs/Post/PBRBloomFinal.frag | 3 +- .../Common/MatDefs/Post/PBRBloomFinal.j3md | 1 + .../Common/MatDefs/Post/Upsample.frag | 9 +- .../main/java/jme3test/post/TestPBRBloom.java | 3 +- 5 files changed, 166 insertions(+), 26 deletions(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java index e1952a06ca..cf742bed9a 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java @@ -1,23 +1,61 @@ /* - * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license - * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + * Copyright (c) 2024 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.FastMath; import com.jme3.math.Vector2f; import com.jme3.post.Filter; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; -import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; -import com.jme3.texture.Texture; import java.util.LinkedList; /** - * + * Adds a glow effect to the scene. + *

+ * Compared to {@link BloomFilter}, this filter produces much higher quality + * results that feel much more natural. + *

+ * This implementation, unlike BloomFilter, has no brightness threshold, + * meaning all aspects of the scene glow, although only very bright areas will + * noticably produce glow. For this reason, this filter should only be used + * if HDR is also being utilized, otherwise BloomFilter should be preferred. + *

+ * This filter uses the PBR bloom algorithm presented in + * this article. + * * @author codex */ public class PBRBloomFilter extends Filter { @@ -25,9 +63,51 @@ public class PBRBloomFilter extends Filter { private AssetManager assetManager; private RenderManager renderManager; private ViewPort viewPort; - private Pass[] downsamplingPasses = new Pass[4]; - private Pass[] upsamplingPasses = new Pass[4]; - private Image.Format format = Image.Format.RGBA16F; + private int width, height; + private Pass[] downsamplingPasses; + private Pass[] upsamplingPasses; + private final Image.Format format = Image.Format.RGBA16F; + private boolean initialized = false; + private int numSamplingPasses = 5; + private float glowFactor = 0.05f; + + /** + * Creates filter with default settings. + */ + public PBRBloomFilter() {} + + /** + * Creates filter with the given number of sampling passes. + * + * @param numSamplingPasses + * @see #setNumSamplingPasses(int) + */ + public PBRBloomFilter(int numSamplingPasses) { + this.numSamplingPasses = numSamplingPasses; + } + + /** + * Creates filter with given glow factor. + * + * @param glowFactor + * @see #setGlowFactor(float) + */ + public PBRBloomFilter(float glowFactor) { + this.glowFactor = glowFactor; + } + + /** + * Creates filter with the given number of sampling passes and the given glow factor. + * + * @param numSamplingPasses + * @param glowFactor + * @see #setNumSamplingPasses(int) + * @see #setGlowFactor(float) + */ + public PBRBloomFilter(int numSamplingPasses, float glowFactor) { + this.numSamplingPasses = numSamplingPasses; + this.glowFactor = glowFactor; + } @Override protected void initFilter(AssetManager am, RenderManager rm, ViewPort vp, int width, int height) { @@ -37,9 +117,11 @@ protected void initFilter(AssetManager am, RenderManager rm, ViewPort vp, int wi viewPort = vp; postRenderPasses = new LinkedList<>(); Renderer renderer = renderManager.getRenderer(); + int w = this.width = width; + int h = this.height = height; - int w = width; - int h = height; + downsamplingPasses = new Pass[numSamplingPasses]; + upsamplingPasses = new Pass[numSamplingPasses]; // downsampling passes Material downsampleMat = new Material(assetManager, "Common/MatDefs/Post/Downsample.j3md"); @@ -59,14 +141,12 @@ public void beforeRender() { postRenderPasses.add(initialPass); downsamplingPasses[0] = initialPass; for (int i = 1; i < downsamplingPasses.length; i++) { - int wi = w, hi = h; Vector2f texelSize = new Vector2f(1f/w, 1f/h); w /= 2; h /= 2; Pass prev = downsamplingPasses[i-1]; Pass pass = new Pass() { @Override public void beforeRender() { - //renderManager.getRenderer().setViewPort(0, 0, wi, hi); downsampleMat.setTexture("Texture", prev.getRenderedTexture()); downsampleMat.setVector2("TexelSize", texelSize); } @@ -79,7 +159,6 @@ public void beforeRender() { // upsampling passes Material upsampleMat = new Material(assetManager, "Common/MatDefs/Post/Upsample.j3md"); for (int i = 0; i < upsamplingPasses.length; i++) { - int wi = w, hi = h; Vector2f texelSize = new Vector2f(1f/w, 1f/h); w *= 2; h *= 2; Pass prev; @@ -91,7 +170,6 @@ public void beforeRender() { Pass pass = new Pass() { @Override public void beforeRender() { - //renderManager.getRenderer().setViewPort(0, 0, wi, hi); upsampleMat.setTexture("Texture", prev.getRenderedTexture()); upsampleMat.setVector2("TexelSize", texelSize); } @@ -104,14 +182,78 @@ public void beforeRender() { material = new Material(assetManager, "Common/MatDefs/Post/PBRBloomFinal.j3md"); material.setTexture("GlowMap", upsamplingPasses[upsamplingPasses.length-1].getRenderedTexture()); + initialized = true; + } + @Override protected Material getMaterial() { return material; } - @Override - protected void postFilter(Renderer r, FrameBuffer buffer) { - //renderManager.getRenderer().setV + + /** + * Sets the number of sampling passes in each step. + *

+ * Higher values produce more glow with higher resolution, at the cost + * of more passes. Lower values produce less glow with lower resolution. + *

+ * The total number of passes is {@code 2n+1}: n passes for downsampling + * (13 texture reads per pass per fragment), n passes for upsampling and blur + * (9 texture reads per pass per fragment), and 1 pass for blending (2 texture reads + * per fragment). Though, it should be noted that for each downsampling pass the + * number of fragments decreases by 75%, and for each upsampling pass, the number + * of fragments quadruples (which restores the number of fragments to the original + * resolution). + *

+ * Settings this after the filter has been initialized forces reinitialization. + *

+ * default=5 + * + * @param n number of passes per donwsampling/upsampling step + */ + public void setNumSamplingPasses(int n) { + numSamplingPasses = n; + if (initialized) { + initFilter(assetManager, renderManager, viewPort, width, height); + } + } + + /** + * Sets the factor at which the glow result texture is merged with + * the scene texture. + *

+ * Low values favor the scene texture more, while high values make + * glow more noticable. This value is clamped between 0 and 1. + *

+ * default=0.05f + * + * @param factor + */ + public void setGlowFactor(float factor) { + this.glowFactor = FastMath.clamp(factor, 0, 1); + if (material != null) { + material.setFloat("GlowFactor", glowFactor); + } + } + + /** + * Gets the number of downsampling/upsampling passes per step. + * + * @return glow factor + * @see #setNumSamplingPasses(int) + */ + public int getNumSamplingPasses() { + return numSamplingPasses; + } + + /** + * Gets the glow factor. + * + * @return glow factor + * @see #setGlowFactor(float) + */ + public float getGlowFactor() { + return glowFactor; } } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag index 7b54e9828d..20fb792cc3 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag @@ -4,11 +4,12 @@ uniform COLORTEXTURE m_Texture; uniform sampler2D m_GlowMap; +uniform float m_GlowFactor; varying vec2 texCoord; void main() { - gl_FragColor = mix(getColor(m_Texture, texCoord), texture2D(m_GlowMap, texCoord), 0.05); + gl_FragColor = mix(getColor(m_Texture, texCoord), texture2D(m_GlowMap, texCoord), m_GlowFactor); } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md index 10510cdcde..af610682fd 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md @@ -3,6 +3,7 @@ MaterialDef PBRBloomFinal { MaterialParameters { Texture2D Texture Texture2D GlowMap + Float GlowFactor : 0.05 Int BoundDrawBuffer Int NumSamples } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.frag index 897c55f04b..61bf280061 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/Upsample.frag @@ -3,7 +3,6 @@ #import "Common/ShaderLib/MultiSample.glsllib" uniform COLORTEXTURE m_Texture; -uniform float m_FilterRadius; uniform vec2 m_TexelSize; varying vec2 texCoord; @@ -13,8 +12,6 @@ void main() { // The filter kernel is applied with a radius, specified in texture // coordinates, so that the radius will vary across mip resolutions. - //float x = m_FilterRadius; - //float y = m_FilterRadius; float x = m_TexelSize.x; float y = m_TexelSize.y; @@ -36,9 +33,9 @@ void main() { vec3 i = getColor(m_Texture, vec2(texCoord.x + x, texCoord.y - y)).rgb; // Apply weighted distribution, by using a 3x3 tent filter: - // 1 | 1 2 1 | - // -- * | 2 4 2 | - // 16 | 1 2 1 | + // | 1 2 1 | + // 1/16 * | 2 4 2 | + // | 1 2 1 | vec3 upsample = e*4.0; upsample += (b+d+f+h)*2.0; upsample += (a+c+g+i); diff --git a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java index 479da377d4..4edc308221 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java +++ b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java @@ -83,9 +83,8 @@ public void simpleInitApp() { matSoil.setFloat("Shininess", 15f); matSoil.setBoolean("UseMaterialColors", true); matSoil.setColor("Ambient", ColorRGBA.Gray); - matSoil.setColor("Diffuse", ColorRGBA.Black); + matSoil.setColor("Diffuse", ColorRGBA.Gray); matSoil.setColor("Specular", ColorRGBA.Gray); - Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); teapot.setLocalTranslation(0,0,10); From 8d262b19e2ee13a1dd636db97065970b0517b6f9 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:04:24 -0400 Subject: [PATCH 03/18] documented and tweaked test --- .../main/java/jme3test/post/TestPBRBloom.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java index 4edc308221..ea26385bda 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java +++ b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2021 jMonkeyEngine + * Copyright (c) 2024 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,7 +34,6 @@ import com.jme3.app.SimpleApplication; import com.jme3.asset.TextureKey; -import com.jme3.asset.plugins.FileLocator; import com.jme3.environment.EnvironmentProbeControl; import com.jme3.light.DirectionalLight; import com.jme3.light.PointLight; @@ -50,6 +49,14 @@ import com.jme3.util.SkyFactory; import com.jme3.util.SkyFactory.EnvMapType; +/** + * Tests {@link PBRBloomFilter} with HDR. + *

+ * Note: the camera is pointed directly at the ground, which is completely + * black for some reason. + * + * @author codex + */ public class TestPBRBloom extends SimpleApplication { private FilterPostProcessor fpp; @@ -62,13 +69,7 @@ public static void main(String[] args){ @Override public void simpleInitApp() { - assetManager.registerLocator("../jmonkeyengine/jme3-effects/src/main/resources", FileLocator.class); - assetManager.registerLocator("../jmonkeyengine/jme3-testdata/src/main/resources", FileLocator.class); - - // put the camera in a bad position - //cam.setLocation(new Vector3f(-2.336393f, 11.91392f, -7.139601f)); - //cam.setRotation(new Quaternion(0.23602544f, 0.11321983f, -0.027698677f, 0.96473104f)); - //cam.setFrustumFar(1000); + cam.setLocation(new Vector3f(10, 10, 10)); flyCam.setMoveSpeed(20); Material mat = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md"); @@ -78,7 +79,6 @@ public void simpleInitApp() { mat.setColor("Diffuse", ColorRGBA.Yellow.mult(0.2f)); mat.setColor("Specular", ColorRGBA.Yellow.mult(0.8f)); - Material matSoil = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md"); matSoil.setFloat("Shininess", 15f); matSoil.setBoolean("UseMaterialColors", true); @@ -105,8 +105,8 @@ public void simpleInitApp() { tankMat.setTexture("SpecularMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_specular.jpg", !true))); tankMat.setTexture("NormalMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_normals.png", !true))); tankMat.setTexture("EmissiveMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_glow_map.jpg", !true))); - tankMat.setFloat("EmissivePower", 100); - tankMat.setFloat("EmissiveIntensity", 100); + tankMat.setFloat("EmissivePower", 50); + tankMat.setFloat("EmissiveIntensity", 50); tankMat.setFloat("Metallic", .5f); Spatial tank = assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); tank.setLocalTranslation(-10, 5, -10); From e6048406a36de535f8d4b31e1643366a5a1cd761 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:07:41 -0400 Subject: [PATCH 04/18] added exception --- .../src/main/java/com/jme3/post/filters/PBRBloomFilter.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java index cf742bed9a..1c6012f3c2 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java @@ -212,6 +212,9 @@ protected Material getMaterial() { * @param n number of passes per donwsampling/upsampling step */ public void setNumSamplingPasses(int n) { + if (n <= 0) { + throw new IllegalArgumentException("Expected number of sampling passes to be greater than zero (found: "+n+")."); + } numSamplingPasses = n; if (initialized) { initFilter(assetManager, renderManager, viewPort, width, height); From c5014f11bf4c7a13f5442be939737818071449b0 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:40:05 -0400 Subject: [PATCH 05/18] various formatting fixes --- .../com/jme3/post/filters/PBRBloomFilter.java | 70 ++++++++----------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java index 1c6012f3c2..4cd667aaa6 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java @@ -32,14 +32,20 @@ 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.FastMath; import com.jme3.math.Vector2f; import com.jme3.post.Filter; +import com.jme3.post.filters.BloomFilter.GlowMode; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; import com.jme3.texture.Image; +import java.io.IOException; import java.util.LinkedList; /** @@ -74,39 +80,8 @@ public class PBRBloomFilter extends Filter { /** * Creates filter with default settings. */ - public PBRBloomFilter() {} - - /** - * Creates filter with the given number of sampling passes. - * - * @param numSamplingPasses - * @see #setNumSamplingPasses(int) - */ - public PBRBloomFilter(int numSamplingPasses) { - this.numSamplingPasses = numSamplingPasses; - } - - /** - * Creates filter with given glow factor. - * - * @param glowFactor - * @see #setGlowFactor(float) - */ - public PBRBloomFilter(float glowFactor) { - this.glowFactor = glowFactor; - } - - /** - * Creates filter with the given number of sampling passes and the given glow factor. - * - * @param numSamplingPasses - * @param glowFactor - * @see #setNumSamplingPasses(int) - * @see #setGlowFactor(float) - */ - public PBRBloomFilter(int numSamplingPasses, float glowFactor) { - this.numSamplingPasses = numSamplingPasses; - this.glowFactor = glowFactor; + public PBRBloomFilter() { + super("PBRBloomFilter"); } @Override @@ -206,16 +181,15 @@ protected Material getMaterial() { * resolution). *

* Settings this after the filter has been initialized forces reinitialization. - *

- * default=5 + *

numSamplingPassesdefault=5 * - * @param n number of passes per donwsampling/upsampling step + * @param numSamplingPasses number of passes per donwsampling/upsampling step */ - public void setNumSamplingPasses(int n) { - if (n <= 0) { - throw new IllegalArgumentException("Expected number of sampling passes to be greater than zero (found: "+n+")."); + public void setNumSamplingPasses(int numSamplingPasses) { + if (numSamplingPasses <= 0) { + throw new IllegalArgumentException("Expected number of sampling passes to be greater than zero (found: " + numSamplingPasses + ")."); } - numSamplingPasses = n; + this.numSamplingPasses = numSamplingPasses; if (initialized) { initFilter(assetManager, renderManager, viewPort, width, height); } @@ -259,4 +233,20 @@ public float getGlowFactor() { return glowFactor; } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + oc.write(numSamplingPasses, "numSamplingPasses", 5); + oc.write(glowFactor, "glowFactor", 0.05f); + } + + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule ic = im.getCapsule(this); + numSamplingPasses = ic.readInt("numSamplingPasses", numSamplingPasses); + glowFactor = ic.readFloat("glowFactor", glowFactor); + } + } From 4b31f76f18f5fbee43181fe94f53710d3c3ac928 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:43:34 -0400 Subject: [PATCH 06/18] fixed javadoc typo --- .../java/com/jme3/post/filters/PBRBloomFilter.java | 2 +- .../src/main/java/jme3test/post/TestPBRBloom.java | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java index 4cd667aaa6..6aa6c3e889 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java @@ -216,7 +216,7 @@ public void setGlowFactor(float factor) { /** * Gets the number of downsampling/upsampling passes per step. * - * @return glow factor + * @return number of downsampling/upsampling passes * @see #setNumSamplingPasses(int) */ public int getNumSamplingPasses() { diff --git a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java index ea26385bda..e77a16c889 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java +++ b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java @@ -134,15 +134,11 @@ public void simpleInitApp() { rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); - fpp=new FilterPostProcessor(assetManager); - PBRBloomFilter bloom=new PBRBloomFilter(); + fpp = new FilterPostProcessor(assetManager); + PBRBloomFilter bloom = new PBRBloomFilter(); fpp.addFilter(bloom); - //ToneMapFilter toneMap = new ToneMapFilter(); - //fpp.addFilter(toneMap); viewPort.addProcessor(fpp); - + } - - - + } From 66dba26e3b4395423e50f43e9b344d7baa827460 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:48:49 -0400 Subject: [PATCH 07/18] fixed bug on applying glow factor --- .../src/main/java/com/jme3/post/filters/PBRBloomFilter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java index 6aa6c3e889..ef12a64850 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java @@ -156,6 +156,7 @@ public void beforeRender() { material = new Material(assetManager, "Common/MatDefs/Post/PBRBloomFinal.j3md"); material.setTexture("GlowMap", upsamplingPasses[upsamplingPasses.length-1].getRenderedTexture()); + material.setFloat("GlowFactor", glowFactor); initialized = true; From 60491c5d5fc6b61537ebe4a5c0b37afff99ef741 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 19 Mar 2024 17:27:01 -0400 Subject: [PATCH 08/18] fix javadoc typo --- .../src/main/java/com/jme3/post/filters/PBRBloomFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java index ef12a64850..640b742705 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java @@ -182,7 +182,8 @@ protected Material getMaterial() { * resolution). *

* Settings this after the filter has been initialized forces reinitialization. - *

numSamplingPassesdefault=5 + *

+ * default=5 * * @param numSamplingPasses number of passes per donwsampling/upsampling step */ From f563bb34c4bfc14b518101cc9cb6f9ac7f0e8e63 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 20 Mar 2024 07:49:44 -0400 Subject: [PATCH 09/18] fixed formatting issues --- .../com/jme3/post/filters/PBRBloomFilter.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java index 640b742705..c41b2a65ad 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java @@ -40,7 +40,6 @@ import com.jme3.math.FastMath; import com.jme3.math.Vector2f; import com.jme3.post.Filter; -import com.jme3.post.filters.BloomFilter.GlowMode; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; @@ -56,7 +55,7 @@ *

* This implementation, unlike BloomFilter, has no brightness threshold, * meaning all aspects of the scene glow, although only very bright areas will - * noticably produce glow. For this reason, this filter should only be used + * noticeably produce glow. For this reason, this filter should only be used * if HDR is also being utilized, otherwise BloomFilter should be preferred. *

* This filter uses the PBR bloom algorithm presented in @@ -69,9 +68,8 @@ public class PBRBloomFilter extends Filter { private AssetManager assetManager; private RenderManager renderManager; private ViewPort viewPort; - private int width, height; - private Pass[] downsamplingPasses; - private Pass[] upsamplingPasses; + private int width; + private int height; private final Image.Format format = Image.Format.RGBA16F; private boolean initialized = false; private int numSamplingPasses = 5; @@ -85,18 +83,18 @@ public PBRBloomFilter() { } @Override - protected void initFilter(AssetManager am, RenderManager rm, ViewPort vp, int width, int height) { + protected void initFilter(AssetManager am, RenderManager rm, ViewPort vp, int w, int h) { assetManager = am; renderManager = rm; viewPort = vp; postRenderPasses = new LinkedList<>(); Renderer renderer = renderManager.getRenderer(); - int w = this.width = width; - int h = this.height = height; + this.width = w; + this.height = h; - downsamplingPasses = new Pass[numSamplingPasses]; - upsamplingPasses = new Pass[numSamplingPasses]; + Pass[] downsamplingPasses = new Pass[numSamplingPasses]; + Pass[] upsamplingPasses = new Pass[numSamplingPasses]; // downsampling passes Material downsampleMat = new Material(assetManager, "Common/MatDefs/Post/Downsample.j3md"); @@ -185,11 +183,12 @@ protected Material getMaterial() { *

* default=5 * - * @param numSamplingPasses number of passes per donwsampling/upsampling step + * @param numSamplingPasses The number of passes per donwsampling/upsampling step. Must be greater than zero. + * @throws IllegalArgumentException if argument is less than or equal to zero */ public void setNumSamplingPasses(int numSamplingPasses) { if (numSamplingPasses <= 0) { - throw new IllegalArgumentException("Expected number of sampling passes to be greater than zero (found: " + numSamplingPasses + ")."); + throw new IllegalArgumentException("Number of sampling passes must be greater than zero (found: " + numSamplingPasses + ")."); } this.numSamplingPasses = numSamplingPasses; if (initialized) { @@ -202,7 +201,7 @@ public void setNumSamplingPasses(int numSamplingPasses) { * the scene texture. *

* Low values favor the scene texture more, while high values make - * glow more noticable. This value is clamped between 0 and 1. + * glow more noticeable. This value is clamped between 0 and 1. *

* default=0.05f * @@ -247,8 +246,8 @@ public void write(JmeExporter ex) throws IOException { public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule ic = im.getCapsule(this); - numSamplingPasses = ic.readInt("numSamplingPasses", numSamplingPasses); - glowFactor = ic.readFloat("glowFactor", glowFactor); + numSamplingPasses = ic.readInt("numSamplingPasses", 5); + glowFactor = ic.readFloat("glowFactor", 0.05f); } } From b0f1cdc83fc8d70a34cb879be76c94681be2497a Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 20 Mar 2024 20:57:34 -0400 Subject: [PATCH 10/18] switched texture min/mag filters --- .../src/main/java/com/jme3/post/filters/PBRBloomFilter.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java index c41b2a65ad..46d862b112 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java @@ -44,6 +44,7 @@ import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; import com.jme3.texture.Image; +import com.jme3.texture.Texture; import java.io.IOException; import java.util.LinkedList; @@ -125,6 +126,8 @@ public void beforeRender() { } }; pass.init(renderer, w, h, format, Image.Format.Depth, 1, downsampleMat); + pass.getRenderedTexture().setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + pass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear); postRenderPasses.add(pass); downsamplingPasses[i] = pass; } @@ -148,6 +151,8 @@ public void beforeRender() { } }; pass.init(renderer, w, h, format, Image.Format.Depth, 1, upsampleMat); + pass.getRenderedTexture().setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + pass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear); postRenderPasses.add(pass); upsamplingPasses[i] = pass; } From b91d9c675f0db0a108db6a50fcf48d2e0116efd8 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 20 Mar 2024 21:04:18 -0400 Subject: [PATCH 11/18] rename filter --- .../filters/{PBRBloomFilter.java => SoftBloomFilter.java} | 7 +++---- .../src/main/java/jme3test/post/TestPBRBloom.java | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) rename jme3-effects/src/main/java/com/jme3/post/filters/{PBRBloomFilter.java => SoftBloomFilter.java} (98%) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java similarity index 98% rename from jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java rename to jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java index 46d862b112..2c9c05239c 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/PBRBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java @@ -64,7 +64,7 @@ * * @author codex */ -public class PBRBloomFilter extends Filter { +public class SoftBloomFilter extends Filter { private AssetManager assetManager; private RenderManager renderManager; @@ -79,8 +79,8 @@ public class PBRBloomFilter extends Filter { /** * Creates filter with default settings. */ - public PBRBloomFilter() { - super("PBRBloomFilter"); + public SoftBloomFilter() { + super("SoftBloomFilter"); } @Override @@ -127,7 +127,6 @@ public void beforeRender() { }; pass.init(renderer, w, h, format, Image.Format.Depth, 1, downsampleMat); pass.getRenderedTexture().setMinFilter(Texture.MinFilter.BilinearNoMipMaps); - pass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear); postRenderPasses.add(pass); downsamplingPasses[i] = pass; } diff --git a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java index e77a16c889..4f20d5503a 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java +++ b/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java @@ -41,7 +41,7 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; -import com.jme3.post.filters.PBRBloomFilter; +import com.jme3.post.filters.SoftBloomFilter; import com.jme3.renderer.queue.RenderQueue.ShadowMode; import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; @@ -50,7 +50,7 @@ import com.jme3.util.SkyFactory.EnvMapType; /** - * Tests {@link PBRBloomFilter} with HDR. + * Tests {@link SoftBloomFilter} with HDR. *

* Note: the camera is pointed directly at the ground, which is completely * black for some reason. @@ -135,7 +135,7 @@ public void simpleInitApp() { rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); fpp = new FilterPostProcessor(assetManager); - PBRBloomFilter bloom = new PBRBloomFilter(); + SoftBloomFilter bloom = new SoftBloomFilter(); fpp.addFilter(bloom); viewPort.addProcessor(fpp); From 7cf0ea9722e48b3b03cbca3034a26b9405de424c Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 20 Mar 2024 21:07:51 -0400 Subject: [PATCH 12/18] rename filter --- .../src/main/java/com/jme3/post/filters/SoftBloomFilter.java | 1 - .../jme3test/post/{TestPBRBloom.java => TestSoftBloom.java} | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) rename jme3-examples/src/main/java/jme3test/post/{TestPBRBloom.java => TestSoftBloom.java} (98%) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java index 2c9c05239c..da300fb260 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java @@ -150,7 +150,6 @@ public void beforeRender() { } }; pass.init(renderer, w, h, format, Image.Format.Depth, 1, upsampleMat); - pass.getRenderedTexture().setMinFilter(Texture.MinFilter.BilinearNoMipMaps); pass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear); postRenderPasses.add(pass); upsamplingPasses[i] = pass; diff --git a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java b/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java similarity index 98% rename from jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java rename to jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java index 4f20d5503a..45282b9c7a 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestPBRBloom.java +++ b/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java @@ -57,12 +57,12 @@ * * @author codex */ -public class TestPBRBloom extends SimpleApplication { +public class TestSoftBloom extends SimpleApplication { private FilterPostProcessor fpp; public static void main(String[] args){ - TestPBRBloom app = new TestPBRBloom(); + TestSoftBloom app = new TestSoftBloom(); app.start(); } From eb2efbf37e0833d5ec520547b62bce1c1bb8357c Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:10:27 -0400 Subject: [PATCH 13/18] improved test and capped number of passes --- .../jme3/post/filters/SoftBloomFilter.java | 101 +++++++++++++-- .../java/jme3test/post/TestSoftBloom.java | 115 +++++++++++++++++- 2 files changed, 199 insertions(+), 17 deletions(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java index da300fb260..40aec264ff 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java @@ -46,6 +46,8 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture; import java.io.IOException; +import java.util.logging.Logger; +import java.util.logging.Level; import java.util.LinkedList; /** @@ -66,15 +68,20 @@ */ public class SoftBloomFilter extends Filter { + private static final Logger logger = Logger.getLogger(SoftBloomFilter.class.getName()); + private AssetManager assetManager; private RenderManager renderManager; private ViewPort viewPort; private int width; private int height; + private Pass[] downsamplingPasses; + private Pass[] upsamplingPasses; private final Image.Format format = Image.Format.RGBA16F; private boolean initialized = false; private int numSamplingPasses = 5; private float glowFactor = 0.05f; + private boolean bilinearFiltering = true; /** * Creates filter with default settings. @@ -94,13 +101,15 @@ protected void initFilter(AssetManager am, RenderManager rm, ViewPort vp, int w, this.width = w; this.height = h; - Pass[] downsamplingPasses = new Pass[numSamplingPasses]; - Pass[] upsamplingPasses = new Pass[numSamplingPasses]; + capPassesToSize(w, h); + + downsamplingPasses = new Pass[numSamplingPasses]; + upsamplingPasses = new Pass[numSamplingPasses]; // downsampling passes Material downsampleMat = new Material(assetManager, "Common/MatDefs/Post/Downsample.j3md"); Vector2f initTexelSize = new Vector2f(1f/w, 1f/h); - w /= 2; h /= 2; + w = w >> 1; h = h >> 1; Pass initialPass = new Pass() { @Override public boolean requiresSceneAsTexture() { @@ -116,7 +125,7 @@ public void beforeRender() { downsamplingPasses[0] = initialPass; for (int i = 1; i < downsamplingPasses.length; i++) { Vector2f texelSize = new Vector2f(1f/w, 1f/h); - w /= 2; h /= 2; + w = w >> 1; h = h >> 1; Pass prev = downsamplingPasses[i-1]; Pass pass = new Pass() { @Override @@ -126,7 +135,9 @@ public void beforeRender() { } }; pass.init(renderer, w, h, format, Image.Format.Depth, 1, downsampleMat); - pass.getRenderedTexture().setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + if (bilinearFiltering) { + pass.getRenderedTexture().setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + } postRenderPasses.add(pass); downsamplingPasses[i] = pass; } @@ -135,7 +146,7 @@ public void beforeRender() { Material upsampleMat = new Material(assetManager, "Common/MatDefs/Post/Upsample.j3md"); for (int i = 0; i < upsamplingPasses.length; i++) { Vector2f texelSize = new Vector2f(1f/w, 1f/h); - w *= 2; h *= 2; + w = w << 1; h = h << 1; Pass prev; if (i == 0) { prev = downsamplingPasses[downsamplingPasses.length-1]; @@ -150,7 +161,9 @@ public void beforeRender() { } }; pass.init(renderer, w, h, format, Image.Format.Depth, 1, upsampleMat); - pass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear); + if (bilinearFiltering) { + pass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear); + } postRenderPasses.add(pass); upsamplingPasses[i] = pass; } @@ -182,7 +195,7 @@ protected Material getMaterial() { * of fragments quadruples (which restores the number of fragments to the original * resolution). *

- * Settings this after the filter has been initialized forces reinitialization. + * Setting this after the filter has been initialized forces reinitialization. *

* default=5 * @@ -193,9 +206,11 @@ public void setNumSamplingPasses(int numSamplingPasses) { if (numSamplingPasses <= 0) { throw new IllegalArgumentException("Number of sampling passes must be greater than zero (found: " + numSamplingPasses + ")."); } - this.numSamplingPasses = numSamplingPasses; - if (initialized) { - initFilter(assetManager, renderManager, viewPort, width, height); + if (this.numSamplingPasses != numSamplingPasses) { + this.numSamplingPasses = numSamplingPasses; + if (initialized) { + initFilter(assetManager, renderManager, viewPort, width, height); + } } } @@ -217,6 +232,39 @@ public void setGlowFactor(float factor) { } } + /** + * Sets pass textures to use bilinear filtering. + *

+ * If true, downsampling textures are set to {@code min=BilinearNoMipMaps} and + * upsampling textures are set to {@code mag=Bilinear}, which produces better + * quality glow. If false, textures use their default filters. + *

+ * default=true + * + * @param bilinearFiltering true to use bilinear filtering + */ + public void setBilinearFiltering(boolean bilinearFiltering) { + if (this.bilinearFiltering != bilinearFiltering) { + this.bilinearFiltering = bilinearFiltering; + if (initialized) { + for (Pass p : downsamplingPasses) { + if (this.bilinearFiltering) { + p.getRenderedTexture().setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + } else { + p.getRenderedTexture().setMinFilter(Texture.MinFilter.NearestNoMipMaps); + } + } + for (Pass p : upsamplingPasses) { + if (this.bilinearFiltering) { + p.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear); + } else { + p.getRenderedTexture().setMagFilter(Texture.MagFilter.Nearest); + } + } + } + } + } + /** * Gets the number of downsampling/upsampling passes per step. * @@ -237,6 +285,37 @@ public float getGlowFactor() { return glowFactor; } + /** + * Returns true if pass textures use bilinear filtering. + * + * @return + * @see #setBilinearFiltering(boolean) + */ + public boolean isBilinearFiltering() { + return bilinearFiltering; + } + + /** + * Caps the number of sampling passes so that texture size does + * not go below 1 on any axis. + *

+ * A message will be logged if the number of sampling passes is changed. + * + * @param w texture width + * @param h texture height + */ + private void capPassesToSize(int w, int h) { + int limit = Math.min(w, h); + for (int i = 0; i < numSamplingPasses; i++) { + limit = limit >> 1; + if (limit <= 0) { + numSamplingPasses = i; + logger.log(Level.INFO, "Number of sampling passes capped at {0} due to texture size.", i); + break; + } + } + } + @Override public void write(JmeExporter ex) throws IOException { super.write(ex); diff --git a/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java b/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java index 45282b9c7a..0c27920b5f 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java +++ b/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java @@ -35,6 +35,11 @@ import com.jme3.app.SimpleApplication; import com.jme3.asset.TextureKey; import com.jme3.environment.EnvironmentProbeControl; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.KeyTrigger; import com.jme3.light.DirectionalLight; import com.jme3.light.PointLight; import com.jme3.material.Material; @@ -57,9 +62,16 @@ * * @author codex */ -public class TestSoftBloom extends SimpleApplication { +public class TestSoftBloom extends SimpleApplication implements ActionListener, AnalogListener { - private FilterPostProcessor fpp; + private SoftBloomFilter bloom; + private BitmapText passes, factor, bilinear; + private BitmapText power, intensity; + private Material tankMat; + private float emissionPower = 50; + private float emissionIntensity = 50; + private final int maxPasses = 10; + private final float factorRate = 0.1f; public static void main(String[] args){ TestSoftBloom app = new TestSoftBloom(); @@ -100,12 +112,12 @@ public void simpleInitApp() { soil.setShadowMode(ShadowMode.CastAndReceive); rootNode.attachChild(soil); - Material tankMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md"); + tankMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md"); tankMat.setTexture("BaseColorMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_diffuse.jpg", !true))); tankMat.setTexture("SpecularMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_specular.jpg", !true))); tankMat.setTexture("NormalMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_normals.png", !true))); tankMat.setTexture("EmissiveMap", assetManager.loadTexture(new TextureKey("Models/HoverTank/tank_glow_map.jpg", !true))); - tankMat.setFloat("EmissivePower", 50); + tankMat.setFloat("EmissivePower", emissionPower); tankMat.setFloat("EmissiveIntensity", 50); tankMat.setFloat("Metallic", .5f); Spatial tank = assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); @@ -134,11 +146,102 @@ public void simpleInitApp() { rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); - fpp = new FilterPostProcessor(assetManager); - SoftBloomFilter bloom = new SoftBloomFilter(); + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + bloom = new SoftBloomFilter(); fpp.addFilter(bloom); viewPort.addProcessor(fpp); + int textY = context.getSettings().getHeight()-5; + float xRow1 = 10, xRow2 = 250; + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + passes = createText("", xRow1, textY); + createText("[ R / F ]", xRow2, textY); + factor = createText("", xRow1, textY-25); + createText("[ T / G ]", xRow2, textY-25); + bilinear = createText("", xRow1, textY-25*2); + createText("[ space ]", xRow2, textY-25*2); + power = createText("", xRow1, textY-25*3); + createText("[ Y / H ]", xRow2, textY-25*3); + intensity = createText("", xRow1, textY-25*4); + createText("[ U / J ]", xRow2, textY-25*4); + updateHud(); + + inputManager.addMapping("incr-passes", new KeyTrigger(KeyInput.KEY_R)); + inputManager.addMapping("decr-passes", new KeyTrigger(KeyInput.KEY_F)); + inputManager.addMapping("incr-factor", new KeyTrigger(KeyInput.KEY_T)); + inputManager.addMapping("decr-factor", new KeyTrigger(KeyInput.KEY_G)); + inputManager.addMapping("toggle-bilinear", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("incr-power", new KeyTrigger(KeyInput.KEY_Y)); + inputManager.addMapping("decr-power", new KeyTrigger(KeyInput.KEY_H)); + inputManager.addMapping("incr-intensity", new KeyTrigger(KeyInput.KEY_U)); + inputManager.addMapping("decr-intensity", new KeyTrigger(KeyInput.KEY_J)); + inputManager.addListener(this, "incr-passes", "decr-passes", "incr-factor", "decr-factor", + "toggle-bilinear", "incr-power", "decr-power", "incr-intensity", "decr-intensity"); + + } + @Override + public void simpleUpdate(float tpf) { + updateHud(); + } + @Override + public void onAction(String name, boolean isPressed, float tpf) { + if (isPressed) { + if (name.equals("incr-passes")) { + bloom.setNumSamplingPasses(Math.min(bloom.getNumSamplingPasses()+1, maxPasses)); + } else if (name.equals("decr-passes")) { + bloom.setNumSamplingPasses(Math.max(bloom.getNumSamplingPasses()-1, 1)); + } else if (name.equals("toggle-bilinear")) { + bloom.setBilinearFiltering(!bloom.isBilinearFiltering()); + } + updateHud(); + } + } + @Override + public void onAnalog(String name, float value, float tpf) { + if (name.equals("incr-factor")) { + bloom.setGlowFactor(bloom.getGlowFactor()+factorRate*tpf); + } else if (name.equals("decr-factor")) { + bloom.setGlowFactor(bloom.getGlowFactor()-factorRate*tpf); + } else if (name.equals("incr-power")) { + emissionPower += 10f*tpf; + updateTankMaterial(); + } else if (name.equals("decr-power")) { + emissionPower -= 10f*tpf; + updateTankMaterial(); + } else if (name.equals("incr-intensity")) { + emissionIntensity += 10f*tpf; + updateTankMaterial(); + } else if (name.equals("decr-intensity")) { + emissionIntensity -= 10f*tpf; + updateTankMaterial(); + } + updateHud(); + } + + private BitmapText createText(String string, float x, float y) { + BitmapText text = new BitmapText(guiFont); + text.setSize(guiFont.getCharSet().getRenderedSize()); + text.setLocalTranslation(x, y, 0); + text.setText(string); + guiNode.attachChild(text); + return text; + } + private void updateHud() { + passes.setText("Passes = " + bloom.getNumSamplingPasses()); + factor.setText("Glow Factor = " + floatToString(bloom.getGlowFactor(), 5)); + bilinear.setText("Bilinear Filtering = " + bloom.isBilinearFiltering()); + power.setText("Emission Power = " + floatToString(emissionPower, 5)); + intensity.setText("Emission Intensity = " + floatToString(emissionIntensity, 5)); + } + private String floatToString(float value, int length) { + String string = Float.toString(value); + return string.substring(0, Math.min(length, string.length())); + } + private void updateTankMaterial() { + emissionPower = Math.max(emissionPower, 0); + emissionIntensity = Math.max(emissionIntensity, 0); + tankMat.setFloat("EmissivePower", emissionPower); + tankMat.setFloat("EmissiveIntensity", emissionIntensity); } } From 23cf55429cf3b8412fcd3dbdf9a365c51a6874ed Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:17:25 -0400 Subject: [PATCH 14/18] reformat test --- .../src/main/java/jme3test/post/TestSoftBloom.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java b/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java index 0c27920b5f..e277e8f943 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java +++ b/jme3-examples/src/main/java/jme3test/post/TestSoftBloom.java @@ -179,10 +179,12 @@ public void simpleInitApp() { "toggle-bilinear", "incr-power", "decr-power", "incr-intensity", "decr-intensity"); } + @Override public void simpleUpdate(float tpf) { updateHud(); } + @Override public void onAction(String name, boolean isPressed, float tpf) { if (isPressed) { @@ -196,6 +198,7 @@ public void onAction(String name, boolean isPressed, float tpf) { updateHud(); } } + @Override public void onAnalog(String name, float value, float tpf) { if (name.equals("incr-factor")) { @@ -226,6 +229,7 @@ private BitmapText createText(String string, float x, float y) { guiNode.attachChild(text); return text; } + private void updateHud() { passes.setText("Passes = " + bloom.getNumSamplingPasses()); factor.setText("Glow Factor = " + floatToString(bloom.getGlowFactor(), 5)); @@ -233,10 +237,12 @@ private void updateHud() { power.setText("Emission Power = " + floatToString(emissionPower, 5)); intensity.setText("Emission Intensity = " + floatToString(emissionIntensity, 5)); } + private String floatToString(float value, int length) { String string = Float.toString(value); return string.substring(0, Math.min(length, string.length())); } + private void updateTankMaterial() { emissionPower = Math.max(emissionPower, 0); emissionIntensity = Math.max(emissionIntensity, 0); From ab8121f356e86814288bd8063d9ebd924e92e2b7 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:51:30 -0400 Subject: [PATCH 15/18] serialize bilinear filtering --- .../jme3/post/filters/SoftBloomFilter.java | 2 ++ .../resources/Common/MatDefs/Post/Cel.frag | 15 ++++++++++ .../resources/Common/MatDefs/Post/Cel.j3md | 28 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.j3md diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java index 40aec264ff..8abac5cde5 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java @@ -322,6 +322,7 @@ public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this); oc.write(numSamplingPasses, "numSamplingPasses", 5); oc.write(glowFactor, "glowFactor", 0.05f); + oc.write(bilinearFiltering, "bilinearFiltering", true); } @Override @@ -330,6 +331,7 @@ public void read(JmeImporter im) throws IOException { InputCapsule ic = im.getCapsule(this); numSamplingPasses = ic.readInt("numSamplingPasses", 5); glowFactor = ic.readFloat("glowFactor", 0.05f); + bilinearFiltering = ic.readBoolean("bilinearFiltering", true); } } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.frag new file mode 100644 index 0000000000..753c4db4f7 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.frag @@ -0,0 +1,15 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" +#import "Common/ShaderLib/MultiSample.glsllib" + +uniform COLORTEXTURE m_Texture; +uniform sampler2D m_ColorRamp; +varying vec2 texCoord; + +uniform float m_Value; + +void main() { + + vec4 texVal = getColor(m_Texture, texCoord); + gl_FragColor = texVal * m_Value; + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.j3md new file mode 100644 index 0000000000..b6267326a0 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.j3md @@ -0,0 +1,28 @@ +MaterialDef Fade { + + MaterialParameters { + Int BoundDrawBuffer + Int NumSamples + Int NumSamplesDepth + Texture2D Texture + Texture2D DepthTexture + Vector4 FogColor; + Float FogDensity; + Float FogDistance; + } + + Technique { + VertexShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Post/Post.vert + FragmentShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Post/Fog.frag + + WorldParameters { + } + + Defines { + BOUND_DRAW_BUFFER: BoundDrawBuffer + RESOLVE_MS : NumSamples + RESOLVE_DEPTH_MS : NumSamplesDepth + } + } + +} \ No newline at end of file From 2b45ec07ba47b02e7f23ac0371d9292e60426fbd Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:52:14 -0400 Subject: [PATCH 16/18] delete unrelated files --- .../resources/Common/MatDefs/Post/Cel.frag | 15 ---------- .../resources/Common/MatDefs/Post/Cel.j3md | 28 ------------------- 2 files changed, 43 deletions(-) delete mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.frag delete mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.j3md diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.frag deleted file mode 100644 index 753c4db4f7..0000000000 --- a/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.frag +++ /dev/null @@ -1,15 +0,0 @@ -#import "Common/ShaderLib/GLSLCompat.glsllib" -#import "Common/ShaderLib/MultiSample.glsllib" - -uniform COLORTEXTURE m_Texture; -uniform sampler2D m_ColorRamp; -varying vec2 texCoord; - -uniform float m_Value; - -void main() { - - vec4 texVal = getColor(m_Texture, texCoord); - gl_FragColor = texVal * m_Value; - -} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.j3md deleted file mode 100644 index b6267326a0..0000000000 --- a/jme3-effects/src/main/resources/Common/MatDefs/Post/Cel.j3md +++ /dev/null @@ -1,28 +0,0 @@ -MaterialDef Fade { - - MaterialParameters { - Int BoundDrawBuffer - Int NumSamples - Int NumSamplesDepth - Texture2D Texture - Texture2D DepthTexture - Vector4 FogColor; - Float FogDensity; - Float FogDistance; - } - - Technique { - VertexShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Post/Post.vert - FragmentShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Post/Fog.frag - - WorldParameters { - } - - Defines { - BOUND_DRAW_BUFFER: BoundDrawBuffer - RESOLVE_MS : NumSamples - RESOLVE_DEPTH_MS : NumSamplesDepth - } - } - -} \ No newline at end of file From 5ad4d7c61684d0754cfce5107d4e138e9c7d44c2 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 22 Mar 2024 14:12:38 -0400 Subject: [PATCH 17/18] increase size limit to 2 --- .../src/main/java/com/jme3/post/filters/SoftBloomFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java index 8abac5cde5..40b62dd9eb 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java @@ -308,7 +308,7 @@ private void capPassesToSize(int w, int h) { int limit = Math.min(w, h); for (int i = 0; i < numSamplingPasses; i++) { limit = limit >> 1; - if (limit <= 0) { + if (limit <= 2) { numSamplingPasses = i; logger.log(Level.INFO, "Number of sampling passes capped at {0} due to texture size.", i); break; From 11559c17d963460b1bc2a1d962d3622185698a35 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 23 Mar 2024 14:36:45 -0400 Subject: [PATCH 18/18] renamed shaders --- .../src/main/java/com/jme3/post/filters/SoftBloomFilter.java | 2 +- .../MatDefs/Post/{PBRBloomFinal.frag => SoftBloomFinal.frag} | 0 .../MatDefs/Post/{PBRBloomFinal.j3md => SoftBloomFinal.j3md} | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename jme3-effects/src/main/resources/Common/MatDefs/Post/{PBRBloomFinal.frag => SoftBloomFinal.frag} (100%) rename jme3-effects/src/main/resources/Common/MatDefs/Post/{PBRBloomFinal.j3md => SoftBloomFinal.j3md} (95%) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java index 40b62dd9eb..3ccbf03ff9 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java @@ -168,7 +168,7 @@ public void beforeRender() { upsamplingPasses[i] = pass; } - material = new Material(assetManager, "Common/MatDefs/Post/PBRBloomFinal.j3md"); + material = new Material(assetManager, "Common/MatDefs/Post/SoftBloomFinal.j3md"); material.setTexture("GlowMap", upsamplingPasses[upsamplingPasses.length-1].getRenderedTexture()); material.setFloat("GlowFactor", glowFactor); diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/SoftBloomFinal.frag similarity index 100% rename from jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.frag rename to jme3-effects/src/main/resources/Common/MatDefs/Post/SoftBloomFinal.frag diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/SoftBloomFinal.j3md similarity index 95% rename from jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md rename to jme3-effects/src/main/resources/Common/MatDefs/Post/SoftBloomFinal.j3md index af610682fd..d0597f9f9b 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/Post/PBRBloomFinal.j3md +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/SoftBloomFinal.j3md @@ -10,7 +10,7 @@ MaterialDef PBRBloomFinal { Technique { VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Post/Post.vert - FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Post/PBRBloomFinal.frag + FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Post/SoftBloomFinal.frag WorldParameters { }