I have integrated and transformed the code of the subject, which can be used normally in the current version of playcanvas (version 1.35.0)
// --------------- POST EFFECT DEFINITION --------------- //
Object.assign(pc, function () {
/**
* @class
* @name pc.SSAOEffect
* @classdesc Implements the SSAOEffect post processing effect.
* @description Creates new instance of the post effect.
* @augments pc.PostEffect
* @param {pc.GraphicsDevice} graphicsDevice - The graphics device of the application.
* @property {number} offset Controls the offset of the effect.
* @property {number} darkness Controls the darkness of the effect.
*/
var SSAOEffect = function (graphicsDevice) {
pc.PostEffect.call(this, graphicsDevice);
// Shaders
var attributes = {
aPosition: pc.SEMANTIC_POSITION
};
var passThroughVert = [
"attribute vec2 aPosition;",
"",
"varying vec2 vUv0;",
"",
"void main(void)",
"{",
" gl_Position = vec4(aPosition, 0.0, 1.0);",
" vUv0 = (aPosition.xy + 1.0) * 0.5;",
"}"
].join("\n");
var ssaoFrag = [
"precision " + graphicsDevice.precision + " float;",
"uniform sampler2D uDepthMap;",
"uniform sampler2D uInputTexture;",
"varying vec2 vUv0;",
"uniform float total_strength;",
"",
"float unpackFloat(vec4 rgbaDepth) {",
" const vec4 bitShift = vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0);",
" float depth = dot(rgbaDepth, bitShift);",
" return depth;",
"}",
"",
"vec3 normal_from_depth(float depth, vec2 texcoords) {",
" const vec2 offset1 = vec2(0.0,0.001);",
" const vec2 offset2 = vec2(0.001,0.0);",
"",
" float depth1 = unpackFloat(texture2D(uDepthMap, texcoords + offset1));",
" float depth2 = unpackFloat(texture2D(uDepthMap, texcoords + offset2));",
"",
" vec3 p1 = vec3(offset1, depth1 - depth);",
" vec3 p2 = vec3(offset2, depth2 - depth);",
"",
" vec3 normal = cross(p1, p2);",
" normal.z = -normal.z;",
" return normalize(normal);",
"}",
"",
"",
"void main(void) {",
" const float area = 0.0075;",
" const float radius = 0.0017;",
"",
" const int samples = 16;",
" vec3 sample_sphere[samples];",
" sample_sphere[0] = vec3( 0.5381, 0.1856,-0.4319);",
" sample_sphere[1] = vec3( 0.1379, 0.2486, 0.4430);",
" sample_sphere[2] = vec3( 0.3371, 0.5679,-0.0057);",
" sample_sphere[3] = vec3(-0.6999,-0.0451,-0.0019);",
" sample_sphere[4] = vec3( 0.0689,-0.1598,-0.8547);",
" sample_sphere[5] = vec3( 0.0560, 0.0069,-0.1843);",
" sample_sphere[6] = vec3(-0.0146, 0.1402, 0.0762);",
" sample_sphere[7] = vec3( 0.0100,-0.1924,-0.0344);",
" sample_sphere[8] = vec3(-0.3577,-0.5301,-0.4358);",
" sample_sphere[9] = vec3(-0.3169, 0.1063, 0.0158);",
" sample_sphere[10] = vec3( 0.0103,-0.5869, 0.0046);",
" sample_sphere[11] = vec3(-0.0897,-0.4940, 0.3287);",
" sample_sphere[12] = vec3( 0.7119,-0.0154,-0.0918);",
" sample_sphere[13] = vec3(-0.0533, 0.0596,-0.5411);",
" sample_sphere[14] = vec3( 0.0352,-0.0631, 0.5460);",
" sample_sphere[15] = vec3(-0.4776, 0.2847,-0.0271);",
"",
" float depth = unpackFloat(texture2D(uDepthMap, vUv0));",
"",
" vec3 position = vec3(vUv0, depth);",
" vec3 normal = normal_from_depth(depth, vUv0);",
"",
" float radius_depth = radius/depth;",
" float occlusion = 0.0;",
" float difference;",
" for(int i=0; i < samples; i++) {",
" vec3 ray = radius_depth * reflect(sample_sphere[i], normalize(vec3(0.1,0.5,0.3)));",
" vec3 hemi_ray = position + sign(dot(ray,normal)) * ray;",
"",
" float occ_depth = unpackFloat(texture2D(uDepthMap, clamp(hemi_ray.xy,0.0,1.0)));",
" difference = (occ_depth - depth);",
" occlusion += smoothstep(0.0,area, clamp(difference,0.0,1.0));",
" }",
"",
" float ao = total_strength * occlusion * (1.0 / float(samples));",
" gl_FragColor = mix(texture2D(uInputTexture, vUv0), vec4(0,0,0,1), vec4(ao, ao, ao, 1));",
"}"
].join("\n");
this.ssaoShader = new pc.Shader(graphicsDevice, {
attributes: attributes,
vshader: passThroughVert,
fshader: ssaoFrag
});
this.strength = 0.4;
};
SSAOEffect.prototype = Object.create(pc.PostEffect.prototype);
SSAOEffect.prototype.constructor = SSAOEffect;
Object.assign(SSAOEffect.prototype, {
render: function (inputTarget, outputTarget, rect) {
var device = this.device;
var scope = device.scope;
scope.resolve("uInputTexture").setValue(inputTarget.colorBuffer);
scope.resolve("total_strength").setValue(this.strength);
pc.drawFullscreenQuad(device, outputTarget, this.vertexBuffer, this.ssaoShader, rect);
}
});
return {
SSAOEffect: SSAOEffect
};
}());
// ----------------- SCRIPT DEFINITION ------------------ //
var SSAOForum = pc.createScript('ssaoForum');
SSAOForum.attributes.add('strength',{type:'number', default:0.5});
// initialize code called once per entity
SSAOForum.prototype.initialize = function () {
this.effect = new pc.SSAOEffect(this.app.graphicsDevice);
this.effect.strength = this.strength;
this.on('attr', function (name, value) {
this.effect[name] = value;
}, this);
var queue = this.entity.camera.postEffects;
queue.addEffect(this.effect);
this.on('state', function (enabled) {
if (enabled) {
queue.addEffect(this.effect);
} else {
queue.removeEffect(this.effect);
}
});
this.on('destroy', function () {
queue.removeEffect(this.effect);
});
};
No need to add requestDepthMap() in the current version of Playcanvas. Actually, if you do this, you won’t get the normal map correctly.