From 8261abe06febe4b9e6acdde1980823af0835b07b Mon Sep 17 00:00:00 2001 From: rickard Date: Sat, 13 Jul 2019 08:55:29 +0200 Subject: [PATCH 01/20] fixes for ssr filter --- .../java/com/jme3/post/filters/SsrFilter.java | 269 +++++++++++ .../resources/Common/MatDefs/SSR/ssr.frag | 454 ++++++++++++++++++ .../resources/Common/MatDefs/SSR/ssr.j3md | 74 +++ .../resources/Common/MatDefs/SSR/ssr.vert | 10 + .../resources/Common/MatDefs/SSR/ssrBlur.frag | 105 ++++ .../resources/Common/MatDefs/SSR/ssrBlur.j3md | 37 ++ 6 files changed, 949 insertions(+) create mode 100644 jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.vert create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.j3md diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java new file mode 100644 index 0000000000..0e31d97090 --- /dev/null +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2009-2019 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.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.post.Filter; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.texture.Image; +import java.util.ArrayList; + +/** + * Based on Riccardo Balbo's SSR shader for jMonkeyEngine: https://github.com/riccardobl/SimpleSSRShader + * @author rickard + */ +public class SsrFilter extends Filter{ + + private Vector2f frustumNearFar; + private Vector3f frustumCorner; + + private RenderManager renderManager; + private ViewPort viewPort; + private Pass normalPass; + private Pass ssrPass; + private boolean approximateNormals = false; + private float downSampleFactor = 1f; + + private Material ssrMaterial; + private boolean fastBlur = false; + private int raySteps = 16; + private boolean sampleNearby = true; + private float stepLength = 1.0f; + private float blurScale = 1f; + private float sigma = 5f; + private float reflectionFactor = 1f; + + + public SsrFilter(){ + super("SSR Filter"); + } + + @Override + protected boolean isRequiresDepthTexture() { + return true; + } + + @Override + protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { + + this.renderManager = renderManager; + this.viewPort = vp; + int screenWidth = w; + int screenHeight = h; + postRenderPasses = new ArrayList<>(); + + + frustumNearFar = new Vector2f(); + + float farY = (vp.getCamera().getFrustumTop() / vp.getCamera().getFrustumNear()) * vp.getCamera().getFrustumFar(); + float farX = farY * ((float) screenWidth / (float) screenHeight); + frustumCorner = new Vector3f(farX, farY, vp.getCamera().getFrustumFar()); + frustumNearFar.x = vp.getCamera().getFrustumNear(); + frustumNearFar.y = vp.getCamera().getFrustumFar(); + + + //if(!approximateNormals){ + normalPass = new Pass(); + normalPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Image.Format.RGBA8, Image.Format.Depth); + //} + + ssrMaterial = new Material(manager, "Common/MatDefs/SSR/ssr.j3md"); + ssrMaterial.setVector3("FrustumCorner", frustumCorner); + //if(!approximateNormals){ + ssrMaterial.setTexture("Normals", normalPass.getRenderedTexture()); + //} + ssrMaterial.setInt("RaySamples", raySteps); + ssrMaterial.setInt("NearbySamples", sampleNearby ? 4 : 0); + ssrMaterial.setFloat("StepLength", stepLength); + ssrMaterial.setFloat("ReflectionFactor", reflectionFactor); + + + ssrPass = new Pass("SSR pass") { + + @Override + public boolean requiresDepthAsTexture() { + return true; + } + + @Override + public boolean requiresSceneAsTexture() { + return true; //To change body of generated methods, choose Tools | Templates. + } + + + }; + + ssrPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Image.Format.RGBA8, Image.Format.Depth, 1, ssrMaterial); + postRenderPasses.add(ssrPass); + + material = new Material(manager, "Common/MatDefs/SSR/ssrBlur.j3md"); + material.setTexture("SSR", ssrPass.getRenderedTexture()); + material.setBoolean("Horizontal", true); + material.setBoolean("FastBlur", fastBlur); + material.setFloat("BlurScale", blurScale); + material.setFloat("Sigma", sigma); + +} + + @Override + protected void postQueue(RenderQueue queue) { + if(!approximateNormals) { + Renderer r = renderManager.getRenderer(); + r.setFrameBuffer(normalPass.getRenderFrameBuffer()); + renderManager.getRenderer().clearBuffers(true, true, true); + renderManager.setForcedTechnique("PreNormalPass"); + renderManager.renderViewPortQueues(viewPort, false); + renderManager.setForcedTechnique(null); + renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer()); + } + } + + @Override + protected void cleanUpFilter(Renderer r) { + normalPass.cleanup(r); + } + + @Override + protected Material getMaterial() { + return material; + } + + /** + * If true, any passed normals won't be used. Instead they will be approximated using the depth map + * @param approximateNormals + */ + public void setApproximateNormals(boolean approximateNormals) { + this.approximateNormals = approximateNormals; + if(ssrMaterial != null){ + ssrMaterial.setBoolean("ApproximateNormals", approximateNormals); + } + } + + /** + * Value to scale (down) the textures the filter uses. + * @param downSampleFactor + */ + public void setDownSampleFactor(float downSampleFactor) { + this.downSampleFactor = downSampleFactor; + } + + /** + * Using a faster blur function in the blur pass. Default false + * @param fastBlur + */ + public void setFastBlur(boolean fastBlur) { + this.fastBlur = fastBlur; + if(material != null){ + material.setBoolean("FastBlur", fastBlur); + } + } + + /** + * Amount of steps + * @param raySteps + */ + public void setRaySteps(int raySteps) { + this.raySteps = raySteps; + if(ssrMaterial != null){ + ssrMaterial.setInt("RaySamples", raySteps); + } + } + + /** + * Whether to sample nearby ray hits for better accuracy + * @param sampleNearby + */ + public void setSampleNearby(boolean sampleNearby) { + this.sampleNearby = sampleNearby; + if(ssrMaterial != null){ + ssrMaterial.setInt("NearbySamples", sampleNearby ? 4 : 0); + } + } + + /** + * Length of each ray step + * @param stepLength + */ + public void setStepLength(float stepLength) { + this.stepLength = stepLength; + if(ssrMaterial != null){ + ssrMaterial.setFloat("StepLength", stepLength); + } + } + + /** + * Scale for blur. Only used if fastBlur is true + * @param blurScale + */ + public void setBlurScale(float blurScale) { + this.blurScale = blurScale; + if(material != null){ + material.setFloat("BlurScale", blurScale); + } + } + + /** + * Sigma for regular gaussian blur. Only used if fastBlur is false + * @param sigma + */ + public void setSigma(float sigma) { + this.sigma = sigma; + if(material != null){ + material.setFloat("Sigma", sigma); + } + } + + public float getReflectionFactor() { + return reflectionFactor; + } + + /** + * Sets the overall reflection amount. Scales between 0 and 1 + * @param reflectionFactor + */ + public void setReflectionFactor(float reflectionFactor) { + this.reflectionFactor = reflectionFactor; + if(ssrMaterial != null){ + ssrMaterial.setFloat("ReflectionFactor", reflectionFactor); + } + } + + + + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag new file mode 100644 index 0000000000..c397b60750 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag @@ -0,0 +1,454 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" + +#import "Common/ShaderLib/MultiSample.glsllib" +/** +####################### +# Simple SSR shader +####################### + +Copyright (c) 2019, Riccardo Balbo +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder 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 HOLDER 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. +*/ + +/// ########### SETTINGS (most of these are setted by the material) ########### +//// +//// # GENERAL +//// Use dFdx and dFdy instead of multiple samples +#define FAST_APPROXIMATIONS 0 +//// Read only XY from normal map and generate Z +// #define RG_NORMAL_MAP 1 +//// Read glossiness from Z component of the normal map (works with RG_NORMAL_MAP) +// #define GLOSSINESS_PACKET_IN_NORMAL_B 1 +//// Aproximate surface normals from the depth buffer +// #define USE_APPROXIMATED_NORMALS 1 +//// Approximate glossiness from the normal map +// #define USE_APPROXIMATED_GLOSSINESS 1 +//// +//// # RAYMARCHING +//// How many samples along the ray +// #define RAY_SAMPLES 16 +//// How many samples around the hit position +// #define NEARBY_SAMPLES 4 // 0 to 4 , 0 to disable +//// Length of first sample in world space +//// Size of a pixel used by NEARBY_SAMPLES +#define PIXEL_SIZE_MULT 1. +//// A depth difference equals or below this will be considered 0 +#define DEPTH_TEST_BIAS 0.00001 +//// +//// # DEBUG +// #define _ENABLE_TESTS 1 +// #define _TEST_CONVERSIONS 1 +// #define _TEST_SHOW_WPOS 1 +// #define _TEST_SHOW_SCREEN_Z 1 +// #define _TEST_SHOW_LINEAR_Z 1 +// #define _TEST_SHOW_APROXIMATED_GLOSS 1 +// #define _TEST_SHOW_RAY_GLOSS +///// ########### ########### ########### + + +#ifndef SCENE_NORMALS + // If normal map is not provided, fallback to normal approximation + #define USE_APPROXIMATED_NORMALS 1 + #undef USE_APPROXIMATED_GLOSSINESS +#else + uniform sampler2D m_Normals; +#endif + +#if defined(RG_NORMAL_MAP) && !defined(GLOSSINESS_PACKET_IN_NORMAL_B) + // If glossiness is not provided, fallback to glossiness approximation + #define USE_APPROXIMATED_GLOSSINESS 1 +#endif + +#if NEARBY_SAMPLES>0 + const vec2 _SAMPLES[4]=vec2[]( + vec2(1.0, 0.0), + vec2(-1.0, 0.0), + vec2(0.0, 1.0), + vec2(0.0, -1.0) + ); +#endif + +noperspective in vec2 texCoord; + +uniform vec2 g_ResolutionInverse; +uniform sampler2D m_DepthTexture; +uniform sampler2D m_Texture; +uniform vec3 g_CameraPosition; +uniform mat4 g_ViewProjectionMatrixInverse; +uniform mat4 g_ViewProjectionMatrix; +uniform mat4 g_ProjectionMatrix; +uniform vec2 g_FrustumNearFar; +uniform vec3 m_FrustumCorner; +uniform vec2 m_NearReflectionsFade; +uniform vec2 m_FarReflectionsFade; +uniform int m_RaySamples; +uniform float m_StepLength; +uniform float m_ReflectionFactor; +/** +* In this shader we use two types of coordinates +* World coordinates = coordinates of a point in the 3d world +* Screen coordinates = coordinate of a point projected to the screen +* x=(0,1) for left and right +* y=(0,1) for bottom and top +* z=(0,1) for near and far +*/ + +/** +* Represent a ray +*/ +struct Ray { + // World position of the surface from where the ray is originated + vec3 wFrom; + // Same as before but in screenspace + vec3 sFrom; + // Glossiness of the surface from where the ray is originated + float surfaceGlossiness; + // Its direction + vec3 wDir; + + vec3 sDir; + + vec3 normal; +}; + +/** +* Returned when the ray hit or miss the scene +*/ +struct HitResult { + // Last tested screen position (-1,-1 if missed) + vec3 screenPos; + // How strong the reflection is + float reflStrength; +}; + +/** +* Get screen space coordinates +* x=(0,1) for left and right +* y=(0,1) for bottom and top +* z=(0,1) for near and far +*/ +vec3 getScreenPos(in vec2 texCoord,in float depth){ + vec3 screenpos= vec3(texCoord,depth); + return screenpos; +} + +/** +* Exponential to linear depth +*/ +float linearizeDepth(in float depth){ + return (2. * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - depth * (g_FrustumNearFar.y - g_FrustumNearFar.x)); +} + +/** +* Convert world space to screenspace (UV,DEPTH) +*/ +vec3 wposToScreenPos(in vec3 wPos){ + vec4 ww = g_ViewProjectionMatrix * vec4(wPos, 1.0); + ww.xyz /= ww.w; + ww.xyz = ww.xyz * 0.5 + 0.5; + return ww.xyz; +} + +/** +* Convert screen space (UV,DEPTH) to world space +*/ +vec3 screenPosToWPos(in vec3 screenPos){ + vec4 pos=vec4(screenPos,1.0)*2.0-1.0; + pos = g_ViewProjectionMatrixInverse * pos; + return pos.xyz/pos.w; +} + +vec3 getPosition(float depthv, in vec2 uv){ + //Reconstruction from depth + float depth = (2.0 * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - depthv * (g_FrustumNearFar.y-g_FrustumNearFar.x)); + + //one frustum corner methodPreNormalPass + float x = mix(-m_FrustumCorner.x, m_FrustumCorner.x, uv.x); + float y = mix(-m_FrustumCorner.y, m_FrustumCorner.y, uv.y); + + return depth * vec3(x, y, m_FrustumCorner.z); +} + +#define fresnelExp 5.0 + +float fresnel(vec3 direction, vec3 normal) { + vec3 halfDirection = normalize(normal + direction); + + float cosine = dot(halfDirection, direction); + float product = max(cosine, 0.0); + float factor = 1.0 - pow(product, fresnelExp); + + return factor; +} + + + +#ifdef USE_APPROXIMATED_NORMALS + vec3 approximateNormal2(in vec3 pos,in vec2 texCoord){ + float step = g_ResolutionInverse.x ; + float stepy = g_ResolutionInverse.y ; + float depth2 = getDepth(m_DepthTexture,texCoord + vec2(step,-stepy)).r; + float depth3 = getDepth(m_DepthTexture,texCoord + vec2(-step,-stepy)).r; + vec3 pos2 = vec3(getPosition(depth2,texCoord + vec2(step,-stepy))); + vec3 pos3 = vec3(getPosition(depth3,texCoord + vec2(-step,-stepy))); + + vec3 v1 = (pos - pos2).xyz; + vec3 v2 = (pos3 - pos2).xyz; + vec4 normal = vec4(normalize(cross(-v1, v2)), 1.0) * g_ProjectionMatrix; + return normal.xyz / normal.w; + } + /** + * Use nearby positions to aproximate normals + */ + // Adapted from https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-effects/src/main/resources/Common/MatDefs/SSAO/ssao.frag#L33 + vec3 approximateNormal(in vec3 pos,in vec2 texCoord){ + #ifdef FAST_APPROXIMATIONS + vec3 v1=dFdx(pos); + vec3 v2=dFdy(pos); + #else + float step = g_ResolutionInverse.x ; + float stepy = g_ResolutionInverse.y ; + float depth2 = texture(m_DepthTexture,texCoord + vec2(step,-stepy)).r; + float depth3 = texture(m_DepthTexture,texCoord + vec2(-step,-stepy)).r; + vec3 pos2=screenPosToWPos( getScreenPos(texCoord + vec2(step,-stepy),depth2) ); + vec3 pos3=screenPosToWPos( getScreenPos(texCoord + vec2(-step,-stepy),depth3) ); + vec3 v1 = (pos - pos2).xyz; + vec3 v2 = (pos3 - pos2).xyz; + #endif + return normalize(cross(-v1, v2)); + } +#else + vec3 getNormal(in vec2 texCoord){ + vec3 wNormal = texture(m_Normals, texCoord).xyz * 2.0 - 1.0; + vec4 normal = vec4(wNormal , 1.0) * g_ProjectionMatrix; + wNormal = normal.xyz / normal.w; + wNormal.z = (2.0 * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - wNormal.z * (g_FrustumNearFar.y-g_FrustumNearFar.x)); + #ifdef RG_NORMAL_MAP + wNormal.z = sqrt(1-clamp(dot(wNormal.xy, wNormal.xy),0.,1.)); // Reconstruct Z + #endif + return normalize(wNormal); + } +#endif + +#ifdef USE_APPROXIMATED_GLOSSINESS + /** + * Use nearby normals to aproximate glossiness + */ + float approximateGlossiness(in vec3 normal,in vec2 texCoord){ + vec3 d1 = dFdx(normal); + vec3 d2 = dFdy(normal); + float maxd=max(dot(d1,d1),dot(d2,d2)); + maxd=smoothstep(0.,1.,maxd); + maxd=pow(maxd,8)*1.; + return 1.-clamp(maxd,0,1); + } +#endif + +// ##### DEBUG +#ifdef _ENABLE_TESTS + void _testConversions(){ + float depth=texture(m_DepthTexture,texCoord).r; + vec3 screenpos=getScreenPos(texCoord.xy,depth); + vec3 wpos=screenPosToWPos(screenpos); + screenpos=wposToScreenPos(wpos); + vec3 nwpos=screenPosToWPos(screenpos); + if(distance(nwpos,wpos)>0.01)outFragColor=vec4(1,0,0,1); + } + void _testShowWPos(){ + float depth=texture(m_DepthTexture,texCoord).r; + vec3 screenpos=getScreenPos(texCoord.xy,depth); + vec3 wpos=screenPosToWPos(screenpos); + outFragColor.rgb=wpos; + } + void _testScreenZ(){ + float depth=texture(m_DepthTexture,texCoord).r; + vec3 screenpos=getScreenPos(texCoord.xy,depth); + outFragColor.rgb=vec3(screenpos.z); + } + void _testLinearZ(){ + float depth=texture(m_DepthTexture,texCoord).r; + vec3 screenpos=getScreenPos(texCoord.xy,depth); + outFragColor.rgb=vec3(linearizeDepth(screenpos.z)); + } + void _testShowApproximatedGloss(){ + vec3 wNormal=texture(m_Normals,texCoord).rgb; + wNormal.xyz=wNormal.xyz*2.-1.; + #ifdef RG_NORMAL_MAP + wNormal.z = sqrt(1-clamp(dot(wNormal.xy, wNormal.xy),0.,1.)); // Reconstruct Z + #endif + outFragColor.rgb=vec3(approximateGlossiness(wNormal,texCoord)); + } + void _testShowRayGloss(in Ray ray){g_View + outFragColor.rgb=vec3(ray.surfaceGlossiness); + } +#endif +// #### + +/** +* Create a ray for ray marching +*/ +Ray createRay(in vec2 texCoord,in float depth){ + Ray ray; + ray.sFrom=getScreenPos(texCoord,depth); + ray.wFrom = screenPosToWPos(ray.sFrom); + ray.surfaceGlossiness=1.; + + #ifdef USE_APPROXIMATED_NORMALS + vec3 wNormal=approximateNormal(ray.wFrom, texCoord); + #else + vec3 wNormal= getNormal(texCoord); + #ifdef GLOSSINESS_PACKET_IN_NORMAL_B + ray.surfaceGlossiness = wNormal.z * m_ReflectionFactor; + #elif defined(USE_APPROXIMATED_GLOSSINESS) + ray.surfaceGlossiness = min(ray.surfaceGlossiness, approximateGlossiness(wNormal,texCoord)) * m_ReflectionFactor; + #endif + #endif + + ray.normal = wNormal; + + // direction from camera to fragment (in world space) + vec3 wDir = normalize(ray.wFrom - g_CameraPosition); + + // reflection vector + ray.wDir = normalize(reflect(wDir, wNormal)); + return ray; +} + +/** +* Actual ray marching happens here +*/ +HitResult performRayMarching(in Ray ray){ + + HitResult result; + result.screenPos=vec3(-1,-1,-1); + + // Current position of the sample along the ray + vec3 sampleWPos; + + // Same of before, but in screen space + vec3 sampleScreenPos; + + // Position of the nearest surface at the sample position (in screen space) + vec3 hitSurfaceScreenPos; + + // Length of the next step + float stepLength = m_StepLength; + + float linearSourceDepth=linearizeDepth(ray.sFrom.z); + + for(int i = 0; i < m_RaySamples; i++) { + // if(hit)break; + sampleWPos = ray.wFrom + ray.wDir * stepLength; + sampleScreenPos = wposToScreenPos(sampleWPos); // ray.sFrom + ray.sDir * stepLength; + + hitSurfaceScreenPos = getScreenPos(sampleScreenPos.xy, getDepth(m_DepthTexture, sampleScreenPos.xy).r); + vec3 hitSurfaceWPos = screenPosToWPos(hitSurfaceScreenPos); + + int j=0; + #if NEARBY_SAMPLES>0 + do{ + #endif + // We need to linearize the depth to have consistent tests for distant samples + float linearHitSurfaceDepth=linearizeDepth(hitSurfaceScreenPos.z); + float linearSampleDepth=linearizeDepth(sampleScreenPos.z); + bool hit= + linearHitSurfaceDepth>linearSourceDepth // check if the thing we want to reflect is behind the source of the ray + && abs(linearSampleDepth - linearHitSurfaceDepth) < DEPTH_TEST_BIAS; // check if the ray is (~almost) hitting the surface + // if first hit (letting the cycle running helds to better performances than breaking it) + if(hit && result.screenPos.x == -1){ + result.screenPos=sampleScreenPos; + // Fade distant reflections + result.reflStrength=distance(hitSurfaceWPos,ray.wFrom); + result.reflStrength=smoothstep(m_NearReflectionsFade.x,m_NearReflectionsFade.y, result.reflStrength) + *(1.-smoothstep(m_FarReflectionsFade.x,m_FarReflectionsFade.y, result.reflStrength)); + } + #if NEARBY_SAMPLES>0 + hitSurfaceScreenPos = getScreenPos(sampleScreenPos.xy, + texture(m_DepthTexture, sampleScreenPos.xy+_SAMPLES[j].xy * g_ResolutionInverse).r + ); + j++; + }while(j<=NEARBY_SAMPLES); + #endif + + // Compute next step length + stepLength = length(ray.wFrom - hitSurfaceWPos); + } + return result; +} + + +void main(){ + outFragColor=vec4(0); + + float depth=getDepth(m_DepthTexture,texCoord).r; + + if(depth!=1){ // ignore the sky + // Build the ray + Ray ray=createRay(texCoord, depth); + // Perform ray marching + HitResult result=performRayMarching(ray); + + // Used to fade reflections near screen edges to remove artifacts + float d=distance(result.screenPos.xy,vec2(0.5)); + d=pow(1.-clamp(d,0.,.5)*2.,2); + + // Render reflections + if(result.screenPos.x!=-1){ + outFragColor.rgb = texture2D(m_Texture,result.screenPos.xy).rgb; + outFragColor.a = d*ray.surfaceGlossiness*result.reflStrength; + //float fresnel = fresnel(ray.wDir, ray.normal); + //outFragColor.rgb *= fresnel; + } + //outFragColor = texture2D(m_Texture, texCoord); + + //outFragColor.a = 1.0; + // Tests + #ifdef _ENABLE_TESTS + outFragColor=vec4(0,0,0,1); + #ifdef _TEST_SHOW_WPOS + _testShowWPos(); + #endif + #ifdef _TEST_CONVERSIONS + _testConversions(); + #endif + #ifdef _TEST_SHOW_SCREEN_Z + _testScreenZ(); + #endif + #ifdef _TEST_SHOW_LINEAR_Z + _testLinearZ(); + #endif + #ifdef _TEST_SHOW_APROXIMATED_GLOSS + _testShowApproximatedGloss(); + #endif + #ifdef _TEST_SHOW_RAY_GLOSS + _testShowRayGloss(ray); + #endif + #endif + + } +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md new file mode 100644 index 0000000000..b7991f2a9f --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md @@ -0,0 +1,74 @@ +MaterialDef SSR { + + MaterialParameters { + // Scene depth + Texture2D DepthTexture + + // Scene color + Texture2D Texture + + Texture2D Normals + + // How many samples along the ray + Int RaySamples: 16 + + // How many samples around the hit position + Int NearbySamples: 4 + + Float StepLength : 1.0 + + // Read only XY from normalmap and generate Z + Boolean RGNormalMap: False + + // Z component of normal map is actually glossiness + Boolean GlossinessPackedInNormalB : False + + // Approximate normals using the depth buffer (automatically actived if you don't provide a Normals texture) + Boolean ApproximateNormals : False + + // Approximate glossiness using the normal map + // (requires Normals, can be used together with GlossinessPackedInNormalB to reduce noise for high frequency normals) + Boolean ApproximateGlossiness : True + + // Reflections fading + Vector2 NearReflectionsFade : 0.01 1.0 + Vector2 FarReflectionsFade : 80.0 100.0 + + /// + Vector3 FrustumCorner + + Int NumSamples + Int NumSamplesDepth + + Float ReflectionFactor : 1.0 + + + } + + Technique { + VertexShader GLSL130: Common/MatDefs/SSR/ssr.vert + FragmentShader GLSL130: Common/MatDefs/SSR/ssr.frag + + WorldParameters { + ResolutionInverse + CameraPosition + ViewProjectionMatrix + ViewProjectionMatrixInverse + FrustumNearFar + ProjectionMatrix + ProjectionMatrixInverse + } + + Defines { + SCENE_NORMALS:Normals + SCENE: Texture + RG_NORMAL_MAP: RGNormalMap + USE_APPROXIMATED_NORMALS: ApproximateNormals + USE_APPROXIMATED_GLOSSINESS: ApproximateGlossiness + GLOSSINESS_PACKET_IN_NORMAL_B: GlossinessPackedInNormalB + RAY_SAMPLES: NumSamples + NEARBY_SAMPLES: NearbySamples + } + } + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.vert b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.vert new file mode 100644 index 0000000000..ac81c7d47a --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.vert @@ -0,0 +1,10 @@ +in vec4 inPosition; +in vec2 inTexCoord; + +noperspective out vec2 texCoord; + +void main() { + vec2 pos = inPosition.xy * 2.0 - 1.0; + gl_Position = vec4(pos, 0.0, 1.0); + texCoord = inTexCoord; +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag new file mode 100644 index 0000000000..4610e63dbf --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag @@ -0,0 +1,105 @@ +#define ALPHA_CUT_OFF 0.01 + +uniform sampler2D m_Texture; + +uniform sampler2D m_SSR; + +uniform vec2 g_Resolution; +uniform vec2 g_ResolutionInverse; +uniform float m_BlurScale; +uniform float m_Sigma; + +noperspective in vec2 texCoord; +out vec4 outFragColor; + +#ifdef USE_FAST_BLUR +// https://github.com/Jam3/glsl-fast-gaussian-blur +vec4 fastBlur(sampler2D image, vec2 direction) { + vec4 color = vec4(0.0); + vec2 off1 = vec2(1.3846153846) * direction; + vec2 off2 = vec2(3.2307692308) * direction; + vec4 pixel = texture(image, texCoord); + if(pixel.a > ALPHA_CUT_OFF){ + color += pixel * 0.2270270270; + } + pixel = texture(image, texCoord + off1); + if(pixel.a > ALPHA_CUT_OFF){ + color += pixel * 0.3162162162; + } + pixel = texture(image, texCoord - off1); + if(pixel.a > ALPHA_CUT_OFF){ + color += pixel * 0.3162162162; + } + + pixel = texture(image, texCoord + off2); + if(pixel.a > ALPHA_CUT_OFF){ + color += pixel * 0.0702702703; + + } + + pixel = texture(image, texCoord - off2); + if(pixel.a > ALPHA_CUT_OFF){ + color += pixel * 0.0702702703; + } + + return color; +} + +#else + +float normpdf(in float x){ + return 0.39894*exp(-0.5*x*x/(m_Sigma*m_Sigma))/m_Sigma; +} +// based on: https://www.shadertoy.com/view/XdfGDH +vec4 blur(sampler2D image){ + const int mSize = 5; + const int kSize = (mSize-1)/2; + float kernel[mSize]; + vec4 final_colour = vec4(0.0); + + //create the 1-D kernel + float Z = 0.0; + for (int j = 0; j <= kSize; ++j){ + kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j)); + } + + //get the normalization factor (as the gaussian has been clamped) + for (int j = 0; j < mSize; ++j){ + Z += kernel[j]; + } + + //read out the texels + for (int i=-kSize; i <= kSize; ++i){ + for (int j=-kSize; j <= kSize; ++j){ + vec4 color = texture(image, texCoord + vec2(i,j) * g_ResolutionInverse); + if(color.a > ALPHA_CUT_OFF){ + final_colour += kernel[kSize+j]*kernel[kSize+i]*color; + } + } + } + + final_colour /= Z * Z / 1.1; + return final_colour; +} + +#endif + +void main(){ + vec2 texCoord=texCoord; + outFragColor=texture2D(m_Texture,texCoord); + + if(texture(m_SSR, texCoord).a > ALPHA_CUT_OFF){ + #ifdef USE_FAST_BLUR + #ifdef HORIZONTAL + vec4 sum = fastBlur(m_SSR, vec2(1 * m_BlurScale, 0) * g_ResolutionInverse); + #else + vec4 sum = fastBlur(m_SSR, vec2(0, 1 * m_BlurScale) * g_ResolutionInverse); + #endif + #else + vec4 sum = blur(m_SSR); + #endif + outFragColor.rgb=mix(outFragColor.rgb, sum.rgb, sum.a); + } else { + //outFragColor = vec4(0.0); + } +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.j3md b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.j3md new file mode 100644 index 0000000000..cddf881c39 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.j3md @@ -0,0 +1,37 @@ +MaterialDef SSRMerger { + + MaterialParameters { + Texture2D DepthTexture + Texture2D Texture + Texture2D SSR + Boolean Horizontal + Boolean Vertical + Boolean FastBlur : False + Float BlurScale: 1.0 + Float Sigma: 5.0 + + Int NumSamples + + } + + Technique { + VertexShader GLSL130: Common/MatDefs/SSR/ssr.vert + FragmentShader GLSL130: Common/MatDefs/SSR/ssrBlur.frag + + + WorldParameters { + Resolution + ResolutionInverse + } + + Defines { + FINAL:Texture + HORIZONTAL : Horizontal + VERTICAL : Vertical + USE_FAST_BLUR : FastBlur + } + + } + + +} From 27f2ba1696ff8620a8aead0875e304bf4bbc1f22 Mon Sep 17 00:00:00 2001 From: rickard Date: Sat, 13 Jul 2019 09:06:55 +0200 Subject: [PATCH 02/20] simple test scene for ssr --- .../src/main/resources/Scenes/SSR/testScene.j3o | Bin 0 -> 7923 bytes .../main/resources/Scenes/SSR/testScene.j3odata | 3 +++ 2 files changed, 3 insertions(+) create mode 100644 jme3-testdata/src/main/resources/Scenes/SSR/testScene.j3o create mode 100644 jme3-testdata/src/main/resources/Scenes/SSR/testScene.j3odata diff --git a/jme3-testdata/src/main/resources/Scenes/SSR/testScene.j3o b/jme3-testdata/src/main/resources/Scenes/SSR/testScene.j3o new file mode 100644 index 0000000000000000000000000000000000000000..39f48d6e98d0545a89cbdb945d9393542de46bb0 GIT binary patch literal 7923 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 Date: Sat, 13 Jul 2019 09:07:16 +0200 Subject: [PATCH 03/20] test application for ssr filter --- .../src/main/java/jme3test/post/TestSsr.java | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 jme3-examples/src/main/java/jme3test/post/TestSsr.java diff --git a/jme3-examples/src/main/java/jme3test/post/TestSsr.java b/jme3-examples/src/main/java/jme3test/post/TestSsr.java new file mode 100644 index 0000000000..36a0c8b3d1 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/post/TestSsr.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.AmbientLight; +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.SsrFilter; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.texture.Texture; +import com.jme3.util.TangentBinormalGenerator; + +public class TestSsr extends SimpleApplication { + + Spatial model; + + public static void main(String[] args) { + TestSsr app = new TestSsr(); + app.start(); + } + + @Override + public void simpleInitApp() { + cam.setLocation(new Vector3f(10, 5, 10)); + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); +// cam.setRotation(new Quaternion(0.046916496f, -0.69500375f, 0.045538206f, 0.7160271f)); + + + flyCam.setMoveSpeed(50); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Texture diff = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); + diff.setWrap(Texture.WrapMode.Repeat); + Texture norm = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_normal.jpg"); + norm.setWrap(Texture.WrapMode.Repeat); + mat.setTexture("DiffuseMap", diff); + mat.setTexture("NormalMap", norm); + //mat.setFloat("Shininess", 10.0f); + + + AmbientLight al = new AmbientLight(); + al.setColor(ColorRGBA.DarkGray); + rootNode.addLight(al); + +// DirectionalLight dl = new DirectionalLight(new Vector3f(0f ,-1f, 0.f)); +// dl.setColor(ColorRGBA.LightGray); +// rootNode.addLight(dl); + + PointLight p = new PointLight(new Vector3f(-5, 5, -5), ColorRGBA.Blue); + p.setRadius(15); + rootNode.addLight(p); + + PointLight p3 = new PointLight(new Vector3f(0, 10, 0), ColorRGBA.LightGray); + p3.setRadius(15); + rootNode.addLight(p3); + + PointLight p2 = new PointLight(new Vector3f(5, 5, 5), ColorRGBA.Red); + p2.setRadius(15); + rootNode.addLight(p2); + + model = assetManager.loadModel("Scenes/SSR/testScene.j3o"); + +// model.setMaterial(mat); + +// model = (Geometry) assetManager.loadModel("Models/Sponza/Sponza.j3o"); +// model.getMesh().scaleTextureCoordinates(new Vector2f(2, 2)); +// model.setMaterial(mat); +// TangentBinormalGenerator.generate(model); + rootNode.attachChild(model); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + SsrFilter ssrFilter = new SsrFilter(); + ssrFilter.setDownSampleFactor(1.5f); + ssrFilter.setApproximateNormals(false); + ssrFilter.setFastBlur(false); + ssrFilter.setStepLength(0.5f); + ssrFilter.setRaySteps(16); + ssrFilter.setSigma(2f); + ssrFilter.setReflectionFactor(0.25f); + fpp.addFilter(ssrFilter); + viewPort.addProcessor(fpp); + } + + @Override + public void simpleUpdate(float tpf) { + } +} From c17d0ec9ac5525a47ed78dd9cc41c47fa72d096d Mon Sep 17 00:00:00 2001 From: rickard Date: Sat, 13 Jul 2019 12:00:28 +0200 Subject: [PATCH 04/20] adding approximateGlossiness to filter applying approximateNormals on filter creation --- .../java/com/jme3/post/filters/SsrFilter.java | 22 +++++++++++++++---- .../resources/Common/MatDefs/SSR/ssr.frag | 16 +++++--------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java index 0e31d97090..acf9d5d983 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java @@ -57,6 +57,8 @@ public class SsrFilter extends Filter{ private Pass normalPass; private Pass ssrPass; private boolean approximateNormals = false; + private boolean approximateGlossiness = true; + private float downSampleFactor = 1f; private Material ssrMaterial; @@ -97,20 +99,21 @@ protected void initFilter(AssetManager manager, RenderManager renderManager, Vie frustumNearFar.y = vp.getCamera().getFrustumFar(); - //if(!approximateNormals){ +// if(!approximateNormals){ normalPass = new Pass(); normalPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Image.Format.RGBA8, Image.Format.Depth); - //} +// } ssrMaterial = new Material(manager, "Common/MatDefs/SSR/ssr.j3md"); ssrMaterial.setVector3("FrustumCorner", frustumCorner); - //if(!approximateNormals){ +// if(!approximateNormals){ ssrMaterial.setTexture("Normals", normalPass.getRenderedTexture()); - //} +// } ssrMaterial.setInt("RaySamples", raySteps); ssrMaterial.setInt("NearbySamples", sampleNearby ? 4 : 0); ssrMaterial.setFloat("StepLength", stepLength); ssrMaterial.setFloat("ReflectionFactor", reflectionFactor); + ssrMaterial.setBoolean("ApproximateNormals", approximateNormals); ssrPass = new Pass("SSR pass") { @@ -265,5 +268,16 @@ public void setReflectionFactor(float reflectionFactor) { + public boolean isApproximateGlossiness() { + return approximateGlossiness; + } + + public void setApproximateGlossiness(boolean approximateGlossiness) { + this.approximateGlossiness = approximateGlossiness; + if(ssrMaterial != null){ + ssrMaterial.setBoolean("ApproximateGlossiness", approximateGlossiness); + } + } + } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag index c397b60750..d0c95dd905 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag @@ -58,7 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //// Size of a pixel used by NEARBY_SAMPLES #define PIXEL_SIZE_MULT 1. //// A depth difference equals or below this will be considered 0 -#define DEPTH_TEST_BIAS 0.00001 +#define DEPTH_TEST_BIAS 0.0001 //// //// # DEBUG // #define _ENABLE_TESTS 1 @@ -71,11 +71,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ///// ########### ########### ########### -#ifndef SCENE_NORMALS - // If normal map is not provided, fallback to normal approximation - #define USE_APPROXIMATED_NORMALS 1 - #undef USE_APPROXIMATED_GLOSSINESS -#else +#ifdef SCENE_NORMALS uniform sampler2D m_Normals; #endif @@ -185,7 +181,7 @@ vec3 screenPosToWPos(in vec3 screenPos){ vec3 getPosition(float depthv, in vec2 uv){ //Reconstruction from depth - float depth = (2.0 * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - depthv * (g_FrustumNearFar.y-g_FrustumNearFar.x)); + float depth = depthv;//(2.0 * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - depthv * (g_FrustumNearFar.y-g_FrustumNearFar.x)); //one frustum corner methodPreNormalPass float x = mix(-m_FrustumCorner.x, m_FrustumCorner.x, uv.x); @@ -219,7 +215,7 @@ float fresnel(vec3 direction, vec3 normal) { vec3 v1 = (pos - pos2).xyz; vec3 v2 = (pos3 - pos2).xyz; - vec4 normal = vec4(normalize(cross(-v1, v2)), 1.0) * g_ProjectionMatrix; + vec4 normal = vec4(normalize(cross(-v1, v2)), 1.0) ; return normal.xyz / normal.w; } /** @@ -245,7 +241,7 @@ float fresnel(vec3 direction, vec3 normal) { #else vec3 getNormal(in vec2 texCoord){ vec3 wNormal = texture(m_Normals, texCoord).xyz * 2.0 - 1.0; - vec4 normal = vec4(wNormal , 1.0) * g_ProjectionMatrix; + vec4 normal = vec4(wNormal , 1.0);// * g_ProjectionMatrix; wNormal = normal.xyz / normal.w; wNormal.z = (2.0 * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - wNormal.z * (g_FrustumNearFar.y-g_FrustumNearFar.x)); #ifdef RG_NORMAL_MAP @@ -389,7 +385,7 @@ HitResult performRayMarching(in Ray ray){ } #if NEARBY_SAMPLES>0 hitSurfaceScreenPos = getScreenPos(sampleScreenPos.xy, - texture(m_DepthTexture, sampleScreenPos.xy+_SAMPLES[j].xy * g_ResolutionInverse).r + texture(m_DepthTexture, sampleScreenPos.xy + _SAMPLES[j].xy * g_ResolutionInverse).r ); j++; }while(j<=NEARBY_SAMPLES); From 2e643b6a0dbee761446904c7aa3a9aa55bf61ae2 Mon Sep 17 00:00:00 2001 From: rickard Date: Sat, 13 Jul 2019 12:04:15 +0200 Subject: [PATCH 05/20] modified TestSsr --- .../src/main/java/jme3test/post/TestSsr.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/jme3-examples/src/main/java/jme3test/post/TestSsr.java b/jme3-examples/src/main/java/jme3test/post/TestSsr.java index 36a0c8b3d1..6c232f59d8 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestSsr.java +++ b/jme3-examples/src/main/java/jme3test/post/TestSsr.java @@ -39,10 +39,8 @@ import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.SsrFilter; -import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.texture.Texture; -import com.jme3.util.TangentBinormalGenerator; public class TestSsr extends SimpleApplication { @@ -55,7 +53,7 @@ public static void main(String[] args) { @Override public void simpleInitApp() { - cam.setLocation(new Vector3f(10, 5, 10)); + cam.setLocation(new Vector3f(20, 15, 20)); cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); // cam.setRotation(new Quaternion(0.046916496f, -0.69500375f, 0.045538206f, 0.7160271f)); @@ -93,7 +91,8 @@ public void simpleInitApp() { rootNode.addLight(p2); model = assetManager.loadModel("Scenes/SSR/testScene.j3o"); - +// model = assetManager.loadModel("Scenes/ManyLights/Main.scene"); +// // model.setMaterial(mat); // model = (Geometry) assetManager.loadModel("Models/Sponza/Sponza.j3o"); @@ -104,13 +103,14 @@ public void simpleInitApp() { FilterPostProcessor fpp = new FilterPostProcessor(assetManager); SsrFilter ssrFilter = new SsrFilter(); - ssrFilter.setDownSampleFactor(1.5f); + ssrFilter.setDownSampleFactor(2f); ssrFilter.setApproximateNormals(false); - ssrFilter.setFastBlur(false); + ssrFilter.setFastBlur(true); ssrFilter.setStepLength(0.5f); ssrFilter.setRaySteps(16); - ssrFilter.setSigma(2f); - ssrFilter.setReflectionFactor(0.25f); + ssrFilter.setSigma(5f); + ssrFilter.setSampleNearby(false); + ssrFilter.setReflectionFactor(0.5f); fpp.addFilter(ssrFilter); viewPort.addProcessor(fpp); } From 55357684e10ec17560ddc3547323873700519c8a Mon Sep 17 00:00:00 2001 From: rickard Date: Sat, 13 Jul 2019 12:11:00 +0200 Subject: [PATCH 06/20] removed unused uniforms --- .../java/com/jme3/post/filters/SsrFilter.java | 30 +++++++++++-- .../resources/Common/MatDefs/SSR/ssr.frag | 42 +------------------ .../resources/Common/MatDefs/SSR/ssr.j3md | 5 +-- 3 files changed, 28 insertions(+), 49 deletions(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java index acf9d5d983..1d4a401722 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java @@ -50,7 +50,6 @@ public class SsrFilter extends Filter{ private Vector2f frustumNearFar; - private Vector3f frustumCorner; private RenderManager renderManager; private ViewPort viewPort; @@ -69,6 +68,8 @@ public class SsrFilter extends Filter{ private float blurScale = 1f; private float sigma = 5f; private float reflectionFactor = 1f; + private Vector2f nearFade = new Vector2f(0.01f, 1.0f); + private Vector2f farFade = new Vector2f(200f, 300f); public SsrFilter(){ @@ -94,7 +95,6 @@ protected void initFilter(AssetManager manager, RenderManager renderManager, Vie float farY = (vp.getCamera().getFrustumTop() / vp.getCamera().getFrustumNear()) * vp.getCamera().getFrustumFar(); float farX = farY * ((float) screenWidth / (float) screenHeight); - frustumCorner = new Vector3f(farX, farY, vp.getCamera().getFrustumFar()); frustumNearFar.x = vp.getCamera().getFrustumNear(); frustumNearFar.y = vp.getCamera().getFrustumFar(); @@ -105,7 +105,6 @@ protected void initFilter(AssetManager manager, RenderManager renderManager, Vie // } ssrMaterial = new Material(manager, "Common/MatDefs/SSR/ssr.j3md"); - ssrMaterial.setVector3("FrustumCorner", frustumCorner); // if(!approximateNormals){ ssrMaterial.setTexture("Normals", normalPass.getRenderedTexture()); // } @@ -114,7 +113,8 @@ protected void initFilter(AssetManager manager, RenderManager renderManager, Vie ssrMaterial.setFloat("StepLength", stepLength); ssrMaterial.setFloat("ReflectionFactor", reflectionFactor); ssrMaterial.setBoolean("ApproximateNormals", approximateNormals); - + ssrMaterial.setVector2("NearReflectionsFade", nearFade); + ssrMaterial.setVector2("FarReflectionsFade", farFade); ssrPass = new Pass("SSR pass") { @@ -278,6 +278,28 @@ public void setApproximateGlossiness(boolean approximateGlossiness) { ssrMaterial.setBoolean("ApproximateGlossiness", approximateGlossiness); } } + + public Vector2f getNearFade() { + return nearFade; + } + + public void setNearFade(Vector2f nearFade) { + this.nearFade = nearFade; + if(ssrMaterial != null){ + ssrMaterial.setVector2("NearReflectionsFade", nearFade); + } + } + + public Vector2f getFarFade() { + return farFade; + } + + public void setFarFade(Vector2f farFade) { + this.farFade = farFade; + if(ssrMaterial != null){ + ssrMaterial.setVector2("FarReflectionsFade", farFade); + } + } } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag index d0c95dd905..4edf4b8e19 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag @@ -97,9 +97,7 @@ uniform sampler2D m_Texture; uniform vec3 g_CameraPosition; uniform mat4 g_ViewProjectionMatrixInverse; uniform mat4 g_ViewProjectionMatrix; -uniform mat4 g_ProjectionMatrix; uniform vec2 g_FrustumNearFar; -uniform vec3 m_FrustumCorner; uniform vec2 m_NearReflectionsFade; uniform vec2 m_FarReflectionsFade; uniform int m_RaySamples; @@ -179,45 +177,7 @@ vec3 screenPosToWPos(in vec3 screenPos){ return pos.xyz/pos.w; } -vec3 getPosition(float depthv, in vec2 uv){ - //Reconstruction from depth - float depth = depthv;//(2.0 * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - depthv * (g_FrustumNearFar.y-g_FrustumNearFar.x)); - - //one frustum corner methodPreNormalPass - float x = mix(-m_FrustumCorner.x, m_FrustumCorner.x, uv.x); - float y = mix(-m_FrustumCorner.y, m_FrustumCorner.y, uv.y); - - return depth * vec3(x, y, m_FrustumCorner.z); -} - -#define fresnelExp 5.0 - -float fresnel(vec3 direction, vec3 normal) { - vec3 halfDirection = normalize(normal + direction); - - float cosine = dot(halfDirection, direction); - float product = max(cosine, 0.0); - float factor = 1.0 - pow(product, fresnelExp); - - return factor; -} - - - #ifdef USE_APPROXIMATED_NORMALS - vec3 approximateNormal2(in vec3 pos,in vec2 texCoord){ - float step = g_ResolutionInverse.x ; - float stepy = g_ResolutionInverse.y ; - float depth2 = getDepth(m_DepthTexture,texCoord + vec2(step,-stepy)).r; - float depth3 = getDepth(m_DepthTexture,texCoord + vec2(-step,-stepy)).r; - vec3 pos2 = vec3(getPosition(depth2,texCoord + vec2(step,-stepy))); - vec3 pos3 = vec3(getPosition(depth3,texCoord + vec2(-step,-stepy))); - - vec3 v1 = (pos - pos2).xyz; - vec3 v2 = (pos3 - pos2).xyz; - vec4 normal = vec4(normalize(cross(-v1, v2)), 1.0) ; - return normal.xyz / normal.w; - } /** * Use nearby positions to aproximate normals */ @@ -241,7 +201,7 @@ float fresnel(vec3 direction, vec3 normal) { #else vec3 getNormal(in vec2 texCoord){ vec3 wNormal = texture(m_Normals, texCoord).xyz * 2.0 - 1.0; - vec4 normal = vec4(wNormal , 1.0);// * g_ProjectionMatrix; + vec4 normal = vec4(wNormal , 1.0); wNormal = normal.xyz / normal.w; wNormal.z = (2.0 * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - wNormal.z * (g_FrustumNearFar.y-g_FrustumNearFar.x)); #ifdef RG_NORMAL_MAP diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md index b7991f2a9f..b0aaf952b3 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md @@ -32,10 +32,7 @@ MaterialDef SSR { // Reflections fading Vector2 NearReflectionsFade : 0.01 1.0 - Vector2 FarReflectionsFade : 80.0 100.0 - - /// - Vector3 FrustumCorner + Vector2 FarReflectionsFade : 200.0 300.0 Int NumSamples Int NumSamplesDepth From bdb3562388a8cf7001b444c471b28015088b36d4 Mon Sep 17 00:00:00 2001 From: rickard Date: Sat, 13 Jul 2019 15:04:17 +0200 Subject: [PATCH 07/20] switched back some uniforms to macros and replaced even more uniforms with macros(!) reapplied depth linearization fix removed the test scene --- .../src/main/resources/Common/MatDefs/SSR/ssr.frag | 10 +++++++--- .../src/main/resources/Common/MatDefs/SSR/ssr.j3md | 2 +- .../src/main/resources/Common/MatDefs/SSR/ssrBlur.frag | 10 ++++------ .../src/main/resources/Common/MatDefs/SSR/ssrBlur.j3md | 4 ++++ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag index 4edf4b8e19..5863329f0b 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag @@ -100,7 +100,6 @@ uniform mat4 g_ViewProjectionMatrix; uniform vec2 g_FrustumNearFar; uniform vec2 m_NearReflectionsFade; uniform vec2 m_FarReflectionsFade; -uniform int m_RaySamples; uniform float m_StepLength; uniform float m_ReflectionFactor; /** @@ -155,7 +154,12 @@ vec3 getScreenPos(in vec2 texCoord,in float depth){ * Exponential to linear depth */ float linearizeDepth(in float depth){ - return (2. * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - depth * (g_FrustumNearFar.y - g_FrustumNearFar.x)); + float f=g_FrustumNearFar.y; + float n = g_FrustumNearFar.x; + float d=depth*2.-1.; + d= (2. * n *f ) / (f + n - d * (f - n)); + return (d-n)/(f-n); + //return (2. * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - depth * (g_FrustumNearFar.y - g_FrustumNearFar.x)); } /** @@ -317,7 +321,7 @@ HitResult performRayMarching(in Ray ray){ float linearSourceDepth=linearizeDepth(ray.sFrom.z); - for(int i = 0; i < m_RaySamples; i++) { + for(int i = 0; i < RAY_SAMPLES; i++) { // if(hit)break; sampleWPos = ray.wFrom + ray.wDir * stepLength; sampleScreenPos = wposToScreenPos(sampleWPos); // ray.sFrom + ray.sDir * stepLength; diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md index b0aaf952b3..01c3dd8aab 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md @@ -63,7 +63,7 @@ MaterialDef SSR { USE_APPROXIMATED_NORMALS: ApproximateNormals USE_APPROXIMATED_GLOSSINESS: ApproximateGlossiness GLOSSINESS_PACKET_IN_NORMAL_B: GlossinessPackedInNormalB - RAY_SAMPLES: NumSamples + RAY_SAMPLES: RaySamples NEARBY_SAMPLES: NearbySamples } } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag index 4610e63dbf..b243a82626 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag @@ -6,8 +6,6 @@ uniform sampler2D m_SSR; uniform vec2 g_Resolution; uniform vec2 g_ResolutionInverse; -uniform float m_BlurScale; -uniform float m_Sigma; noperspective in vec2 texCoord; out vec4 outFragColor; @@ -48,11 +46,11 @@ vec4 fastBlur(sampler2D image, vec2 direction) { #else float normpdf(in float x){ - return 0.39894*exp(-0.5*x*x/(m_Sigma*m_Sigma))/m_Sigma; + return 0.39894*exp(-0.5*x*x/(SIGMA * SIGMA))/SIGMA; } // based on: https://www.shadertoy.com/view/XdfGDH vec4 blur(sampler2D image){ - const int mSize = 5; + const int mSize = KERNEL_SIZE; const int kSize = (mSize-1)/2; float kernel[mSize]; vec4 final_colour = vec4(0.0); @@ -91,9 +89,9 @@ void main(){ if(texture(m_SSR, texCoord).a > ALPHA_CUT_OFF){ #ifdef USE_FAST_BLUR #ifdef HORIZONTAL - vec4 sum = fastBlur(m_SSR, vec2(1 * m_BlurScale, 0) * g_ResolutionInverse); + vec4 sum = fastBlur(m_SSR, vec2(1 * BLUR_SCALE, 0) * g_ResolutionInverse); #else - vec4 sum = fastBlur(m_SSR, vec2(0, 1 * m_BlurScale) * g_ResolutionInverse); + vec4 sum = fastBlur(m_SSR, vec2(0, 1 * BLUR_SCALE) * g_ResolutionInverse); #endif #else vec4 sum = blur(m_SSR); diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.j3md b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.j3md index cddf881c39..6d3aa2d95e 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.j3md +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.j3md @@ -9,6 +9,7 @@ MaterialDef SSRMerger { Boolean FastBlur : False Float BlurScale: 1.0 Float Sigma: 5.0 + Int KernelSize : 5 Int NumSamples @@ -29,6 +30,9 @@ MaterialDef SSRMerger { HORIZONTAL : Horizontal VERTICAL : Vertical USE_FAST_BLUR : FastBlur + BLUR_SCALE : BlurScale + SIGMA : Sigma + KERNEL_SIZE : KernelSize } } From 7abc5b780b339a55cd61a1afb40c9404e17c19ca Mon Sep 17 00:00:00 2001 From: rickard Date: Sat, 13 Jul 2019 15:04:38 +0200 Subject: [PATCH 08/20] removed the test scene --- jme3-examples/src/main/java/jme3test/post/TestSsr.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jme3-examples/src/main/java/jme3test/post/TestSsr.java b/jme3-examples/src/main/java/jme3test/post/TestSsr.java index 6c232f59d8..cde08a325c 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestSsr.java +++ b/jme3-examples/src/main/java/jme3test/post/TestSsr.java @@ -90,8 +90,8 @@ public void simpleInitApp() { p2.setRadius(15); rootNode.addLight(p2); - model = assetManager.loadModel("Scenes/SSR/testScene.j3o"); -// model = assetManager.loadModel("Scenes/ManyLights/Main.scene"); +// model = assetManager.loadModel("Scenes/SSR/testScene.j3o"); + model = assetManager.loadModel("Scenes/ManyLights/Main.scene"); // // model.setMaterial(mat); @@ -107,7 +107,7 @@ public void simpleInitApp() { ssrFilter.setApproximateNormals(false); ssrFilter.setFastBlur(true); ssrFilter.setStepLength(0.5f); - ssrFilter.setRaySteps(16); + ssrFilter.setRaySteps(32); ssrFilter.setSigma(5f); ssrFilter.setSampleNearby(false); ssrFilter.setReflectionFactor(0.5f); From ec0db956e200a6a523e8bf75bdaa3ebe09d591c6 Mon Sep 17 00:00:00 2001 From: rickard Date: Sat, 13 Jul 2019 15:04:47 +0200 Subject: [PATCH 09/20] removed the test scene --- .../src/main/resources/Scenes/SSR/testScene.j3o | Bin 7923 -> 0 bytes .../main/resources/Scenes/SSR/testScene.j3odata | 3 --- 2 files changed, 3 deletions(-) delete mode 100644 jme3-testdata/src/main/resources/Scenes/SSR/testScene.j3o delete mode 100644 jme3-testdata/src/main/resources/Scenes/SSR/testScene.j3odata diff --git a/jme3-testdata/src/main/resources/Scenes/SSR/testScene.j3o b/jme3-testdata/src/main/resources/Scenes/SSR/testScene.j3o deleted file mode 100644 index 39f48d6e98d0545a89cbdb945d9393542de46bb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7923 zcmdT}U2qgt7CxuvCo}oa0Fi$q5h6i?3W$GXCIN)7{7I0N{UO^-I%IG%9j7}n;FeC6 zWvS&4wJ*BX^0vMhunJ0F*at#htlH9jT(^Ak3AfgLpe(K8!3Xy{clvhj43juMZd3Q% zuTOvH+;h)8ed*jeczEA-BC^n0nix{9HCcC}@7#p5z0b=!1*h+%Q}msg!Ktw^r-;Y# z*h`Qdqqc89Tkvvc3(n~9xLfqCr=e~-qi7@k`AH`-14UAJPv>3Rr$*d1!uOqFD5o6qOGoLlHSlN;|F96E5s9d*EOh)Lj$#oXC( zf206iTqQ2=jQJzE!l+XYs!`of=Iw%G2|uasg&q}pQ`ubc)m#FFGKdHxYR}}nm=0@Y z7?w)KGgCIQRzPrIQv7aKUZU$eB=S(s^Fd-76{>pRHH(ET(Ix8w?*Zx^zTGEoCJPGFhxs*qL4%}(B#K%FWEOWJfG)rGd-agmndc~BZ7 zYT5mwUGU`1Ny=?Pr&3L|=|#7gA01Jz4oRk?1!OfQ>y&gci(+on@fsxI$thIuh`g%m zEsnh~>b=-tt(B08Z%gF!@1JW_Q1a%3v(yzQgH zRQbldtetmSw5Qr-b4;p2Ig`mWOxwj1c(v5a*)(nEr<{>7*=W=osHO_mS~TrdGW&b9 z2%3~^6zyfS7~0!takM|7HK4tRmOz_DOQKyvlhywmO={{Jv}U+QqZTyr*NXdY^lhL@ z9kin_q3=NdXY?ube?`9xz4*iC()f4uD8a^mq3=Y03;jJX{U`dBFquNX3NVX)HTuuc zuR;HB^qAW!iCyN$BAz2|_Z`n4mVJBcSrp6GhnOvk<3}fLtZ9U!QBK4#(FV5gujT0R zq5VTg1`drJ892PpxIH#-;sBl}xiP^_NnRzHOA$wSpbPJHrZv?Q5fmXwp4>_*lf*IR zxWx?;lzON{8>dUS7h#EzG{d1}c?EXbyF->Io${n(TlH*YN$x||ng3{UKPXXdjUlcG zAy^Bblkee`LAWhd;bI+=dx)Eu+bmuYv8=v1@2xB8Puf49`*QNS;LN+J9^iT4OM-8{ z_wB|ij;X&Sw&3*4cOfoZ16}1Ncpg}qT=QK-H`{KXOt;QnoGSspe&@1aNeA#pp}y_* z@l5yZhjXv|bX)Wa2YkVbZ~8I$&2)#lANn+NYp#)D8|DqM0bf`7)GU-o~k*1A-T zTNSfWtKr<0Pjl^pI88q_IeHxz_+dPE)j&``H-hE~)8`VL(7(2o_|2S{c>sROy}cn^(R8 z_5}xezk&mPz^UfHA^Obnj@Am>N}nd@4e@^$KkyHI3Vuw^g00E%FJ1`zRPxO@O-`ll z!d##a^H9YP^=3Saa~ASe$ya0Pd6~Hib6y#<$q&~>uPN$8YALK?vzDUV&kyoeewerO z4t|uMH z#6A1~Z|1eUhF9}CzLy{3RlE`(Qk}elm-8}CaR;|^8@F-`KE2k0o6%gNsn5sUq6Uw<|CL2pN9xO*t0@u~M;&FuQI_onDg ztT{jIJgWG@sm8*;4xgeItbJD7*5a7_YCn1`(btMi>-D&rFXL){bqr=~CdagW`J$is z=E|Gt*AfTP8mBszXWl5Kl)e@CodEj*CwFU8M);x^EPCM!7XAhJ6fAzUPwijZ*5a6a z!6wJ_Z^l-Qbqr=~i^XroW^zp1=3BGrFE)SIf2V)v4ULEc)*QEc_^ZieCI^pVhXtI3{1P$ua%cicQ9?=IGcozd8mpHj`t{%eo%ReBS;^ zdgHh6-PHK{V;zGT+hXzSu_S(zW7-mR&0~|p)iqFVcVRpaIrArPx81xr+nOdS%^5g- z`OfQFpZ;h8&m9NUNj%va4t$7$MPzvsVH?)R}FIRlMyOU2=HjQ=L*AQsYX;m{$9V~IE<4mxm(lf=nQ z0<8%rHZ3@%X+~?KcAU$kAXE5nYdKCLIw3o8_OcS^Eo;zLL$0NDv>tLj-Ai3Kc-R2B zfx78_+DMxqH&G8gK%1!-vX{2dgS3_UAp2+=Jwy-FcC<$zchF9H6!KBpMUT8k_Tj*8FWP=OKtps8@*w?+4$)ycigpC@7(GMBA&=8A zouFswB;-l@H4cGJ;jryFwBOS2aNczq@-&UmAIPRNkY^~1qgsc?Ajjw|jZ==!L7t=M zDNhqrfGm(plk@@=A&cbUbZd&HA*bm@nxXS_0rCR9Bqw39|5UC|{D>Um=jDH6seP%= za$h&b+d!qVP3dQ_dS0fY+5>=YF{~IR>>czjnznQCgu$ilR zaF~};Fb_4M#j!k=E3{h@%Woa0i8t(VCnns&HvEvc*BSG+sb2xhQhuO4w|!!i Date: Sat, 20 Jul 2019 09:44:33 +0200 Subject: [PATCH 10/20] more tweaks and boiler plate code --- .../java/com/jme3/post/filters/SsrFilter.java | 93 ++++++++++++++++++- .../resources/Common/MatDefs/SSR/ssr.frag | 20 ++-- .../resources/Common/MatDefs/SSR/ssr.j3md | 1 - .../resources/Common/MatDefs/SSR/ssrBlur.frag | 17 ++-- 4 files changed, 109 insertions(+), 22 deletions(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java index 1d4a401722..02f4a21b24 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java @@ -32,6 +32,10 @@ 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.Vector2f; import com.jme3.math.Vector3f; @@ -41,6 +45,7 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; import com.jme3.texture.Image; +import java.io.IOException; import java.util.ArrayList; /** @@ -55,6 +60,7 @@ public class SsrFilter extends Filter{ private ViewPort viewPort; private Pass normalPass; private Pass ssrPass; + private Pass[] blurPass; private boolean approximateNormals = false; private boolean approximateGlossiness = true; @@ -70,7 +76,8 @@ public class SsrFilter extends Filter{ private float reflectionFactor = 1f; private Vector2f nearFade = new Vector2f(0.01f, 1.0f); private Vector2f farFade = new Vector2f(200f, 300f); - + private int blurPasses = 4; + private Image.Format ssrImageFormat = Image.Format.RGBA16F; public SsrFilter(){ super("SSR Filter"); @@ -131,12 +138,33 @@ public boolean requiresSceneAsTexture() { }; - ssrPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Image.Format.RGBA8, Image.Format.Depth, 1, ssrMaterial); + ssrPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), ssrImageFormat, Image.Format.Depth, 1, ssrMaterial); postRenderPasses.add(ssrPass); + + Material blurMaterial = new Material(manager, "Common/MatDefs/SSR/ssrBlur.j3md"); + blurMaterial.setTexture("SSR", ssrPass.getRenderedTexture()); + blurMaterial.setBoolean("Horizontal", true); + blurMaterial.setBoolean("FastBlur", fastBlur); + blurMaterial.setFloat("BlurScale", blurScale); + blurMaterial.setFloat("Sigma", sigma); + + blurPass = new Pass[blurPasses-1]; + for(int i = 0; i < blurPasses-1; i++){ + blurPass[i] = new Pass("Blur Pass"); + Material passMat = blurMaterial.clone(); + passMat.setBoolean("Horizontal", i % 2 == 0); + if(i == 0){ + passMat.setTexture("SSR", ssrPass.getRenderedTexture()); + } else { + passMat.setTexture("SSR", blurPass[i-1].getRenderedTexture()); + } + blurPass[i].init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Image.Format.RGBA8, Image.Format.Depth, 1, passMat); + postRenderPasses.add(blurPass[i]); + } material = new Material(manager, "Common/MatDefs/SSR/ssrBlur.j3md"); - material.setTexture("SSR", ssrPass.getRenderedTexture()); - material.setBoolean("Horizontal", true); + material.setTexture("SSR", blurPasses > 1 ? blurPass[blurPasses-2].getRenderedTexture() : ssrPass.getRenderedTexture()); + material.setBoolean("Horizontal", blurPasses % 2 == 1); material.setBoolean("FastBlur", fastBlur); material.setFloat("BlurScale", blurScale); material.setFloat("Sigma", sigma); @@ -179,6 +207,7 @@ public void setApproximateNormals(boolean approximateNormals) { /** * Value to scale (down) the textures the filter uses. + * Some values work better than others with approximateNormals. Good values: 1.5f, 3f; * @param downSampleFactor */ public void setDownSampleFactor(float downSampleFactor) { @@ -300,6 +329,62 @@ public void setFarFade(Vector2f farFade) { ssrMaterial.setVector2("FarReflectionsFade", farFade); } } + + public int getBlurPasses() { + return blurPasses; + } + + public void setBlurPasses(int blurPasses) { + this.blurPasses = blurPasses; + } + + public Image.Format getSsrImageFormat() { + return ssrImageFormat; + } + + public void setSsrImageFormat(Image.Format ssrImageFormat) { + this.ssrImageFormat = ssrImageFormat; + } + + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + oc.write(approximateNormals, "approximateNormals", true); + oc.write(approximateGlossiness, "approximateGlossiness", true); + oc.write(sampleNearby, "sampleNearby", true); + oc.write(fastBlur, "fastBlur", true); + oc.write(downSampleFactor, "downSampleFactor", 1f); + oc.write(stepLength, "stepLength", 1f); + oc.write(blurScale, "blurScale", 1f); + oc.write(sigma, "sigma", 5f); + oc.write(reflectionFactor, "reflectionFactor", 1f); + oc.write(raySteps, "raySteps", 16); + oc.write(blurPasses, "blurPasses", 2); + oc.write(new float[]{nearFade.x, nearFade.y}, "nearFade", new float[]{0.01f, 1.0f}); + oc.write(new float[]{farFade.x, farFade.y}, "farFade", new float[]{200f, 300f}); + } + + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule ic = im.getCapsule(this); + approximateNormals = ic.readBoolean("approximateNormals", true); + approximateGlossiness = ic.readBoolean("intensity", true); + sampleNearby = ic.readBoolean("sampleNearby", true); + fastBlur = ic.readBoolean("fastBlur", true); + downSampleFactor = ic.readFloat("downSampleFactor", 1f); + stepLength = ic.readFloat("stepLength", 1f); + blurScale = ic.readFloat("blurScale", 1f); + sigma = ic.readFloat("sigma", 5f); + reflectionFactor = ic.readFloat("reflectionFactor", 1f); + raySteps = ic.readInt("raySteps", 16); + blurPasses = ic.readInt("blurPasses", 2); + float[] nearArray = ic.readFloatArray("nearFade", new float[]{0.01f, 1.0f}); + nearFade = new Vector2f(nearArray[0], nearArray[1]); + float[] farArray = ic.readFloatArray("farFade", new float[]{200f, 300f}); + farFade = new Vector2f(farArray[0], farArray[1]); + } } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag index 5863329f0b..df1cf430d1 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag @@ -1,5 +1,4 @@ #import "Common/ShaderLib/GLSLCompat.glsllib" - #import "Common/ShaderLib/MultiSample.glsllib" /** ####################### @@ -97,6 +96,7 @@ uniform sampler2D m_Texture; uniform vec3 g_CameraPosition; uniform mat4 g_ViewProjectionMatrixInverse; uniform mat4 g_ViewProjectionMatrix; +uniform mat4 g_ProjectionMatrix; uniform vec2 g_FrustumNearFar; uniform vec2 m_NearReflectionsFade; uniform vec2 m_FarReflectionsFade; @@ -146,7 +146,7 @@ struct HitResult { * z=(0,1) for near and far */ vec3 getScreenPos(in vec2 texCoord,in float depth){ - vec3 screenpos= vec3(texCoord,depth); + vec3 screenpos= vec3(texCoord, depth); return screenpos; } @@ -191,12 +191,12 @@ vec3 screenPosToWPos(in vec3 screenPos){ vec3 v1=dFdx(pos); vec3 v2=dFdy(pos); #else - float step = g_ResolutionInverse.x ; - float stepy = g_ResolutionInverse.y ; + float step = g_ResolutionInverse.x; + float stepy = g_ResolutionInverse.y; float depth2 = texture(m_DepthTexture,texCoord + vec2(step,-stepy)).r; float depth3 = texture(m_DepthTexture,texCoord + vec2(-step,-stepy)).r; - vec3 pos2=screenPosToWPos( getScreenPos(texCoord + vec2(step,-stepy),depth2) ); - vec3 pos3=screenPosToWPos( getScreenPos(texCoord + vec2(-step,-stepy),depth3) ); + vec3 pos2=screenPosToWPos( getScreenPos(texCoord + vec2(step,-stepy), depth2) ); + vec3 pos3=screenPosToWPos( getScreenPos(texCoord + vec2(-step,-stepy), depth3) ); vec3 v1 = (pos - pos2).xyz; vec3 v2 = (pos3 - pos2).xyz; #endif @@ -276,16 +276,16 @@ Ray createRay(in vec2 texCoord,in float depth){ Ray ray; ray.sFrom=getScreenPos(texCoord,depth); ray.wFrom = screenPosToWPos(ray.sFrom); - ray.surfaceGlossiness=1.; + ray.surfaceGlossiness=1.* m_ReflectionFactor; #ifdef USE_APPROXIMATED_NORMALS vec3 wNormal=approximateNormal(ray.wFrom, texCoord); #else vec3 wNormal= getNormal(texCoord); #ifdef GLOSSINESS_PACKET_IN_NORMAL_B - ray.surfaceGlossiness = wNormal.z * m_ReflectionFactor; + ray.surfaceGlossiness = wNormal.z; #elif defined(USE_APPROXIMATED_GLOSSINESS) - ray.surfaceGlossiness = min(ray.surfaceGlossiness, approximateGlossiness(wNormal,texCoord)) * m_ReflectionFactor; + ray.surfaceGlossiness = min(ray.surfaceGlossiness, approximateGlossiness(wNormal,texCoord)); #endif #endif @@ -380,7 +380,7 @@ void main(){ // Render reflections if(result.screenPos.x!=-1){ outFragColor.rgb = texture2D(m_Texture,result.screenPos.xy).rgb; - outFragColor.a = d*ray.surfaceGlossiness*result.reflStrength; + outFragColor.a = d * ray.surfaceGlossiness*result.reflStrength; //float fresnel = fresnel(ray.wDir, ray.normal); //outFragColor.rgb *= fresnel; } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md index 01c3dd8aab..556b1bc46f 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.j3md @@ -53,7 +53,6 @@ MaterialDef SSR { ViewProjectionMatrixInverse FrustumNearFar ProjectionMatrix - ProjectionMatrixInverse } Defines { diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag index b243a82626..e2271dad33 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssrBlur.frag @@ -68,15 +68,18 @@ vec4 blur(sampler2D image){ //read out the texels for (int i=-kSize; i <= kSize; ++i){ - for (int j=-kSize; j <= kSize; ++j){ - vec4 color = texture(image, texCoord + vec2(i,j) * g_ResolutionInverse); - if(color.a > ALPHA_CUT_OFF){ - final_colour += kernel[kSize+j]*kernel[kSize+i]*color; - } - } + #ifdef HORIZONTAL + vec2 uv = vec2(i, 0); + #else + vec2 uv = vec2(0, i); + #endif + vec4 color = texture(image, texCoord + uv * g_ResolutionInverse); + //if(color.a > ALPHA_CUT_OFF){ + final_colour += kernel[kSize+i]*color; + //} } - final_colour /= Z * Z / 1.1; + final_colour /= Z / 1.1; return final_colour; } From 47df16f0928f281b839d205bc7f4a75d7636cb30 Mon Sep 17 00:00:00 2001 From: rickard Date: Wed, 31 Jul 2019 12:57:44 +0200 Subject: [PATCH 11/20] added pre rendering pass for normals + glossiness --- .../java/com/jme3/post/filters/SsrFilter.java | 24 ++++++- .../Common/MatDefs/SSR/normal_gloss.frag | 38 +++++++++++ .../Common/MatDefs/SSR/normal_gloss.vert | 22 +++++++ .../resources/Common/MatDefs/SSR/ssr.frag | 63 +++++++++++-------- 4 files changed, 120 insertions(+), 27 deletions(-) create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java index 02f4a21b24..19fea9773d 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java @@ -78,6 +78,8 @@ public class SsrFilter extends Filter{ private Vector2f farFade = new Vector2f(200f, 300f); private int blurPasses = 4; private Image.Format ssrImageFormat = Image.Format.RGBA16F; + private boolean rgNormalMap; + private boolean glossinessPackedInNormalB = true; public SsrFilter(){ super("SSR Filter"); @@ -119,6 +121,8 @@ protected void initFilter(AssetManager manager, RenderManager renderManager, Vie ssrMaterial.setInt("NearbySamples", sampleNearby ? 4 : 0); ssrMaterial.setFloat("StepLength", stepLength); ssrMaterial.setFloat("ReflectionFactor", reflectionFactor); + ssrMaterial.setBoolean("GlossinessPackedInNormalB", glossinessPackedInNormalB); + ssrMaterial.setBoolean("RGNormalMap", glossinessPackedInNormalB); ssrMaterial.setBoolean("ApproximateNormals", approximateNormals); ssrMaterial.setVector2("NearReflectionsFade", nearFade); ssrMaterial.setVector2("FarReflectionsFade", farFade); @@ -177,7 +181,12 @@ protected void postQueue(RenderQueue queue) { Renderer r = renderManager.getRenderer(); r.setFrameBuffer(normalPass.getRenderFrameBuffer()); renderManager.getRenderer().clearBuffers(true, true, true); - renderManager.setForcedTechnique("PreNormalPass"); + if(glossinessPackedInNormalB){ + renderManager.setForcedTechnique("PreNormalGlossPass"); + } else { + renderManager.setForcedTechnique("PreNormalPass"); + } + renderManager.renderViewPortQueues(viewPort, false); renderManager.setForcedTechnique(null); renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer()); @@ -346,6 +355,19 @@ public void setSsrImageFormat(Image.Format ssrImageFormat) { this.ssrImageFormat = ssrImageFormat; } + public boolean isGlossinessPackedInNormalB() { + return glossinessPackedInNormalB; + } + + public void setGlossinessPackedInNormalB(boolean glossinessPackedInNormalB) { + this.glossinessPackedInNormalB = glossinessPackedInNormalB; + if(ssrMaterial != null){ + ssrMaterial.setBoolean("GlossinessPackedInNormalB", glossinessPackedInNormalB); + ssrMaterial.setBoolean("RGNormalMap", glossinessPackedInNormalB); + } + } + + @Override public void write(JmeExporter ex) throws IOException { diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.frag new file mode 100644 index 0000000000..9ed8f3a264 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.frag @@ -0,0 +1,38 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" +varying vec3 normal; +varying vec2 texCoord; + + +#ifdef SPECGLOSSPIPELINE + #ifdef GLOSSINESSMAP + uniform sampler2D m_GlossinessMap; + #else + uniform float m_Glossiness; + #endif +#else + #ifdef ROUGHNESSMAP + uniform sampler2D m_RoughnessMap; + #else + uniform float m_Roughness; + #endif +#endif + +void main(void) +{ + float glossiness = 0.0; + #ifdef SPECGLOSSPIPELINE + #ifdef GLOSSINESSMAP + glossiness = texture2D(m_GlossinessMap,texCoord).r; + #else + glossiness = m_Glossiness; + #endif + #else + #ifdef GLOSSINESSMAP + glossiness = 1.0 - texture2D(m_RoughnessMap,texCoord).r; + #else + glossiness = 1.0 - m_Roughness; + #endif + #endif + gl_FragColor = vec4(vec3(normal.xy * 0.5 + 0.5, glossiness), 1.0); + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert new file mode 100644 index 0000000000..479bca3af0 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert @@ -0,0 +1,22 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" +#import "Common/ShaderLib/Instancing.glsllib" +#import "Common/ShaderLib/Skinning.glsllib" + +attribute vec3 inPosition; +attribute vec3 inNormal; +attribute vec4 inTexCoord; + +varying vec3 normal; +varying vec2 texCoord; + +void main(void) +{ + texCoord=inTexCoord.xy; + vec4 modelSpacePos = vec4(inPosition, 1.0); + vec3 modelSpaceNormals = inNormal; + #ifdef NUM_BONES + Skinning_Compute(modelSpacePos,modelSpaceNormals); + #endif + normal = normalize((g_WorldMatrix * vec4(modelSpaceNormals, 1.0)).xyz); + gl_Position = TransformWorldViewProjection(modelSpacePos); +} \ No newline at end of file diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag index df1cf430d1..acf41575df 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/ssr.frag @@ -181,6 +181,21 @@ vec3 screenPosToWPos(in vec3 screenPos){ return pos.xyz/pos.w; } +#ifdef USE_APPROXIMATED_GLOSSINESS + /** + * Use nearby normals to aproximate glossiness + */ + float approximateGlossiness(in vec3 normal,in vec2 texCoord){ + vec3 d1 = dFdx(normal); + vec3 d2 = dFdy(normal); + float maxd=max(dot(d1,d1),dot(d2,d2)); + maxd=smoothstep(0.,1.,maxd); + maxd=pow(maxd,8)*1.; + return 1.-clamp(maxd,0,1); + } +#endif + + #ifdef USE_APPROXIMATED_NORMALS /** * Use nearby positions to aproximate normals @@ -203,32 +218,31 @@ vec3 screenPosToWPos(in vec3 screenPos){ return normalize(cross(-v1, v2)); } #else - vec3 getNormal(in vec2 texCoord){ - vec3 wNormal = texture(m_Normals, texCoord).xyz * 2.0 - 1.0; - vec4 normal = vec4(wNormal , 1.0); - wNormal = normal.xyz / normal.w; - wNormal.z = (2.0 * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - wNormal.z * (g_FrustumNearFar.y-g_FrustumNearFar.x)); + vec3 getNormal(in vec2 texCoord, out float glossiness){ + vec3 wNormal = texture(m_Normals, texCoord).xyz; + #ifdef RG_NORMAL_MAP + #ifdef GLOSSINESS_PACKET_IN_NORMAL_B + glossiness = wNormal.z; + #endif + wNormal.xy = wNormal.xy * 2.0 - 1.0; + //wNormal.z = sqrt(1.0 - wNormal.x*wNormal.x - wNormal.y * wNormal.y); wNormal.z = sqrt(1-clamp(dot(wNormal.xy, wNormal.xy),0.,1.)); // Reconstruct Z + #else + wNormal = wNormal * 2.0 - 1.0; + vec4 normal = vec4(wNormal , 1.0); + wNormal = normal.xyz / normal.w; + wNormal.z = (2.0 * g_FrustumNearFar.x) / (g_FrustumNearFar.y + g_FrustumNearFar.x - wNormal.z * (g_FrustumNearFar.y-g_FrustumNearFar.x)); + #endif + + #ifdef USE_APPROXIMATED_GLOSSINESS + glossiness = min(glossiness, approximateGlossiness(wNormal,texCoord)); #endif + return normalize(wNormal); } #endif -#ifdef USE_APPROXIMATED_GLOSSINESS - /** - * Use nearby normals to aproximate glossiness - */ - float approximateGlossiness(in vec3 normal,in vec2 texCoord){ - vec3 d1 = dFdx(normal); - vec3 d2 = dFdy(normal); - float maxd=max(dot(d1,d1),dot(d2,d2)); - maxd=smoothstep(0.,1.,maxd); - maxd=pow(maxd,8)*1.; - return 1.-clamp(maxd,0,1); - } -#endif - // ##### DEBUG #ifdef _ENABLE_TESTS void _testConversions(){ @@ -277,16 +291,13 @@ Ray createRay(in vec2 texCoord,in float depth){ ray.sFrom=getScreenPos(texCoord,depth); ray.wFrom = screenPosToWPos(ray.sFrom); ray.surfaceGlossiness=1.* m_ReflectionFactor; - + #ifdef USE_APPROXIMATED_NORMALS vec3 wNormal=approximateNormal(ray.wFrom, texCoord); #else - vec3 wNormal= getNormal(texCoord); - #ifdef GLOSSINESS_PACKET_IN_NORMAL_B - ray.surfaceGlossiness = wNormal.z; - #elif defined(USE_APPROXIMATED_GLOSSINESS) - ray.surfaceGlossiness = min(ray.surfaceGlossiness, approximateGlossiness(wNormal,texCoord)); - #endif + float glossiness = 0.0; + vec3 wNormal= getNormal(texCoord, glossiness); + ray.surfaceGlossiness=glossiness * m_ReflectionFactor; #endif ray.normal = wNormal; From 00d38e9db668b22ade9da7483a9462cdf756a5f9 Mon Sep 17 00:00:00 2001 From: rickard Date: Wed, 31 Jul 2019 12:59:44 +0200 Subject: [PATCH 12/20] added pre rendering pass for normals + glossiness --- .../Common/MatDefs/Light/PBRLighting.j3md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md index 8465d2f0b2..2ed1bd61b5 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md @@ -287,6 +287,29 @@ MaterialDef PBR Lighting { } + Technique PreNormalGlossPass { + + VertexShader GLSL100 : Common/MatDefs/SSR/normal_gloss.vert + FragmentShader GLSL100 : Common/MatDefs/SSR/normal_gloss.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + WorldMatrix + NormalMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + NUM_MORPH_TARGETS: NumberOfMorphTargets + NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers + } + + } + Technique Glow { VertexShader GLSL100 GLSL150: Common/MatDefs/Misc/Unshaded.vert From fed0f339e5efc2646a2e290cc03f63c581af3866 Mon Sep 17 00:00:00 2001 From: rickard Date: Wed, 31 Jul 2019 15:59:23 +0200 Subject: [PATCH 13/20] changed to TransformWorldNormal --- .../src/main/resources/Common/MatDefs/SSR/normal_gloss.vert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert index 479bca3af0..95ba732ab7 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert @@ -17,6 +17,6 @@ void main(void) #ifdef NUM_BONES Skinning_Compute(modelSpacePos,modelSpaceNormals); #endif - normal = normalize((g_WorldMatrix * vec4(modelSpaceNormals, 1.0)).xyz); + normal = normalize(TransformWorldNormal(modelSpaceNormals)); gl_Position = TransformWorldViewProjection(modelSpacePos); } \ No newline at end of file From 7b175afffd6c090299ca26b7dfa4e65a69d7de02 Mon Sep 17 00:00:00 2001 From: rickard Date: Fri, 2 Aug 2019 14:23:58 +0200 Subject: [PATCH 14/20] added support for normal map --- .../Common/MatDefs/SSR/normal_gloss.frag | 30 ++++++++++++++++--- .../Common/MatDefs/SSR/normal_gloss.vert | 14 +++++++-- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.frag b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.frag index 9ed8f3a264..825d514d1a 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.frag @@ -1,7 +1,11 @@ #import "Common/ShaderLib/GLSLCompat.glsllib" -varying vec3 normal; +varying vec3 wNormal; varying vec2 texCoord; +#ifdef NORMALMAP + uniform sampler2D m_NormalMap; + varying vec4 wTangent; +#endif #ifdef SPECGLOSSPIPELINE #ifdef GLOSSINESSMAP @@ -19,16 +23,34 @@ varying vec2 texCoord; void main(void) { + #if defined(NORMALMAP) + vec3 tan = normalize(wTangent.xyz); + mat3 tbnMat = mat3(tan, wTangent.w * cross( (wNormal), (tan)), wNormal); + #endif + + #if defined(NORMALMAP) + vec4 normalHeight = texture2D(m_NormalMap, texCoord); + //Note the -2.0 and -1.0. We invert the green channel of the normal map, + //as it's complient with normal maps generated with blender. + //see http://hub.jmonkeyengine.org/forum/topic/parallax-mapping-fundamental-bug/#post-256898 + //for more explanation. + vec3 normal = normalize((normalHeight.xyz * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0))); + normal = normalize(tbnMat * normal); + //normal = normalize(normal * inverse(tbnMat)); + #else + vec3 normal = wNormal; + #endif + float glossiness = 0.0; #ifdef SPECGLOSSPIPELINE #ifdef GLOSSINESSMAP - glossiness = texture2D(m_GlossinessMap,texCoord).r; + glossiness = texture2D(m_GlossinessMap, texCoord).r; #else glossiness = m_Glossiness; #endif #else - #ifdef GLOSSINESSMAP - glossiness = 1.0 - texture2D(m_RoughnessMap,texCoord).r; + #ifdef ROUGHNESSMAP + glossiness = 1.0 - texture2D(m_RoughnessMap, texCoord).r; #else glossiness = 1.0 - m_Roughness; #endif diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert index 95ba732ab7..34b4e4046d 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert @@ -6,17 +6,27 @@ attribute vec3 inPosition; attribute vec3 inNormal; attribute vec4 inTexCoord; -varying vec3 normal; +varying vec3 wNormal; varying vec2 texCoord; +#if defined(NORMALMAP) + attribute vec4 inTangent; + varying vec4 wTangent; +#endif + void main(void) { texCoord=inTexCoord.xy; vec4 modelSpacePos = vec4(inPosition, 1.0); vec3 modelSpaceNormals = inNormal; + + #if defined(NORMALMAP) + wTangent = vec4(TransformWorldNormal(inTangent.xyz),inTangent.w); + #endif + #ifdef NUM_BONES Skinning_Compute(modelSpacePos,modelSpaceNormals); #endif - normal = normalize(TransformWorldNormal(modelSpaceNormals)); + wNormal = normalize(TransformWorldNormal(modelSpaceNormals)); gl_Position = TransformWorldViewProjection(modelSpacePos); } \ No newline at end of file From f60ccefcbbf8c43b853bffe55894ed310ddeb37f Mon Sep 17 00:00:00 2001 From: rickard Date: Fri, 2 Aug 2019 14:30:20 +0200 Subject: [PATCH 15/20] added support for normal map --- .../src/main/resources/Common/MatDefs/Light/PBRLighting.j3md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md index 2ed1bd61b5..13af7e8d79 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md @@ -306,6 +306,10 @@ MaterialDef PBR Lighting { INSTANCING : UseInstancing NUM_MORPH_TARGETS: NumberOfMorphTargets NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers + NORMALMAP : NormalMap + ROUGHNESSMAP : RoughnessMap + SPECGLOSSPIPELINE : UseSpecGloss + GLOSSINESSMAP : GlossinessMap } } From 2a85f6d0a8b085e7a31689ad5fd8fe784efa9968 Mon Sep 17 00:00:00 2001 From: rickard Date: Fri, 2 Aug 2019 14:31:27 +0200 Subject: [PATCH 16/20] added some fields to read/write --- .../src/main/java/com/jme3/post/filters/SsrFilter.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java index 19fea9773d..757397efc1 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java @@ -384,6 +384,8 @@ public void write(JmeExporter ex) throws IOException { oc.write(reflectionFactor, "reflectionFactor", 1f); oc.write(raySteps, "raySteps", 16); oc.write(blurPasses, "blurPasses", 2); + oc.write(glossinessPackedInNormalB, "glossinessPackedInNormalB", false); + oc.write(ssrImageFormat.toString(), "ssrImageFormat", Image.Format.RGBA16F.toString()); oc.write(new float[]{nearFade.x, nearFade.y}, "nearFade", new float[]{0.01f, 1.0f}); oc.write(new float[]{farFade.x, farFade.y}, "farFade", new float[]{200f, 300f}); } @@ -403,6 +405,9 @@ public void read(JmeImporter im) throws IOException { reflectionFactor = ic.readFloat("reflectionFactor", 1f); raySteps = ic.readInt("raySteps", 16); blurPasses = ic.readInt("blurPasses", 2); + glossinessPackedInNormalB = ic.readBoolean("glossinessPackedInNormalB", false); + String format = ic.readString("ssrImageFormat", Image.Format.RGBA16F.toString()); + ssrImageFormat = Image.Format.valueOf(format); float[] nearArray = ic.readFloatArray("nearFade", new float[]{0.01f, 1.0f}); nearFade = new Vector2f(nearArray[0], nearArray[1]); float[] farArray = ic.readFloatArray("farFade", new float[]{200f, 300f}); From 311bac4d7d11f9c18c5ebffe67db33825710f97c Mon Sep 17 00:00:00 2001 From: rickard Date: Thu, 8 Aug 2019 09:09:04 +0200 Subject: [PATCH 17/20] repurposed TestSSAO as SSR example --- .../src/main/java/jme3test/post/TestSsr.java | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/jme3-examples/src/main/java/jme3test/post/TestSsr.java b/jme3-examples/src/main/java/jme3test/post/TestSsr.java index cde08a325c..145386816c 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestSsr.java +++ b/jme3-examples/src/main/java/jme3test/post/TestSsr.java @@ -31,23 +31,32 @@ */ package jme3test.post; +import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; import com.jme3.light.PointLight; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.SsrFilter; +import com.jme3.post.ssao.SSAOFilter; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; import com.jme3.texture.Texture; public class TestSsr extends SimpleApplication { - Spatial model; + Geometry model; public static void main(String[] args) { TestSsr app = new TestSsr(); + app.setShowSettings(false); app.start(); } @@ -57,54 +66,44 @@ public void simpleInitApp() { cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); // cam.setRotation(new Quaternion(0.046916496f, -0.69500375f, 0.045538206f, 0.7160271f)); + cam.setLocation(new Vector3f(68.45442f, 8.235511f, 7.9676695f)); + cam.setRotation(new Quaternion(0.046916496f, -0.69500375f, 0.045538206f, 0.7160271f)); + flyCam.setMoveSpeed(50); - Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + Material mat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md"); Texture diff = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); diff.setWrap(Texture.WrapMode.Repeat); Texture norm = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_normal.jpg"); norm.setWrap(Texture.WrapMode.Repeat); - mat.setTexture("DiffuseMap", diff); + mat.setTexture("BaseColorMap", diff); mat.setTexture("NormalMap", norm); - //mat.setFloat("Shininess", 10.0f); + mat.setFloat("Glossiness", 1.0f); + mat.setBoolean("UseSpecGloss", true); - AmbientLight al = new AmbientLight(); - al.setColor(ColorRGBA.DarkGray); - rootNode.addLight(al); + PointLight al = new PointLight(); + al.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f)); +al.setPosition(new Vector3f(0, 2, 0)); +al.setRadius(500); + rootNode.addLight(al); -// DirectionalLight dl = new DirectionalLight(new Vector3f(0f ,-1f, 0.f)); -// dl.setColor(ColorRGBA.LightGray); -// rootNode.addLight(dl); + model = (Geometry) assetManager.loadModel("Models/Sponza/Sponza.j3o"); + model.getMesh().scaleTextureCoordinates(new Vector2f(2, 2)); + + model.setMaterial(mat); - PointLight p = new PointLight(new Vector3f(-5, 5, -5), ColorRGBA.Blue); - p.setRadius(15); - rootNode.addLight(p); - - PointLight p3 = new PointLight(new Vector3f(0, 10, 0), ColorRGBA.LightGray); - p3.setRadius(15); - rootNode.addLight(p3); - - PointLight p2 = new PointLight(new Vector3f(5, 5, 5), ColorRGBA.Red); - p2.setRadius(15); - rootNode.addLight(p2); - -// model = assetManager.loadModel("Scenes/SSR/testScene.j3o"); - model = assetManager.loadModel("Scenes/ManyLights/Main.scene"); -// -// model.setMaterial(mat); - -// model = (Geometry) assetManager.loadModel("Models/Sponza/Sponza.j3o"); -// model.getMesh().scaleTextureCoordinates(new Vector2f(2, 2)); -// model.setMaterial(mat); -// TangentBinormalGenerator.generate(model); rootNode.attachChild(model); + cam.setLocation(new Vector3f(10.247649f, 8.275992f, 10.405156f)); + cam.setRotation(new Quaternion(-0.083419204f, 0.90370524f, -0.20599906f, -0.36595422f)); + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + SsrFilter ssrFilter = new SsrFilter(); ssrFilter.setDownSampleFactor(2f); - ssrFilter.setApproximateNormals(false); + ssrFilter.setApproximateNormals(true); ssrFilter.setFastBlur(true); ssrFilter.setStepLength(0.5f); ssrFilter.setRaySteps(32); From d0ba0bfe0316225cbea80e9b0ec3694de33c9a5c Mon Sep 17 00:00:00 2001 From: rickard Date: Thu, 8 Aug 2019 09:09:45 +0200 Subject: [PATCH 18/20] fix NPE if cleanup is called twice (without init in between --- .../src/main/java/com/jme3/post/filters/SsrFilter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java index 757397efc1..01349ec11b 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java @@ -195,7 +195,9 @@ protected void postQueue(RenderQueue queue) { @Override protected void cleanUpFilter(Renderer r) { - normalPass.cleanup(r); + if(normalPass != null){ + normalPass.cleanup(r); + } } @Override From 9faea09cc1e9b2f5f22959217620d744c17d7c16 Mon Sep 17 00:00:00 2001 From: rickard Date: Mon, 12 Aug 2019 07:53:16 +0200 Subject: [PATCH 19/20] alright looking normals --- .../src/main/resources/Common/MatDefs/SSR/normal_gloss.vert | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert index 34b4e4046d..b0850fc9b8 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert +++ b/jme3-effects/src/main/resources/Common/MatDefs/SSR/normal_gloss.vert @@ -21,12 +21,12 @@ void main(void) vec3 modelSpaceNormals = inNormal; #if defined(NORMALMAP) - wTangent = vec4(TransformWorldNormal(inTangent.xyz),inTangent.w); + wTangent = vec4(TransformWorld(vec4(inTangent.xyz, 1.0)).xyz,inTangent.w); #endif #ifdef NUM_BONES Skinning_Compute(modelSpacePos,modelSpaceNormals); #endif - wNormal = normalize(TransformWorldNormal(modelSpaceNormals)); + wNormal = normalize(TransformWorld(vec4(modelSpaceNormals, 1.0)).xyz); gl_Position = TransformWorldViewProjection(modelSpacePos); } \ No newline at end of file From 6d7b7dab73551ac6314f712d02dc0cda6b7cfb18 Mon Sep 17 00:00:00 2001 From: rickard Date: Thu, 22 Aug 2019 14:34:31 +0200 Subject: [PATCH 20/20] added clone method --- .../java/com/jme3/post/filters/SsrFilter.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java index 01349ec11b..92858fb179 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SsrFilter.java @@ -369,7 +369,26 @@ public void setGlossinessPackedInNormalB(boolean glossinessPackedInNormalB) { } } - + @Override + public SsrFilter clone(){ + SsrFilter clone = new SsrFilter(); + clone.approximateNormals = approximateNormals; + clone.approximateGlossiness = approximateGlossiness; + clone.sampleNearby = sampleNearby; + clone.fastBlur = fastBlur; + clone.downSampleFactor = downSampleFactor; + clone.stepLength = stepLength; + clone.blurScale = blurScale; + clone.sigma = sigma; + clone.reflectionFactor = reflectionFactor; + clone.raySteps = raySteps; + clone.blurPasses = blurPasses; + clone.glossinessPackedInNormalB = glossinessPackedInNormalB; + clone.ssrImageFormat = ssrImageFormat; + clone.nearFade = nearFade.clone(); + clone.farFade = farFade.clone(); + return clone; + } @Override public void write(JmeExporter ex) throws IOException {