SSILVB

https://cybereality.com/screen-space-indirect-lighting-with-visibility-bitmask-improvement-to-gtao-ssao-real-time-ambient-occlusion-algorithm-glsl-shader-implementation/

by Cody Bennett

HTML

<script type="importmap">
	{
		"imports": {
			"three": "https://unpkg.com/[email protected]/build/three.module.min.js",
			"three/examples/": "https://unpkg.com/[email protected]/examples/"
		}
	}
</script>

CSS

body {
  margin: 0;
}

canvas {
  display: block;
}

JavaScript

import * as THREE from 'three'
import Stats from 'three/examples/jsm/libs/stats.module.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'

THREE.Texture.DEFAULT_ANISOTROPY = 16

const stats = new Stats()
document.body.appendChild(stats.dom)

const renderer = new THREE.WebGLRenderer({ alpha: true })
renderer.toneMapping = THREE.AgXToneMapping
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFSoftShadowMap
document.body.appendChild(renderer.domElement)

const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 50)
camera.position.set(0, 1, 6.5)

const controls = new OrbitControls(camera, renderer.domElement)

const scene = new THREE.Scene()

const gltfLoader = new GLTFLoader()
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.5/')
gltfLoader.setDRACOLoader(dracoLoader)

gltfLoader.load('https://rawgit.com/KhronosGroup/glTF-Sample-Models/master/2.0/Sponza/glTF/Sponza.gltf', (gltf) => {
  const sponza = gltf.scene.children[0]
  sponza.position.set(0.25, -2 / 3, 0)
  sponza.rotation.set(0, Math.PI / 2, 0)

  sponza.traverse((node) => {
    if (node.isMesh) {
      node.material.metalness = 0
      node.castShadow = true
      node.receiveShadow = true
      node.material.onBeforeCompile = (shader) => {
        shader.fragmentShader = shader.fragmentShader
          .replace('void main', 'layout(location = 1) out highp vec4 gNormalDepth;\nvoid main')
          .replace(
            '#include <opaque_fragment>',
            '#include <opaque_fragment>\ngNormalDepth = vec4(normal * 0.5 + 0.5, 1);',
          )
      }
    }
  })
  scene.add(sponza)
})

const ambientLight = new THREE.AmbientLight(undefined, 0.2 * Math.PI)
scene.add(ambientLight)

const directionalLight = new THREE.DirectionalLight(0xffffff, 3 *...