I finally decided on a method for smoothing out the rough edges that has the least impact on performance and gives good results. I decided to go with shader generated noise, so no noise texture to sample from. It has 2 modes… UseSmoothing & SmoothMore. The second smoothing pass is optional via SmoothMore, but double the texture lookups from 4 - 8. Even just using the basic 1 pass, the results are awesome… the second only slightly improves the smoothing… so not sure if it is worth the performance hit.
Here are the screen caps… the code below has been updated. Oh… did I mention the performance hit is minimal? Just in case I didn’t… the performance hit is minimal!
Without smoothing:
1 pass smoothing:
2 pass smoothing:
To use smoothing:
[java]ssao.setUseSmoothing(true);
ssao.setSmoothMore(true);
// OR //
ssao.toggleSmoothing(); // toggles no smoothing, 1 pass, 2 pass
[/java]
Since I already updated this, I am going to use the OP for maintaining the code.
Changes:
Fixed to work with older drivers/hardware
Added performance optimization which close to doubles the performance by default.
Changed the falloff to stop ambient occlusion on objects outside of the falloff range.
Added global settings scaling.
Updated javadoc info
Basic Usage:
[java]BasicSSAO ssao = new BasicSSAO();
ssao.scaleSettings(0.25); // or whatever works for your model scale
[/java]
Advanced Usage:
[java]// In vars: reflection-radius, intensity, scale, bias
BasicSSAO ssao = new BasicSSAO(3.0f, 10.5f, 0.5f, 0.025f);
// Add in detail pass - this doubles the number of samples taken and halves performance. But, allows for smoothing artifacting while keeping detail
ssao.setUseDetailPass(true);
// Add distance falloff and set distance/rate of falloff
ssao.setUseDistanceFalloff(true);
ssao.setFalloffStartDistance(250f);
ssao.setFalloffRate(4.0f);
[/java]
Here is the (as close as I can tell) final code:
BasicSSAO.java (updated)
[java]/*
- To change this template, choose Tools | Templates
- and open the template in the editor.
*/
package mygame;
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;
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.shader.VarType;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import java.io.IOException;
import java.util.ArrayList;
public class BasicSSAO extends Filter{
private Pass normalPass;
private Vector3f frustumCorner;
private Vector2f frustumNearFar;
private Vector3f[] samples = {
new Vector3f(1.0f, 0.0f, 1.0f),
new Vector3f(-1.0f, 0.0f, 1.0f),
new Vector3f(0.0f, 1.0f, 1.0f),
new Vector3f(0.0f, -1.0f, 1.0f),
new Vector3f(1.0f, 0.0f, 0.0f),
new Vector3f(-1.0f, 0.0f, 0.0f),
new Vector3f(0.0f, 1.0f, 0.0f),
new Vector3f(0.0f, -1.0f, 0.0f),
new Vector3f(1.0f, 0.0f, -1.0f),
new Vector3f(-1.0f, 0.0f, -1.0f),
new Vector3f(0.0f, 1.0f, -1.0f),
new Vector3f(0.0f, -1.0f, -1.0f)
};
// Wide area occlusion settings
private float sampleRadius = 3.0f;
private float intensity = 10.2f;
private float scale = 3.15f;
private float bias = 0.025f;
// Fine detail occlusion settings
private boolean enableFD = false;
private float sampleRadiusFD = 0.55f;
private float intensityFD = 2.5f;
private float scaleFD = 1.15f;
private float biasFD = 0.025f;
// Distance falloff
private boolean useDistanceFalloff = false;
private float falloffStartDistance = 800f, falloffRate = 2.0f;
private boolean useSmoothing = false;
private boolean smoothMore = false;
private boolean useOnlyAo = false;
private boolean useAo = true;
private Material ssaoMat;
private Pass ssaoPass;
private float downSampleFactor = 1f;
RenderManager renderManager;
ViewPort viewPort;
/**
- Create a Screen Space Ambient Occlusion Filter
*/
public BasicSSAO() {
super("BasicSSAO");
}
/**
- Create a Screen Space Ambient Occlusion Filter
-
@param sampleRadius The radius of the area where random samples will be picked. default 5.1f
-
@param intensity intensity of the resulting AO. default 1.2f
-
@param scale distance between occluders and occludee. default 0.2f
-
@param bias the width of the occlusion cone considered by the occludee. default 0.1f
*/
public BasicSSAO(float sampleRadius, float intensity, float scale, float bias) {
this();
this.sampleRadius = sampleRadius;
this.intensity = intensity;
this.scale = scale;
this.bias = bias;
}
@Override
protected boolean isRequiresDepthTexture() {
return true;
}
@Override
protected void postQueue(RenderQueue renderQueue) {
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 Material getMaterial() {
return material;
}
@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<Pass>();
normalPass = new Pass();
normalPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth);
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();
//ssao Pass
ssaoMat = new Material(manager, "MatDefs/BasicSSAO.j3md");
ssaoMat.setTexture("Normals", normalPass.getRenderedTexture());
ssaoPass = new Pass() {
@Override
public boolean requiresDepthAsTexture() {
return true;
}
};
ssaoPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth, 1, ssaoMat);
ssaoPass.getRenderedTexture().setMinFilter(Texture.MinFilter.Trilinear);
ssaoPass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear);
postRenderPasses.add(ssaoPass);
float xScale = 1.0f / w;
float yScale = 1.0f / h;
float blurScale = 6.75f;
material = new Material(manager, "MatDefs/BasicSSAOBlur.j3md");
material.setTexture("SSAOMap", ssaoPass.getRenderedTexture());
material.setVector2("FrustumNearFar", frustumNearFar);
material.setBoolean("UseAo", useAo);
material.setBoolean("UseOnlyAo", useOnlyAo);
material.setBoolean("UseSmoothing", useSmoothing);
material.setBoolean("SmoothMore", smoothMore);
material.setFloat("XScale", blurScale * xScale);
material.setFloat("YScale", blurScale * yScale);
ssaoMat.setFloat("SampleRadius", sampleRadius);
ssaoMat.setFloat("Intensity", intensity);
ssaoMat.setFloat("Scale", scale);
ssaoMat.setFloat("Bias", bias);
ssaoMat.setBoolean("EnableFD", enableFD);
ssaoMat.setFloat("SampleRadiusFD", sampleRadiusFD);
ssaoMat.setFloat("IntensityFD", intensityFD);
ssaoMat.setFloat("ScaleFD", scaleFD);
ssaoMat.setFloat("BiasFD", biasFD);
ssaoMat.setBoolean("UseDistanceFalloff", useDistanceFalloff);
ssaoMat.setFloat("FalloffStartDistance", falloffStartDistance);
ssaoMat.setFloat("FalloffRate", falloffRate);
ssaoMat.setVector3("FrustumCorner", frustumCorner);
ssaoMat.setVector2("FrustumNearFar", frustumNearFar);
ssaoMat.setParam("Samples", VarType.Vector3Array, samples);
}
/**
- Enables fine detail pass for help in blending out artifacting in the wider area pass without losing detail
-
@param useDetailPass
*/
public void setUseDetailPass(boolean useDetailPass) {
this.enableFD = useDetailPass;
if (ssaoMat != null) {
ssaoMat.setBoolean("EnableFD", useDetailPass);
}
}
/**
- Returns the use fine detail setting
-
@return enableFD
*/
public boolean getUseDetailPass() {
return this.enableFD;
}
/**
- Return the wide area bias<br>
- see {@link #setBias(float bias)}
-
@return bias
*/
public float getBias() {
return bias;
}
/**
- Sets the the width of the wide area occlusion cone considered by the occludee default is 0.025f
-
@param bias
*/
public void setBias(float bias) {
this.bias = bias;
if (ssaoMat != null) {
ssaoMat.setFloat("Bias", bias);
}
}
/**
- Return the fine detail bias<br>
- see {@link #setDetailBias(float biasFD)}
-
@return biasFD
*/
public float getDetailBias() {
return biasFD;
}
/**
- Sets the the width of the fine detail occlusion cone considered by the occludee default is 0.025f
-
@param biasFD
*/
public void setDetailBias(float biasFD) {
this.biasFD = biasFD;
if (ssaoMat != null) {
ssaoMat.setFloat("BiasFD", biasFD);
}
}
/**
- returns the ambient occlusion intensity
-
@return intensity
*/
public float getIntensity() {
return intensity;
}
/**
- Sets the Ambient occlusion intensity default is 10.2f
-
@param intensity
*/
public void setIntensity(float intensity) {
this.intensity = intensity;
if (ssaoMat != null) {
ssaoMat.setFloat("Intensity", intensity);
}
}
/**
- returns the fine detail ambient occlusion intensity
-
@return intensityFD
*/
public float getDetailIntensity() {
return intensityFD;
}
/**
- Sets the fine detail ambient occlusion intensity default is 2.5f
-
@param intensityFD
*/
public void setDetailIntensity(float intensityFD) {
this.intensityFD = intensityFD;
if (ssaoMat != null) {
ssaoMat.setFloat("IntensityFD", intensityFD);
}
}
/**
- returns the sample radius<br>
- see {link setSampleRadius(float sampleRadius)}
-
@return the sample radius
*/
public float getSampleRadius() {
return sampleRadius;
}
/**
- Sets the radius of the area where random samples will be picked dafault 3.0f
-
@param sampleRadius
*/
public void setSampleRadius(float sampleRadius) {
this.sampleRadius = sampleRadius;
if (ssaoMat != null) {
ssaoMat.setFloat("SampleRadius", sampleRadius);
}
}
/**
- returns the sample radius<br>
- see {link setDetailSampleRadius(float sampleRadiusFD)}
-
@return the sample radius for detail pass
*/
public float getDetailSampleRadius() {
return sampleRadiusFD;
}
/**
- Sets the radius of the area where random samples will be picked for fine detail pass dafault 0.55f
-
@param sampleRadiusFD
*/
public void setDetailSampleRadius(float sampleRadiusFD) {
this.sampleRadiusFD = sampleRadiusFD;
if (ssaoMat != null) {
ssaoMat.setFloat("SampleRadiusFD", sampleRadiusFD);
}
}
/**
- returns the scale<br>
- see {@link #setScale(float scale)}
-
@return scale
*/
public float getScale() {
return scale;
}
/**
*
- Returns the distance between occluders and occludee. default 3.15f
-
@param scale
*/
public void setScale(float scale) {
this.scale = scale;
if (ssaoMat != null) {
ssaoMat.setFloat("Scale", scale);
}
}
/**
- returns the detail pass scale<br>
- see {@link #setDetailScale(float scaleFD)}
-
@return scaleFD
*/
public float getDetailScale() {
return scaleFD;
}
/**
*
- Returns the distance between detail pass occluders and occludee. default 1.55f
-
@param scaleFD
*/
public void setDetailScale(float scaleFD) {
this.scaleFD = scaleFD;
if (ssaoMat != null) {
ssaoMat.setFloat("ScaleFD", scaleFD);
}
}
public void scaleSettings(float aoScale) {
setBias(getBias()*aoScale);
setDetailBias(getDetailBias()*aoScale);
setIntensity(getIntensity()*aoScale);
setDetailIntensity(getDetailIntensity()*aoScale);
setScale(getScale()*aoScale);
setDetailScale(getDetailScale()*aoScale);
setScale(getScale()*aoScale);
setDetailScale(getDetailScale()*aoScale);
setSampleRadius(getSampleRadius()*aoScale);
setDetailSampleRadius(getDetailSampleRadius()*aoScale);
}
/**
- debugging only , will be removed
-
@return Whether or not
*/
public boolean isUseAo() {
return useAo;
}
/**
- debugging only
*/
public void setUseAo(boolean useAo) {
this.useAo = useAo;
if (material != null) {
material.setBoolean("UseAo", useAo);
}
}
/**
- debugging only , will be removed
-
@return useOnlyAo
*/
public boolean isUseOnlyAo() {
return useOnlyAo;
}
/**
- debugging only
*/
public void setUseOnlyAo(boolean useOnlyAo) {
this.useOnlyAo = useOnlyAo;
if (material != null) {
material.setBoolean("UseOnlyAo", useOnlyAo);
}
}
public void setUseSmoothing(boolean useSmoothing) {
this.useSmoothing = useSmoothing;
if (material != null) {
material.setBoolean("UseSmoothing", useSmoothing);
}
}
public boolean isUseSmoothing() {
return useSmoothing;
}
public void setSmoothMore(boolean smoothMore) {
this.smoothMore = smoothMore;
if (material != null) {
material.setBoolean("SmoothMore", smoothMore);
}
}
public boolean isSmoothMore() {
return smoothMore;
}
/**
- Enable distance falloff
-
@param useDistanceFalloff
*/
public void setUseDistanceFalloff(boolean useDistanceFalloff) {
this.useDistanceFalloff = useDistanceFalloff;
if (ssaoMat != null) {
ssaoMat.setBoolean("UseDistanceFalloff", useDistanceFalloff);
}
}
/**
- Returns distance falloff setting
-
@return useDistanceFalloff
*/
public boolean getUseDistanceFalloff() {
return this.useDistanceFalloff;
}
/**
- Sets the start distance for distance falloff. Default is 800f
-
@param falloffStartDistance
*/
public void setFalloffStartDistance(float falloffStartDistance) {
this.falloffStartDistance = falloffStartDistance;
if (ssaoMat != null) {
ssaoMat.setFloat("FalloffStart", falloffStartDistance);
}
}
/**
- Returns the start distance for distance falloff.
-
@return falloffStartDistance
*/
public float getFalloffStartDistance() {
return this.falloffStartDistance;
}
/**
- Sets the rate at which distance falloff increases past the start distance. Default is 2.0f
-
@param falloffRate
*/
public void setFalloffRate(float falloffRate) {
this.falloffRate = falloffRate;
if (ssaoMat != null) {
ssaoMat.setFloat("FalloffAmount", falloffRate);
}
}
/**
- Returns the rate at which distance falloff increases past the start distance.
-
@return falloffRate
*/
public float getFalloffRate() {
return this.falloffRate;
}
/**
- Used for debugging. toggles between shadowmap, colormap & colormap+shadowmap
*/
public void toggleSSAO() {
if (!useOnlyAo && useAo) { // BasicSSAO Disabled
useOnlyAo = false;
useAo = false;
} else if (useOnlyAo && useAo) { // BasicSSAO Map Only
useOnlyAo = false;
useAo = true;
} else if (!useOnlyAo && !useAo) { // BasicSSAO Blended
useOnlyAo = true;
useAo = true;
}
if (material != null) {
material.setBoolean("UseAo", useAo);
material.setBoolean("UseOnlyAo", useOnlyAo);
}
}
/**
- Used for debugging. toggles between no smoothing, 1 pass smoothing & 2 pass smoothing
/
public void toggleSmoothing() {
if (smoothMore && useSmoothing) { // Smoothing Disabled
useSmoothing = false;
smoothMore = false;
} else if (useSmoothing && !smoothMore) { // 2 pass Smoothing
useSmoothing = true;
smoothMore = true;
} else if (!useSmoothing && !smoothMore) { // 1 pass Smoothing
useSmoothing = true;
smoothMore = false;
}
if (material != null) {
material.setBoolean("UseSmoothing", useSmoothing);
material.setBoolean("SmoothMore", smoothMore);
}
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(sampleRadius, "sampleRadius", 3.0f);
oc.write(intensity, "intensity", 10.2f);
oc.write(scale, "scale", 3.15f);
oc.write(bias, "bias", 0.025f);
oc.write(sampleRadiusFD, "sampleRadiusFD", 0.55f);
oc.write(intensityFD, "intensityFD", 2.5f);
oc.write(scaleFD, "scaleFD", 1.15f);
oc.write(biasFD, "biasFD", 0.025f);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
sampleRadius = ic.readFloat("sampleRadius", 3.0f);
intensity = ic.readFloat("intensity", 10.2f);
scale = ic.readFloat("scale", 3.15f);
bias = ic.readFloat("bias", 0.025f);
sampleRadiusFD = ic.readFloat("sampleRadiusFD", 0.55f);
intensityFD = ic.readFloat("intensityFD", 2.5f);
scaleFD = ic.readFloat("scaleFD", 1.15f);
biasFD = ic.readFloat("biasFD", 0.025f);
}
}[/java]
Material Definitions (x2):
BasicSSAO.j3md
[java]MaterialDef BasicSSAO {
MaterialParameters {
Int NumSamples
Int NumSamplesDepth
Texture2D DepthTexture
Texture2D Texture
Texture2D Noise
Texture2D Normals
Vector3 FrustumCorner
Float SampleRadius
Float Intensity
Float Scale
Float Bias
Boolean EnableFD
Float SampleRadiusFD
Float IntensityFD
Float ScaleFD
Float BiasFD
Boolean UseDistanceFalloff
Float FalloffStartDistance
Float FalloffRate
Vector2 FrustumNearFar
Vector3Array Samples
}
Technique {
VertexShader GLSL100: Common/MatDefs/Post/Post.vert
FragmentShader GLSL100: Shaders/BasicSSAO.frag
WorldParameters {
WorldViewProjectionMatrix
WorldViewMatrix
Resolution
}
}
}[/java]
BasicSSAOBlur.j3md (updated)
[java]MaterialDef BasicSSAOBlur {
MaterialParameters {
Int NumSamples
Int NumSamplesDepth
Texture2D Texture
Texture2D SSAOMap
Texture2D DepthTexture
Vector2 FrustumNearFar
Boolean UseAo
Boolean UseOnlyAo
Boolean UseSmoothing
Boolean SmoothMore
Float XScale
Float YScale
}
Technique {
VertexShader GLSL100: Common/MatDefs/Post/Post.vert
FragmentShader GLSL100: Shaders/BasicSSAOBlur.frag
WorldParameters {
WorldViewProjectionMatrix
WorldViewMatrix
Resolution
}
Defines {
USE_AO : UseAo
USE_ONLY_AO : UseOnlyAo
RESOLVE_MS : NumSamples
RESOLVE_DEPTH_MS : NumSamplesDepth
}
}
}[/java]
Shaders (x2):
BasicSSAO.frag
[java]uniform vec2 g_Resolution;
uniform vec2 m_FrustumNearFar;
uniform sampler2D m_Texture;
uniform sampler2D m_Normals;
uniform sampler2D m_Noise;
uniform sampler2D m_DepthTexture;
uniform vec3 m_FrustumCorner;
uniform float m_SampleRadius;
uniform float m_Intensity;
uniform float m_Scale;
uniform float m_Bias;
uniform bool m_EnableFD;
uniform float m_SampleRadiusFD;
uniform float m_IntensityFD;
uniform float m_ScaleFD;
uniform float m_BiasFD;
uniform vec3[12] m_Samples;
uniform bool m_UseDistanceFalloff;
uniform float m_FalloffStartDistance;
uniform float m_FalloffRate;
varying vec2 texCoord;
float depthv;
float shadowFactor;
vec3 getPosition(in vec2 uv){
depthv = texture2D(m_DepthTexture,uv).r;
float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - depthv (m_FrustumNearFar.y-m_FrustumNearFar.x));
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);
}
vec3 getNormal(in vec2 uv){
return normalize(texture2D(m_Normals, uv).xyz * 2.0 - 1.0);
}
vec3 getRandom(in vec2 uv){
float rand=(fract(uv.x*(g_Resolution.x/2.0))0.25)+(fract(uv.y(g_Resolution.y/2.0))0.5);
return normalize(vec3(rand,rand,rand));
}
vec3 getNoise(in vec2 uv){
vec4 noise = texture2D(m_Noise, uv25.0);
return (noise.xyz);
}
float doAmbientOcclusion(in vec2 tc, in vec3 pos, in vec3 norm){
vec3 diff = getPosition(tc)- pos;
vec3 v = normalize(diff);
float d = length(diff) * m_Scale;
return step(0.00002,d)max(0.0, dot(norm, v) - m_Bias) * ( 1.0/(1.0 + d) ) * (m_Intensity+shadowFactor) * smoothstep(0.00002,0.0027,d);
}
float doAmbientOcclusionFD(in vec2 tc, in vec3 pos, in vec3 norm){
vec3 diff = getPosition(tc)- pos;
vec3 v = normalize(diff);
float d = length(diff) * m_ScaleFD;
return step(0.00002,d)max(0.0, dot(norm, v) - m_BiasFD) * ( 1.0/(1.0 + d) ) * (m_IntensityFD+shadowFactor) * smoothstep(0.00002,0.0027,d);
}
vec3 reflection(in vec3 v1,in vec3 v2){
vec3 result= 2.0 * dot(v2, v1) * v2;
result=v1-result;
return result;
}
void main(){
float result;
vec3 position = getPosition(texCoord);
if(depthv==1.0){
gl_FragColor=vec4(1.0);
return;
}
vec3 normal = getNormal(texCoord);
vec3 rand = getRandom(texCoord);
float ao = 0.0;
shadowFactor = 0.075;//0.0;//(position.z0.002);
float rad = m_SampleRadius/position.z+shadowFactor;
float radFD = m_SampleRadiusFD/position.z+shadowFactor;
int iterations = 12;
if (m_UseDistanceFalloff) {
float LOG2 = 1.442695;
vec2 m_DistanceFrustum = vec2(1.0,m_FalloffStartDistance);
float depth= (m_DistanceFrustum.x / 4.0) /
(m_DistanceFrustum.y - depthv
(m_DistanceFrustum.y));
float falloffFactor = exp2( -m_FalloffRate * m_FalloffRate * depth * depth * LOG2 );
falloffFactor = clamp(falloffFactor, 0.0, 1.0);
if (falloffFactor < 1.0) {
for (int j = 0; j < iterations; ++j) {
vec3 coord1 = reflection(vec3(m_Samples[j]), rand) * vec3(rad);
ao += doAmbientOcclusion(texCoord + coord1.xy * 0.125, position, normal) - shadowFactor;
// Fine Detail
if (m_EnableFD) {
vec3 coord2 = reflection(vec3(m_Samples[j]), rand) * vec3(radFD0.5);
ao += doAmbientOcclusionFD(texCoord + coord2.xy * 0.05, position, normal) * (0.25-shadowFactor);
}
}
ao /= float(iterations) * (2.35-shadowFactor);
result = 1.0-ao;
result = mix(result,1.0,1.0-falloffFactor);
} else {
result = 1.0;
}
} else {
for (int j = 0; j < iterations; ++j) {
vec3 coord1 = reflection(vec3(m_Samples[j]), rand) * vec3(rad);
ao += doAmbientOcclusion(texCoord + coord1.xy * 0.125, position, normal) - shadowFactor;
// Fine Detail
if (m_EnableFD) {
vec3 coord2 = reflection(vec3(m_Samples[j]), rand) * vec3(radFD0.5);
ao += doAmbientOcclusionFD(texCoord + coord2.xy * 0.05, position, normal) * (0.25-shadowFactor);
}
}
ao /= float(iterations) * (2.35-shadowFactor);
result = 1.0-ao;
}
gl_FragColor = vec4(vec3(result),1.0);
}[/java]
BasicSSAOBlur.frag (updated)
[java]uniform sampler2D m_Texture;
uniform sampler2D m_DepthTexture;
uniform sampler2D m_SSAOMap;
uniform vec2 g_Resolution;
uniform bool m_UseOnlyAo;
uniform bool m_UseAo;
uniform bool m_UseSmoothing;
uniform bool m_SmoothMore;
uniform float m_XScale;
uniform float m_YScale;
uniform vec2 m_FrustumNearFar;
const float epsilon = 0.005;
varying vec2 texCoord;
float random (vec4 seed4) {
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
return fract(sin(dot_product) * 43758.5453);
}
void main(){
vec4 ssao = vec4(0.0);//texture2D( m_SSAOMap,texCoord);
if (m_UseSmoothing) {
for (int i = 0; i < 4; i++) {
ssao += texture2D(m_SSAOMap,texCoord + (random(vec4(texCoord,-texCoord)*vec4(float(-i)))/200.0));
if (m_SmoothMore) ssao += texture2D(m_SSAOMap,texCoord + (random(vec4(-texCoord,texCoord)vec4(float(i)))/100.0));
}
if (m_SmoothMore) ssao /= 8.0;
else ssao /= 4.0;
} else {
ssao = texture2D(m_SSAOMap,texCoord);
}
vec4 color = texture2D(m_Texture,texCoord);
if (!m_UseAo && !m_UseOnlyAo)
gl_FragColor = color;
else if (m_UseAo && m_UseOnlyAo)
gl_FragColor = ssao;
else
gl_FragColor = colorssao;
}[/java]
Here is a video of what it does (prior to optimization):
http://youtu.be/2-Cxi1dsWtg