Jump to content

Is SSAO Possible? Has anyone achieved it?


Stephen Andrews
 Share

Recommended Posts

I assume that screen-space ambient occlusion is possible using BabylonJS's shaders system, but I have so far been hampered by my lack of knowledge of GLSL and shaders in general to be able to understand anyone else's implementations enough to port them.

 

Has anyone else managed to accomplish this feat in BabylonJS? How so?

 

If not, could someone give me some tips for getting started? I understand the basics of hooking up shaders to Babylon materials and the screen.

Link to comment
Share on other sites

Hey Stephen,

 

You'll find here the the SSAO implementation :)

 

The javascript code to create the scene (it creates boxes + different passes + different post-processes).

Shaders : Defining the depth shader for the depth pass needed by the SSAO post-process

Create scene saver: creates a pass to save the "original color" of the scene

Create ssao combine: Combines the SSAO output with the scene saver RTT

 

SSAO will use different passes to be computed :

    - Compute depth pass

    - SSAO pass

    - Blur pass

    - Combine SSAO output with the original color of the scene

///// Shaders//BABYLON.Engine.ShadersRepository = 'Babylon/Shaders/';BABYLON.Effect.ShadersStore["depthVertexShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"attribute vec3 position;\n" +"uniform mat4 worldViewProjection;\n" +"uniform float far;\n" +"varying vec4 coords;\n" +"void main(void) {\n" +"   gl_Position = worldViewProjection * vec4(position, 1.0);\n" +"   coords = vec4(far, gl_Position.y, gl_Position.z, gl_Position.w);" +"}";BABYLON.Effect.ShadersStore["depthPixelShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"varying vec4 coords;\n" +"void main(void) {\n" +"   float depth = coords.z / coords.x;\n" +"   gl_FragColor = vec4(depth, depth * depth, 0.0, 1.0);\n" +"}\n" +"";///// Create engine and scene + camera//var canvas = document.getElementById('renderCanvas');var engine = new BABYLON.Engine(canvas, true);var scene = new BABYLON.Scene(engine);var sceneColor = scene.clearColor;var camera = new BABYLON.FreeCamera("free_camera", new BABYLON.Vector3(0, 5, -10), scene);camera.minZ = 0.1;camera.maxZ = 200.0;camera.setTarget(new BABYLON.Vector3.Zero());camera.attachControl(canvas, false);//// Create scene//var light = new BABYLON.DirectionalLight("globalLight", new BABYLON.Vector3(-1, -2, -1), scene);light.position = new BABYLON.Vector3(10, 10, 0);///// Create scene saver//var screenRTT = new BABYLON.RenderTargetTexture('SceneRTT', 1024, scene, false, true);scene.customRenderTargets.push(screenRTT);///// Create depth material//var depthMaterial = new BABYLON.ShaderMaterial('depth', scene, 'depth', {    uniforms: ['worldViewProjection'],    attributes: ['position']});///// Create render target and configure (for depth pass)//var depthRTT = new BABYLON.RenderTargetTexture('DepthRTT', 1024, scene, false, true);scene.customRenderTargets.push(depthRTT);depthRTT.onBeforeRender = function () {    scene.clearColor = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0);    for (var i = 0; i < depthRTT.renderList.length; i++) {        depthRTT.renderList[i]._savedMaterial = depthRTT.renderList[i].material;        depthRTT.renderList[i].material = depthMaterial;    }};depthRTT.onAfterRender = function () {    scene.clearColor = sceneColor;    for (var i = 0; i < depthRTT.renderList.length; i++)        depthRTT.renderList[i].material = depthRTT.renderList[i]._savedMaterial;};//// Create SSAO post-process//var ssaoPostProcess = new BABYLON.PostProcess('ssao', 'ssao', [],['DepthMapSampler', 'RandomMapSampler'], 1, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, true);var ssaoRandomTexture = new BABYLON.Texture('./textures/random.png', scene, true, false, BABYLON.Texture.BILINEAR_SAMPLINGMODE);ssaoPostProcess.onApply = function (effect) {    effect.setTexture('DepthMapSampler', depthRTT);    effect.setTexture('RandomMapSampler', ssaoRandomTexture);};        //// Create blur post-process//var blurPostProcess = new BABYLON.BlurPostProcess('blur_postprocess', new BABYLON.Vector2(1.0, 1.0), 1, 1, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, true);//// Create ssao combine//var ssaoCombinePostProcess = new BABYLON.PostProcess('ssaoCombine', 'ssaoCombine', [], ['ColorMapSampler'], 1, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, true);ssaoCombinePostProcess.onApply = function (effect) {    effect.setTexture('ColorMapSampler', screenRTT);};//// Create objects :)//for (var i = 0; i < 6; i++) {    for (var j = 0; j < 6; j++) {        for (var k = 0; k < 6; k++) {            var cube = BABYLON.Mesh.CreateBox('cube', 1.0, scene, true);            cube.position = new BABYLON.Vector3(i * 1.0 + 2.0, j * 2.0 + 1.0, k * 3.0 + 3.0);            cube.rotation = new BABYLON.Vector3(Math.floor((Math.random() * 360) + 1), Math.floor((Math.random() * 360) + 1), Math.floor((Math.random() * 360) + 1));            cube.material = new BABYLON.StandardMaterial('mat', scene);            depthRTT.renderList.push(cube);            screenRTT.renderList.push(cube);        }    }}//// Update scene//engine.runRenderLoop(function () {    depthMaterial.setFloat('far', camera.maxZ);    scene.render();});

