So I was having a problem with the SSAO filter and made this based on: Pure Depth SSAO
I’m not sure if anyone else has made this before, its pretty common, but I could not find it for JME.
It’s SSAO without the normal pass that nehon’s SSAO uses. This results in lower quality, but higher fps. Figured it’s just nice to have another option. Here are some comparison shots:
(Since I do not fully understand the workings of the settings for both filters it wasn’t easy for me to provide fair comparisons)
The scene:
Depth only:
Original:
Depth only:
Original:
I think both could get better results if you are willing to play with the settings. Clearly though nehon’s filter with normal pass is nicer. The only benefit is the ~279 extra fps in this particular case, since you don’t need a normal pass.
Here is the code:
DepthSSAOFilter.java
package packagename;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.post.Filter;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import java.util.ArrayList;
public class DepthSSAOFilter extends Filter
{
Material ssaoMat;
Pass ssaoPass;
Pass hpass;
Material hBlurMat;
Pass vpass;
Material vBlurMat;
private int screenWidth;
private int screenHeight;
public DepthSSAOFilter()
{
super("DepthSSAO");
}
@Override
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h)
{
///*
screenWidth = w;
screenHeight = h;
postRenderPasses = new ArrayList<Pass>();
//ssao Pass
ssaoMat = new Material(manager, "MatDefs/Effects/DepthSSAO.j3md");
Texture random = manager.loadTexture("Common/MatDefs/SSAO/Textures/random.png");
random.setWrap(Texture.WrapMode.Repeat);
ssaoMat.setTexture("RandomTexture", random);
ssaoMat.setFloat("Intensity", 0.9f);//1 seems good, 2 was so dark
ssaoMat.setFloat("Base", 0.15f);//at 0.9 barely any parts get darkened - only extreme corners
ssaoMat.setFloat("Area", 0.0075f);
ssaoMat.setFloat("Falloff", 0.000001f);
ssaoMat.setFloat("Radius", 0.06f);//lower adds more?
ssaoPass = new Pass() {
public boolean requiresDepthAsTexture() {
return true;
}
};
float downSampleFactor = 1f;
ssaoPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Image.Format.RGBA8, Image.Format.Depth, 1, ssaoMat);
postRenderPasses.add(ssaoPass);
//hblur
hBlurMat = new Material(manager, "Common/MatDefs/Blur/HGaussianBlur.j3md");
hpass = new Pass() {
@Override
public void beforeRender() {
hBlurMat.setTexture("Texture", ssaoPass.getRenderedTexture());
hBlurMat.setFloat("Size", screenWidth);
hBlurMat.setFloat("Scale", 1.5f);
}
};
hpass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, hBlurMat);
postRenderPasses.add(hpass);
//vblur
vBlurMat = new Material(manager, "Common/MatDefs/Blur/VGaussianBlur.j3md");
vpass = new Pass() {
@Override
public void beforeRender() {
vBlurMat.setTexture("Texture", hpass.getRenderedTexture());
vBlurMat.setFloat("Size", screenHeight);
vBlurMat.setFloat("Scale", 1.5f);
}
};
vpass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, vBlurMat);
postRenderPasses.add(vpass);
material = new Material(manager, "MatDefs/Effects/ApplySSAO.j3md");
material.setTexture("SSAO", vpass.getRenderedTexture());
}
@Override
protected Material getMaterial()
{
return material;
}
protected boolean isRequiresSceneTexture() {
return true;
}
protected boolean isRequiresDepthTexture() {
return true;
}
}
DepthSSAO.frag
uniform sampler2D m_Texture;
uniform sampler2D m_DepthTexture;
uniform sampler2D m_RandomTexture;
varying vec2 texCoord;
uniform float m_Intensity;
uniform float m_Base;
uniform float m_Area;
uniform float m_Falloff;
uniform float m_Radius;
vec3 normalFromDepth(float depth, vec2 texcoords)
{
vec2 offset1 = vec2(0.0,0.001);
vec2 offset2 = vec2(0.001,0.0);
float depth1 = texture2D(m_DepthTexture, texcoords + offset1).r;
float depth2 = texture2D(m_DepthTexture, texcoords + offset2).r;
vec3 p1 = vec3(offset1, depth1 - depth);
vec3 p2 = vec3(offset2, depth2 - depth);
vec3 normal = cross(p1, p2);
normal.z = -normal.z;
return normalize(normal);
}
vec3 reflection(vec3 v1,vec3 v2)
{
vec3 result= 2.0 * dot(v2, v1) * v2;
result=v1-result;
return result;
}
void main()
{
vec3 sample_sphere[16] = vec3[]( vec3( 0.5381, 0.1856,-0.4319), vec3( 0.1379, 0.2486, 0.4430),
vec3( 0.3371, 0.5679,-0.0057), vec3(-0.6999,-0.0451,-0.0019),
vec3( 0.0689,-0.1598,-0.8547), vec3( 0.0560, 0.0069,-0.1843),
vec3(-0.0146, 0.1402, 0.0762), vec3( 0.0100,-0.1924,-0.0344),
vec3(-0.3577,-0.5301,-0.4358), vec3(-0.3169, 0.1063, 0.0158),
vec3( 0.0103,-0.5869, 0.0046), vec3(-0.0897,-0.4940, 0.3287),
vec3( 0.7119,-0.0154,-0.0918), vec3(-0.0533, 0.0596,-0.5411),
vec3( 0.0352,-0.0631, 0.5460), vec3(-0.4776, 0.2847,-0.0271)
);
vec3 random = normalize( texture2D(m_RandomTexture, texCoord * 4.0).rgb );
float depth = texture2D(m_DepthTexture, texCoord).r;
vec3 position = vec3(texCoord.x,texCoord.y,depth);
vec3 normal = normalFromDepth(depth, texCoord);
float radiusDepth = m_Radius/depth;
float occlusion = 0.0;
int iterations = 16;
for (int j = 0; j < iterations; ++j)
{
vec3 ray = radiusDepth * reflection(sample_sphere[j], random);
vec3 hemiRay = position + sign(dot(ray,normal)) * ray;
float occDepth = texture2D(m_DepthTexture, clamp(hemiRay.xy,0.0,1.0)).r;
float difference = depth - occDepth;
occlusion += step(m_Falloff, difference) * (1.0-smoothstep(m_Falloff, m_Area, difference));
}
float ao = 1.0 - m_Intensity * occlusion * (1.0 / iterations);
float final = clamp(ao + m_Base,0.0,1.0);
gl_FragColor = vec4(final,final,final,1);
}
ApplySSAO.frag
uniform sampler2D m_Texture;
uniform sampler2D m_SSAO;
varying vec2 texCoord;
void main()
{
vec4 tv = texture2D(m_Texture, texCoord);
vec4 ssaov = texture2D(m_SSAO, texCoord);
gl_FragColor = vec4(tv.r*ssaov.r,tv.g*ssaov.r,tv.b*ssaov.r,1.0);
}
DepthSSAO.j3md
MaterialDef Fade {
MaterialParameters {
Int NumSamples
Int NumSamplesDepth
Texture2D Texture
Texture2D DepthTexture
Texture2D RandomTexture
Float Intensity
Float Base
Float Area
Float Falloff
Float Radius
}
Technique {
VertexShader GLSL100: Common/MatDefs/Post/Post.vert
FragmentShader GLSL100: Shaders/Effects/DepthSSAO.frag
WorldParameters {
WorldViewProjectionMatrix
}
}
}
ApplySSAO.j3md
MaterialDef Fade {
MaterialParameters {
Int NumSamples
Int NumSamplesDepth
Texture2D Texture
Texture2D SSAO
Texture2D DepthTexture
}
Technique {
VertexShader GLSL100: Common/MatDefs/Post/Post.vert
FragmentShader GLSL100: Shaders/Effects/ApplySSAO.frag
WorldParameters {
WorldViewProjectionMatrix
}
}
}
Note: The horizontal and vertical blur came from the jme3-effects jar, I extrected them since I’m using an older version without them, you can either extract them or just redirect the filter.java.
The reason I have an applySSAO material is because I am using that to do some custom stuff that is very specific to my project.
This bit:
vec3 sample_sphere[16] = vec3[](....loads of vec3
Worries me a little, I think it might not have worked on 3.1 (I’m using 3.0 atm) though I can’t remember exactly.