diff --git a/docs/examples/en/postprocessing/EffectComposer.html b/docs/examples/en/postprocessing/EffectComposer.html
index 9531cfc4561992..db75f3f86ee10d 100644
--- a/docs/examples/en/postprocessing/EffectComposer.html
+++ b/docs/examples/en/postprocessing/EffectComposer.html
@@ -41,6 +41,7 @@
Examples
[example:webgl_postprocessing_godrays postprocessing godrays]
[example:webgl_postprocessing_gtao postprocessing gtao]
[example:webgl_postprocessing_masking postprocessing masking]
+ [example:webgl_postprocessing_material_ao postprocessing material ao]
[example:webgl_postprocessing_outline postprocessing outline]
[example:webgl_postprocessing_pixel postprocessing pixelate]
[example:webgl_postprocessing_procedural postprocessing procedural]
diff --git a/docs/examples/zh/postprocessing/EffectComposer.html b/docs/examples/zh/postprocessing/EffectComposer.html
index 6d480877cc04e5..33d2aac17112d0 100644
--- a/docs/examples/zh/postprocessing/EffectComposer.html
+++ b/docs/examples/zh/postprocessing/EffectComposer.html
@@ -40,6 +40,7 @@ 例子
[example:webgl_postprocessing_godrays postprocessing godrays]
[example:webgl_postprocessing_gtao postprocessing gtao]
[example:webgl_postprocessing_masking postprocessing masking]
+ [example:webgl_postprocessing_material_ao postprocessing material ao]
[example:webgl_postprocessing_outline postprocessing outline]
[example:webgl_postprocessing_pixel postprocessing pixelate]
[example:webgl_postprocessing_procedural postprocessing procedural]
diff --git a/examples/files.json b/examples/files.json
index 63efedff6746fe..28087dc28c46ee 100644
--- a/examples/files.json
+++ b/examples/files.json
@@ -249,6 +249,7 @@
"webgl_postprocessing_gtao",
"webgl_postprocessing_rgb_halftone",
"webgl_postprocessing_masking",
+ "webgl_postprocessing_material_ao",
"webgl_postprocessing_ssaa",
"webgl_postprocessing_outline",
"webgl_postprocessing_pixel",
diff --git a/examples/jsm/materials/MeshPostProcessingMaterial.js b/examples/jsm/materials/MeshPostProcessingMaterial.js
new file mode 100644
index 00000000000000..d2fa48f9cbc46d
--- /dev/null
+++ b/examples/jsm/materials/MeshPostProcessingMaterial.js
@@ -0,0 +1,144 @@
+import { MeshPhysicalMaterial } from 'three';
+
+/**
+ * The aim of this mesh material is to use information from a post processing pass in the diffuse color pass.
+ * This material is based on the MeshPhysicalMaterial.
+ *
+ * In the current state, only the information of a screen space AO pass can be used in the material.
+ * Actually, the output of any screen space AO (SSAO, GTAO) can be used,
+ * as it is only necessary to provide the AO in one color channel of a texture,
+ * however the AO pass must be rendered prior to the color pass,
+ * which makes the post-processing pass somewhat of a pre-processing pass.
+ * Fot this purpose a new map (`aoPassMap`) is added to the material.
+ * The value of the map is used the same way as the `aoMap` value.
+ *
+ * Motivation to use the outputs AO pass directly in the material:
+ * The incident light of a fragment is composed of ambient light, direct light and indirect light
+ * Ambient Occlusion only occludes ambient light and environment light, but not direct light.
+ * Direct light is only occluded by geometry that casts shadows.
+ * And of course the emitted light should not be darkened by ambient occlusion either.
+ * This cannot be achieved if the AO post processing pass is simply blended with the diffuse render pass.
+ *
+ * Further extension work might be to use the output of an SSR pass or an HBIL pass from a previous frame.
+ * This would then create the possibility of SSR and IR depending on material properties such as `roughness`, `metalness` and `reflectivity`.
+**/
+
+class MeshPostProcessingMaterial extends MeshPhysicalMaterial {
+
+ constructor( parameters ) {
+
+ const aoPassMap = parameters.aoPassMap;
+ const aoPassMapScale = parameters.aoPassMapScale || 1.0;
+ delete parameters.aoPassMap;
+ delete parameters.aoPassMapScale;
+
+ super( parameters );
+
+ this.onBeforeCompile = this._onBeforeCompile;
+ this.customProgramCacheKey = this._customProgramCacheKey;
+ this._aoPassMap = aoPassMap;
+ this.aoPassMapScale = aoPassMapScale;
+ this._shader = null;
+
+ }
+
+ get aoPassMap() {
+
+ return this._aoPassMap;
+
+ }
+
+ set aoPassMap( aoPassMap ) {
+
+ this._aoPassMap = aoPassMap;
+ this.needsUpdate = true;
+ this._setUniforms();
+
+ }
+
+ _customProgramCacheKey() {
+
+ return this._aoPassMap !== undefined && this._aoPassMap !== null ? 'aoPassMap' : '';
+
+ }
+
+ _onBeforeCompile( shader ) {
+
+ this._shader = shader;
+
+ if ( this._aoPassMap !== undefined && this._aoPassMap !== null ) {
+
+ shader.fragmentShader = shader.fragmentShader.replace(
+ '#include ',
+ aomap_pars_fragment_replacement
+ );
+ shader.fragmentShader = shader.fragmentShader.replace(
+ '#include ',
+ aomap_fragment_replacement
+ );
+
+ }
+
+ this._setUniforms();
+
+ }
+
+ _setUniforms() {
+
+ if ( this._shader ) {
+
+ this._shader.uniforms.tAoPassMap = { value: this._aoPassMap };
+ this._shader.uniforms.aoPassMapScale = { value: this.aoPassMapScale };
+
+ }
+
+ }
+
+}
+
+const aomap_pars_fragment_replacement = /* glsl */`
+#ifdef USE_AOMAP
+
+ uniform sampler2D aoMap;
+ uniform float aoMapIntensity;
+
+#endif
+
+ uniform sampler2D tAoPassMap;
+ uniform float aoPassMapScale;
+`;
+
+const aomap_fragment_replacement = /* glsl */`
+#ifndef AOPASSMAP_SWIZZLE
+ #define AOPASSMAP_SWIZZLE r
+#endif
+ float ambientOcclusion = texelFetch( tAoPassMap, ivec2( gl_FragCoord.xy * aoPassMapScale ), 0 ).AOPASSMAP_SWIZZLE;
+
+#ifdef USE_AOMAP
+
+ // reads channel R, compatible with a combined OcclusionRoughnessMetallic (RGB) texture
+ ambientOcclusion = min( ambientOcclusion, texture2D( aoMap, vAoMapUv ).r );
+ ambientOcclusion *= ( ambientOcclusion - 1.0 ) * aoMapIntensity + 1.0;
+
+#endif
+
+ reflectedLight.indirectDiffuse *= ambientOcclusion;
+
+ #if defined( USE_CLEARCOAT )
+ clearcoatSpecularIndirect *= ambientOcclusion;
+ #endif
+
+ #if defined( USE_SHEEN )
+ sheenSpecularIndirect *= ambientOcclusion;
+ #endif
+
+ #if defined( USE_ENVMAP ) && defined( STANDARD )
+
+ float dotNV = saturate( dot( geometryNormal, geometryViewDir ) );
+
+ reflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );
+
+ #endif
+`;
+
+export { MeshPostProcessingMaterial };
diff --git a/examples/jsm/postprocessing/GTAOPass.js b/examples/jsm/postprocessing/GTAOPass.js
index 14a06338a48a26..ad0a76214bbcbc 100644
--- a/examples/jsm/postprocessing/GTAOPass.js
+++ b/examples/jsm/postprocessing/GTAOPass.js
@@ -162,6 +162,12 @@ class GTAOPass extends Pass {
}
+ get gtaoMap() {
+
+ return this.pdRenderTarget.texture;
+
+ }
+
setGBuffer( depthTexture, normalTexture ) {
if ( depthTexture !== undefined ) {
@@ -359,6 +365,9 @@ class GTAOPass extends Pass {
switch ( this.output ) {
+ case GTAOPass.OUTPUT.Off:
+ break;
+
case GTAOPass.OUTPUT.Diffuse:
this.copyMaterial.uniforms.tDiffuse.value = readBuffer.texture;
@@ -561,6 +570,7 @@ class GTAOPass extends Pass {
}
GTAOPass.OUTPUT = {
+ 'Off': - 1,
'Default': 0,
'Diffuse': 1,
'Depth': 2,
diff --git a/examples/screenshots/webgl_postprocessing_material_ao.jpg b/examples/screenshots/webgl_postprocessing_material_ao.jpg
new file mode 100644
index 00000000000000..210f06ddbe9577
Binary files /dev/null and b/examples/screenshots/webgl_postprocessing_material_ao.jpg differ
diff --git a/examples/tags.json b/examples/tags.json
index a5bf7deca1fb33..540e1e3c2809ea 100644
--- a/examples/tags.json
+++ b/examples/tags.json
@@ -88,6 +88,7 @@
"webgl_postprocessing_fxaa": [ "msaa", "multisampled" ],
"webgl_postprocessing_godrays": [ "light scattering" ],
"webgl_postprocessing_gtao": [ "ambient occlusion" ],
+ "webgl_postprocessing_material_ao": [ "ambient occlusion"],
"webgl_shadowmap_progressive": [ "shadow", "soft", "lightmap", "onBeforeCompile" ],
"webgl_postprocessing_ssaa": [ "msaa", "multisampled" ],
"webgl_postprocessing_ssaa_unbiased": [ "msaa", "multisampled" ],
diff --git a/examples/webgl_postprocessing_material_ao.html b/examples/webgl_postprocessing_material_ao.html
new file mode 100644
index 00000000000000..b97144e3740c02
--- /dev/null
+++ b/examples/webgl_postprocessing_material_ao.html
@@ -0,0 +1,278 @@
+
+
+
+ three.js webgl - postprocessing - GTAO
+
+
+
+
+
+
+
+
three.js - Mesh Post Processing Material by
Rabbid76
+
Improved application of the AO passes by using the AO directly in the material shader instead of simply blending with the whole scene
+
+
+
+
+
+
+