Now, you'll find the SSAO implementation I found on internet (mine was too difficult for WebGL :( ) and the SSAO combine

ssao.fragment.fx :

#ifdef GL_ESprecision highp float;#endifvarying vec2 vUV;uniform sampler2D textureSampler;uniform sampler2D DepthMapSampler;uniform sampler2D RandomMapSampler;vec3 normalFromDepth(float depth, vec2 coords) {	const vec2 offset1 = vec2(0.0, 0.001);	const vec2 offset2 = vec2(0.001, 0.0);	float depth1 = texture2D(DepthMapSampler, coords + offset1).r;	float depth2 = texture2D(DepthMapSampler, coords + offset2).r;	vec3 p1 = vec3(offset1, depth1 - depth2);	vec3 p2 = vec3(offset2, depth2 - depth1);	vec3 normal = cross(p1, p2);	normal.z = -normal.z;	return normalize(normal);}void main(){	const float totalStrength = 10.0;	const float base = 0.2;	const float area = 0.0075;	const float fallOff = 0.01;	const float radius = 0.0002;	const int samples = 16;	vec3 sampleSphere[samples];	sampleSphere[0] = vec3(0.5381, 0.1856, -0.4319);	sampleSphere[1] = vec3(0.1379, 0.2486, 0.4430);	sampleSphere[2] = vec3(0.3371, 0.5679, -0.0057);	sampleSphere[3] = vec3(-0.6999, -0.0451, -0.0019);	sampleSphere[4] = vec3(0.0689, -0.1598, -0.8547);	sampleSphere[5] = vec3(0.0560, 0.0069, -0.1843);	sampleSphere[6] = vec3(-0.0146, 0.1402, 0.0762);	sampleSphere[7] = vec3(0.0100, -0.1924, -0.0344);	sampleSphere[8] = vec3(-0.3577, -0.5301, -0.4358);	sampleSphere[9] = vec3(-0.3169, 0.1063, 0.0158);	sampleSphere[10] = vec3(0.0103, -0.5869, 0.0046);	sampleSphere[11] = vec3(-0.0897, -0.4940, 0.3287);	sampleSphere[12] = vec3(0.7119, -0.0154, -0.0918);	sampleSphere[13] = vec3(-0.0533, 0.0596, -0.5411);	sampleSphere[14] = vec3(0.0352, -0.0631, 0.5460);	sampleSphere[15] = vec3(-0.4776, 0.2847, -0.0271);	vec3 random = normalize(texture2D(RandomMapSampler, vUV * 4.0).rgb);	float depth = texture2D(DepthMapSampler, vUV).r;	vec3 position = vec3(vUV, depth);	vec3 normal = normalFromDepth(depth, vUV);	float radiusDepth = radius / depth;	float occlusion = 0.0;	for (int i = 0; i < samples; i++) {		vec3 ray = radiusDepth * reflect(sampleSphere[i], random);		vec3 hemiRay = position + sign(dot(ray, normal)) * ray;		float occlusionDepth = texture2D(DepthMapSampler, clamp(hemiRay.xy, 0.0, 1.0)).r;		float difference = depth - occlusionDepth;		occlusion += step(fallOff, difference) * (1.0 - smoothstep(fallOff, area, difference));	}	float ao = 1.0 - totalStrength * occlusion * (1.0 / float(samples));	vec4 color = vec4(1.0, 1.0, 1.0, 1.0);	gl_FragColor = color * clamp(ao + base, 0.0, 1.0);	gl_FragColor.a = 1.0;}

