Stephen Andrews Posted November 30, 2014 Share Posted November 30, 2014 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. Quote Link to comment Share on other sites More sharing options...
joshcamas Posted November 30, 2014 Share Posted November 30, 2014 At first I saw "Is SAO Possible?" And I was confused why you would ask that. SAO Quote Link to comment Share on other sites More sharing options...
julien-moreau Posted December 1, 2014 Share Posted December 1, 2014 Hey, Hello TriBlade9. I think it's possible (never tried to do with BabylonJS).I'll try an implementation I wrote for OpenGL (not ES) and i'll share if it works Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted December 1, 2014 Share Posted December 1, 2014 THis is on our roadmap for 2.0 Quote Link to comment Share on other sites More sharing options...
Stephen Andrews Posted December 1, 2014 Author Share Posted December 1, 2014 Hey, Hello TriBlade9. I think it's possible (never tried to do with BabylonJS).I'll try an implementation I wrote for OpenGL (not ES) and i'll share if it works Awesome! Glad to see someone who knows shaders. :3 THis is on our roadmap for 2.0Great, I'll keep an eye on the repo. Thanks! Quote Link to comment Share on other sites More sharing options...
julien-moreau Posted December 4, 2014 Share Posted December 4, 2014 Good news, I almost got it ! Just have to create a configurable post-process and clean the code with an example Quote Link to comment Share on other sites More sharing options...
Stephen Andrews Posted December 4, 2014 Author Share Posted December 4, 2014 Good news, I almost got it ! Just have to create a configurable post-process and clean the code with an exampleAWESOME! I can't believe you got it working so fast! Quote Link to comment Share on other sites More sharing options...
julien-moreau Posted December 5, 2014 Share Posted December 5, 2014 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-processCreate scene saver: creates a pass to save the "original color" of the sceneCreate 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 combinessao.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) Stephen Andrews 1 Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted December 5, 2014 Share Posted December 5, 2014 Sounds like you should create a PR julien-moreau and Stephen Andrews 2 Quote Link to comment Share on other sites More sharing options...
Stephen Andrews Posted December 5, 2014 Author Share Posted December 5, 2014 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. Experimentation time > 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 Quote Link to comment Share on other sites More sharing options...
joshcamas Posted December 6, 2014 Share Posted December 6, 2014 Sorry if this is a dumb question, but what exactly IS ssao? :S Quote Link to comment Share on other sites More sharing options...
julien-moreau Posted December 6, 2014 Share Posted December 6, 2014 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 Quote Link to comment Share on other sites More sharing options...
Stephen Andrews Posted December 6, 2014 Author Share Posted December 6, 2014 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. Just wondering, what should the result look like? (So I can compare to make sure things are working properly) [screenshot?] Quote Link to comment Share on other sites More sharing options...
julien-moreau Posted December 7, 2014 Share Posted December 7, 2014 Still working on warnings ^^ But you can find results here : http://en.wikipedia.org/wiki/Ambient_occlusionIt takes the original scene color + SSAO pass + combine pass, as you can see in the code above Quote Link to comment Share on other sites More sharing options...
Stephen Andrews Posted December 7, 2014 Author Share Posted December 7, 2014 Still working on warnings ^^ But you can find results here : http://en.wikipedia.org/wiki/Ambient_occlusionIt takes the original scene color + SSAO pass + combine pass, as you can see in the code aboveI know what it's *supposed* to look like, just wasn't sure what your implementation would look like. :3 Quote Link to comment Share on other sites More sharing options...
julien-moreau Posted December 8, 2014 Share Posted December 8, 2014 My implementation looks like the screenshot you shared ^^The warnings and errors disappeared and got better parameters, I'm going to share ! =D Quote Link to comment Share on other sites More sharing options...
Stephen Andrews Posted December 8, 2014 Author Share Posted December 8, 2014 My implementation looks like the screenshot you shared ^^The warnings and errors disappeared and got better parameters, I'm going to share ! =DGlad you got it fixed. ;3 However, your implementation doesn't look much like SSAO, more like just drawing noisy outlines. Or I'm just mistaken? Quote Link to comment Share on other sites More sharing options...
julien-moreau Posted December 8, 2014 Share Posted December 8, 2014 What image are you comparing with ?Here it looks like : Try this implementation using a real mesh (like the wikipedia article) and you'll see it is the same thing ^^ Quote Link to comment Share on other sites More sharing options...
julien-moreau Posted December 8, 2014 Share Posted December 8, 2014 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 ^^" Quote Link to comment Share on other sites More sharing options...
Stephen Andrews Posted December 8, 2014 Author Share Posted December 8, 2014 What image are you comparing with ?Here it looks like : Try this implementation using a real mesh (like the wikipedia article) and you'll see it is the same thing ^^Okay, I'll test that soon enough.Is there a larger version of that image? xD Quote Link to comment Share on other sites More sharing options...
julien-moreau Posted December 12, 2014 Share Posted December 12, 2014 ///// 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 RaananW 1 Quote Link to comment Share on other sites More sharing options...
Stephen Andrews Posted December 12, 2014 Author Share Posted December 12, 2014 kk, tyvm. Just did a fresh re-install of Ubuntu, as I was running out of space, and now a lot of stuff is broken. I'll do some testing when I get everything working again. :3 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.