ssaoCombine.fragment.fx :

#ifdef GL_ESprecision highp float;#endifvarying vec2 vUV;uniform sampler2D textureSampler;uniform sampler2D ColorMapSampler;void main(){	gl_FragColor = texture2D(textureSampler, vUV) * texture2D(ColorMapSampler, vUV);}

Concerning the .fx files (shaders), you can put it in the Babylon/Shaders folder

 

Concerning the random texture (ssaoRandomTexture in the JS code), you can find it here, or generate it with your custom algorithm

 

Don't hesitate if you have problems when implementing my code. I'll create a zip containing everything (don't know yet where to upload it xD)

Link to comment
Share on other sites

Excellent job Luaacro! I'll get about to testing that right away. It looks a bit complicated, but the results are worth it.

 

Next up: performance testing!

 

EDIT: First issue:

WebGL: INVALID_ENUM: activeTexture: texture unit out of range

 

FPS is down to about 9, weird outline shows.

 

Screenshot_from_2014_12_06_07_23_25.jpg

 

Experimentation time > :D

 

EDIT2:

A plain vanilla take on your code has the same result, but with an extra error:

 [.WebGLRenderingContext]GL ERROR :GL_INVALID_OPERATION : glDrawElementsInstancedANGLE: attempt to draw with all attributes having non-zero divisors

Link to comment
Share on other sites

Oh ? I also get the warnings, the warnings I didn't saw when developing, damn me ! -_-

I'll try to find a solution to that.

 

For the FPS, the SSAO is a very expansive post-process, I don't know if WebGL is enough mature for that (up to 35 values picking per pixel). And I get same errors using IE, FireFox and Chrome now :(

 

Joshcamas, no problems because 2 years ago I was like you lol. If you read the code with this article (http://en.wikipedia.org/wiki/Screen_space_ambient_occlusion) you'll understand :)

Link to comment
Share on other sites

Oh ? I also get the warnings, the warnings I didn't saw when developing, damn me ! -_-

I'll try to find a solution to that.

 

For the FPS, the SSAO is a very expansive post-process, I don't know if WebGL is enough mature for that (up to 35 values picking per pixel). And I get same errors using IE, FireFox and Chrome now :(

Excellent work, you're doing great. :D

 

Just wondering, what should the result look like? (So I can compare to make sure things are working properly) [screenshot?]

Link to comment
Share on other sites

Still working on warnings ^^

 

But you can find results here : http://en.wikipedia.org/wiki/Ambient_occlusion

It takes the original scene color + SSAO pass + combine pass, as you can see in the code above

I know what it's *supposed* to look like, just wasn't sure what your implementation would look like. :3

Link to comment
Share on other sites

You can try this implementation (with parameters). Don't hesitate to play with parameters in "ssaoPostProcess.onApply" and test with a real mesh (like a house or a room)

///// Shaders//BABYLON.Engine.ShadersRepository = 'Babylon/Shaders/';BABYLON.Effect.ShadersStore["simpleVertexShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"attribute vec3 position;\n" +"attribute vec2 uv;\n" +"uniform mat4 worldViewProjection;\n" +"varying vec2 vUV;\n" +"void main(void) {\n" +"   gl_Position = worldViewProjection * vec4(position, 1.0);\n" +"   vUV = uv;" +"}";BABYLON.Effect.ShadersStore["simplePixelShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"uniform sampler2D textureSampler;\n" +"varying vec2 vUV;\n" +"void main(void) {\n" +"   gl_FragColor = texture2D(textureSampler, vUV);\n" +"}\n" +"";BABYLON.Effect.ShadersStore["depthVertexShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"attribute vec3 position;\n" +"uniform mat4 worldViewProjection;\n" +"uniform float far;\n" +"varying vec4 coords;\n" +"void main(void) {\n" +"   gl_Position = worldViewProjection * vec4(position, 1.0);\n" +"   coords = vec4(far, gl_Position.y, gl_Position.z, gl_Position.w);" +"}";BABYLON.Effect.ShadersStore["depthPixelShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"varying vec4 coords;\n" +"void main(void) {\n" +"   float depth = coords.z / coords.x;\n" +"   gl_FragColor = vec4(depth, depth * depth, 0.0, 1.0);\n" +"}\n" +"";///// Create engine and scene + camera//var canvas = document.getElementById('renderCanvas');var engine = new BABYLON.Engine(canvas, true);var scene = new BABYLON.Scene(engine);var sceneColor = new BABYLON.Color3(1, 1, 1);//scene.clearColor;var camera = new BABYLON.FreeCamera("free_camera", new BABYLON.Vector3(0, 5, -10), scene);camera.minZ = 0.1;camera.maxZ = 200.0;camera.setTarget(new BABYLON.Vector3.Zero());camera.attachControl(canvas, true);//// Create scene//var light = new BABYLON.DirectionalLight("globalLight", new BABYLON.Vector3(-1, -2, -1), scene);light.position = new BABYLON.Vector3(10, 10, 0);///// Create scene saver//var screenRTT = new BABYLON.RenderTargetTexture('SceneRTT', 2048, scene, false, true);scene.customRenderTargets.push(screenRTT);screenRTT.onBeforeRender = function () { };screenRTT.onAfterRender = function () { };///// Create depth material//var depthMaterial = new BABYLON.ShaderMaterial('depth', scene, 'depth', {    uniforms: ['worldViewProjection'],    attributes: ['position']});///// Create render target and configure (for depth pass)//var depthRTT = new BABYLON.RenderTargetTexture('DepthRTT', 2048, scene, false, true);scene.customRenderTargets.push(depthRTT);depthRTT.farValue = 50.0;depthRTT.clearColor = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0);depthRTT.onBeforeRender = function () {    depthMaterial.setFloat('far', depthRTT.farValue);    scene.clearColor = depthRTT.clearColor;    for (var i = 0; i < depthRTT.renderList.length; i++) {        depthRTT.renderList[i]._savedMaterial = depthRTT.renderList[i].material;        depthRTT.renderList[i].material = depthMaterial;    }};depthRTT.onAfterRender = function () {    scene.clearColor = sceneColor;    for (var i = 0; i < depthRTT.renderList.length; i++)        depthRTT.renderList[i].material = depthRTT.renderList[i]._savedMaterial;};//// Create SSAO post-process//var ssaoPostProcess = new BABYLON.PostProcess('ssao', 'ssao', ['totalStrength', 'fallOff', 'radius', 'area'],['RandomMapSampler'], 1, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, true);var ssaoRandomTexture = new BABYLON.Texture('./textures/random.png', scene, true, false, BABYLON.Texture.BILINEAR_SAMPLINGMODE);ssaoPostProcess.onApply = function (effect) {    effect.setFloat('totalStrength', 10.0);    effect.setFloat('fallOff', 0.001);    effect.setFloat('radius', 0.0002);    effect.setFloat('area', 0.0075);    effect.setTexture('textureSampler', depthRTT);    effect.setTexture('RandomMapSampler', ssaoRandomTexture);};//// Create blur post-process//var blurPostProcess = new BABYLON.BlurPostProcess('blur_postprocess', new BABYLON.Vector2(1.0, 0.0), 1, 1.0, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, true);//// Create ssao combine//var ssaoCombinePostProcess = new BABYLON.PostProcess('ssaoCombine', 'ssaoCombine', [], ['ColorMapSampler'], 0.25, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, true);ssaoCombinePostProcess.onApply = function (effect) {    effect.setTexture('ColorMapSampler', screenRTT);};//// Create objects :)//var material = new BABYLON.ShaderMaterial('simple', scene, 'simple', { samplers: ['textureSampler'] });var creationCount = 6;for (var i = 0; i < creationCount; i++) {    for (var j = 0; j < creationCount; j++) {        for (var k = 0; k < creationCount; k++) {            var cube = BABYLON.Mesh.CreateBox('cube' + i + '' + j + '' + k, 1.0, scene, false);            cube.position = new BABYLON.Vector3(i * 1.0 + 2.0, j * 2.0 + 1.0, k * 3.0 + 3.0);            cube.rotation = new BABYLON.Vector3(Math.floor((Math.random() * 360) + 1), Math.floor((Math.random() * 360) + 1), Math.floor((Math.random() * 360) + 1));            cube.material = material;            depthRTT.renderList.push(cube);            screenRTT.renderList.push(cube);        }    }}//// Update scene//var wallTexture = new BABYLON.Texture('./textures/wall.jpg', scene, false, false, BABYLON.Texture.BILINEAR_SAMPLINGMODE);engine.runRenderLoop(function () {    material.setTexture('textureSampler', wallTexture);    scene.render();});

SSAO Post-process

#ifdef GL_ESprecision highp float;#endifvarying vec2 vUV;uniform sampler2D textureSampler;uniform sampler2D RandomMapSampler;uniform float totalStrength;uniform float fallOff;uniform float radius;uniform float area;vec3 normalFromDepth(float depth, vec2 coords) {	const vec2 offset1 = vec2(0.0, 0.001);	const vec2 offset2 = vec2(0.001, 0.0);	float depth1 = texture2D(textureSampler, coords + offset1).r;	float depth2 = texture2D(textureSampler, coords + offset2).r;	vec3 p1 = vec3(offset1, depth1 - depth2);	vec3 p2 = vec3(offset2, depth2 - depth1);	vec3 normal = cross(p1, p2);	normal.z = -normal.z;	return normalize(normal);}void main(){	const float base = 0.2;	const int samples = 16;	vec3 sampleSphere[samples];	sampleSphere[0] = vec3(0.5381, 0.1856, -0.4319);	sampleSphere[1] = vec3(0.1379, 0.2486, 0.4430);	sampleSphere[2] = vec3(0.3371, 0.5679, -0.0057);	sampleSphere[3] = vec3(-0.6999, -0.0451, -0.0019);	sampleSphere[4] = vec3(0.0689, -0.1598, -0.8547);	sampleSphere[5] = vec3(0.0560, 0.0069, -0.1843);	sampleSphere[6] = vec3(-0.0146, 0.1402, 0.0762);	sampleSphere[7] = vec3(0.0100, -0.1924, -0.0344);	sampleSphere[8] = vec3(-0.3577, -0.5301, -0.4358);	sampleSphere[9] = vec3(-0.3169, 0.1063, 0.0158);	sampleSphere[10] = vec3(0.0103, -0.5869, 0.0046);	sampleSphere[11] = vec3(-0.0897, -0.4940, 0.3287);	sampleSphere[12] = vec3(0.7119, -0.0154, -0.0918);	sampleSphere[13] = vec3(-0.0533, 0.0596, -0.5411);	sampleSphere[14] = vec3(0.0352, -0.0631, 0.5460);	sampleSphere[15] = vec3(-0.4776, 0.2847, -0.0271);	vec3 random = normalize(texture2D(RandomMapSampler, vUV * 4.0).rgb);	float depth = texture2D(textureSampler, vUV).r;	vec3 position = vec3(vUV, depth);	vec3 normal = normalFromDepth(depth, vUV);	float radiusDepth = radius / depth;	float occlusion = 0.0;	for (int i = 0; i < samples; i++) {		vec3 ray = radiusDepth * reflect(sampleSphere[i], random);		vec3 hemiRay = position + sign(dot(ray, normal)) * ray;		float occlusionDepth = texture2D(textureSampler, clamp(hemiRay.xy, 0.0, 1.0)).r;		float difference = depth - occlusionDepth;		occlusion += step(fallOff, difference) * (1.0 - smoothstep(fallOff, area, difference));	}	float ao = 1.0 - totalStrength * occlusion * (1.0 / float(samples));	vec4 color = vec4(1.0, 1.0, 1.0, 1.0);	gl_FragColor = color * clamp(ao + base, 0.0, 1.0);	gl_FragColor.a = 1.0;}

The error "INVALID_OPERATION: drawElementsInstancedANGLE" appear when drawing the cubes, I don't know why :(

Also, for the rendering offsets (we can see an offset between the scene and the SSAO effect when moving the camera) I don't why it happen. I think we'll have to ask Deltakosh ^^"

Link to comment
Share on other sites

///// Shaders//BABYLON.Engine.ShadersRepository = 'Babylon/Shaders/';BABYLON.Effect.ShadersStore["simpleVertexShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"attribute vec3 position;\n" +"attribute vec2 uv;\n" +"uniform mat4 worldViewProjection;\n" +"varying vec2 vUV;\n" +"void main(void) {\n" +"   gl_Position = worldViewProjection * vec4(position, 1.0);\n" +"   vUV = uv;" +"}";BABYLON.Effect.ShadersStore["simplePixelShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"uniform sampler2D textureSampler;\n" +"varying vec2 vUV;\n" +"void main(void) {\n" +"   gl_FragColor = texture2D(textureSampler, vUV);\n" +"}\n" +"";BABYLON.Effect.ShadersStore["depthVertexShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"attribute vec3 position;\n" +"uniform mat4 worldViewProjection;\n" +"uniform float far;\n" +"varying vec4 coords;\n" +"void main(void) {\n" +"   gl_Position = worldViewProjection * vec4(position, 1.0);\n" +"   coords = vec4(far, gl_Position.y, gl_Position.z, gl_Position.w);" +"}";BABYLON.Effect.ShadersStore["depthPixelShader"] ="#ifdef GL_ES\n" +"precision highp float;\n" +"#endif\n" +"varying vec4 coords;\n" +"void main(void) {\n" +"   float depth = coords.z / coords.x;\n" +"   gl_FragColor = vec4(depth, depth * depth, 0.0, 1.0);\n" +"}\n" +"";///// Create engine and scene + camera//var canvas = document.getElementById('renderCanvas');var engine = new BABYLON.Engine(canvas, true);var scene = new BABYLON.Scene(engine);var sceneColor = new BABYLON.Color3(1, 1, 1);//scene.clearColor;var camera = new BABYLON.FreeCamera("free_camera", new BABYLON.Vector3(0, 5, 0), scene);camera.minZ = 0.1;camera.maxZ = 1000.0;camera.setTarget(new BABYLON.Vector3.Zero());camera.attachControl(canvas, true);camera.speed = 15;camera.inertia = 0;camera.angularSensibility = 100;//// Create scene//var light = new BABYLON.DirectionalLight("globalLight", new BABYLON.Vector3(-1, -2, -1), scene);light.position = new BABYLON.Vector3(10, 10, 0);///// Create scene saver//var screenRTT = new BABYLON.PassPostProcess('SceneRTT', 1.0, camera);///// Create depth material//var depthMaterial = new BABYLON.ShaderMaterial('depth', scene, 'depth', {    uniforms: ['worldViewProjection'],    attributes: ['position']});///// Create render target and configure (for depth pass)//var depthRTT = new BABYLON.RenderTargetTexture('DepthRTT', 1024, scene, false, true);scene.customRenderTargets.push(depthRTT);depthRTT.farValue = 1000.0;depthRTT.clearColor = new BABYLON.Color4(1.0, 1.0, 1.0, 1.0);depthRTT.onBeforeRender = function () {    depthMaterial.setFloat('far', depthRTT.farValue);    scene.clearColor = depthRTT.clearColor;    for (var i = 0; i < depthRTT.renderList.length; i++) {        depthRTT.renderList[i]._savedMaterial = depthRTT.renderList[i].material;        depthRTT.renderList[i].material = depthMaterial;    }};depthRTT.onAfterRender = function () {    scene.clearColor = sceneColor;    for (var i = 0; i < depthRTT.renderList.length; i++)        depthRTT.renderList[i].material = depthRTT.renderList[i]._savedMaterial;};//// Create SSAO post-process//var ssaoPostProcess = new BABYLON.PostProcess('ssao', 'ssao', ['totalStrength', 'fallOff', 'radius', 'area'],['RandomMapSampler'], 1, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false);var ssaoRandomTexture = new BABYLON.Texture('./textures/random2.png', scene, true, false, BABYLON.Texture.BILINEAR_SAMPLINGMODE);ssaoPostProcess.onApply = function (effect) {    effect.setFloat('numSamples', 16);    effect.setFloat('totalStrength', 3);    effect.setFloat('fallOff', 0.01);    effect.setFloat('radius', 0.002);    effect.setFloat('area', 0.0075);    effect.setTexture('textureSampler', depthRTT);    effect.setTexture('RandomMapSampler', ssaoRandomTexture);};        //// Create blur post-process//var blurPostProcessHorizontal = new BABYLON.BlurPostProcess('blur_postprocess', new BABYLON.Vector2(1.0, 0.0), 3, 1.0, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false);var blurPostProcessVertial = new BABYLON.BlurPostProcess('blur_postprocess', new BABYLON.Vector2(0.0, 1.0), 3, 1.0, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false);//// Create ssao combine//// Swith to SSAO RTT to see the result, and vice versa to the combined RTTvar renderColor = true;window.onclick = function () {    renderColor = !renderColor;}var ssaoCombinePostProcess = new BABYLON.PostProcess('ssaoCombine', 'ssaoCombine', [], ['ColorMapSampler'], 0.25, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false);ssaoCombinePostProcess.onApply = function (effect) {    if (renderColor)        effect.setTextureFromPostProcess('ColorMapSampler', screenRTT);    else        effect.setTextureFromPostProcess('ColorMapSampler', blurPostProcessVertial);};//// Create objects :)//// You can find the models here : https://github.com/BabylonJS/Samples/tree/master/Scenes/RobotBABYLON.SceneLoader.ImportMesh('', './samples/', 'Robot.babylon', scene, function (meshes, particleSystems, skeletons) {    for (var i = 0; i < meshes.length; i++) {        depthRTT.renderList.push(meshes[i]);    }});//// Update scene//var wallTexture = new BABYLON.Texture('./textures/wall.jpg', scene, false, false, BABYLON.Texture.BILINEAR_SAMPLINGMODE);engine.runRenderLoop(function () {    scene.render();});

and the SSAO code :

#ifdef GL_ESprecision highp float;#endifvarying vec2 vUV;uniform sampler2D textureSampler;uniform sampler2D RandomMapSampler;uniform float totalStrength;uniform float fallOff;uniform float radius;uniform float area;vec3 normalFromDepth(float depth, vec2 coords) {	const vec2 offset1 = vec2(0.0, 0.001);	const vec2 offset2 = vec2(0.001, 0.0);	float depth1 = texture2D(textureSampler, coords + offset1).r;	float depth2 = texture2D(textureSampler, coords + offset2).r;	vec3 p1 = vec3(offset1, depth1 - depth2);	vec3 p2 = vec3(offset2, depth2 - depth1);	vec3 normal = cross(p1, p2);	normal.z = -normal.z;	return normalize(normal);}void main(){	const float base = 0.2;	const int samples = 16;	vec3 sampleSphere[samples];	sampleSphere[0] = vec3(0.5381, 0.1856, -0.4319);	sampleSphere[1] = vec3(0.1379, 0.2486, 0.4430);	sampleSphere[2] = vec3(0.3371, 0.5679, -0.0057);	sampleSphere[3] = vec3(-0.6999, -0.0451, -0.0019);	sampleSphere[4] = vec3(0.0689, -0.1598, -0.8547);	sampleSphere[5] = vec3(0.0560, 0.0069, -0.1843);	sampleSphere[6] = vec3(-0.0146, 0.1402, 0.0762);	sampleSphere[7] = vec3(0.0100, -0.1924, -0.0344);	sampleSphere[8] = vec3(-0.3577, -0.5301, -0.4358);	sampleSphere[9] = vec3(-0.3169, 0.1063, 0.0158);	sampleSphere[10] = vec3(0.0103, -0.5869, 0.0046);	sampleSphere[11] = vec3(-0.0897, -0.4940, 0.3287);	sampleSphere[12] = vec3(0.7119, -0.0154, -0.0918);	sampleSphere[13] = vec3(-0.0533, 0.0596, -0.5411);	sampleSphere[14] = vec3(0.0352, -0.0631, 0.5460);	sampleSphere[15] = vec3(-0.4776, 0.2847, -0.0271);	vec3 random = normalize(texture2D(RandomMapSampler, vUV * 4.0).rgb);	float depth = texture2D(textureSampler, vUV).r;	vec3 position = vec3(vUV, depth);	vec3 normal = normalFromDepth(depth, vUV);	float radiusDepth = radius / depth;	float occlusion = 0.0;	for (int i = 0; i < samples; i++) {		vec3 ray = radiusDepth * reflect(sampleSphere[i], random);		vec3 hemiRay = position + sign(dot(ray, normal)) * ray;		float occlusionDepth = texture2D(textureSampler, clamp(hemiRay.xy, 0.0, 1.0)).r;		float difference = depth - occlusionDepth;		occlusion += step(fallOff, difference) * (1.0 - smoothstep(fallOff, area, difference));	}	float ao = 1.0 - totalStrength * occlusion * (1.0 / float(samples));	vec4 color = vec4(1.0, 1.0, 1.0, 1.0);	gl_FragColor = color * clamp(ao + base, 0.0, 1.0);	gl_FragColor.a = 1.0;}

You can find the scene I load in the example at https://github.com/BabylonJS/Samples/tree/master/Scenes/Robot

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...