SSAO renderer on obj viewer makes the whole screen white

I have a simple 3d obj viewer that I try to add SSAO with.
Normal rendering works just fine but when I add SSAO (composer renderer), the whole screen turns all white.

I’ve tried making the value of light smaller, radius smaller, etc, but nothing seems to work. Kindly seeking your advise. Many thanks! Below is my code

import * as THREE from ‘three’;
import { OrbitControls } from ‘three/examples/jsm/controls/OrbitControls.js’;
import { OBJLoader } from ‘three/examples/jsm/loaders/OBJLoader.js’;
import { EffectComposer } from ‘three/examples/jsm/postprocessing/EffectComposer.js’;
import { RenderPass } from ‘three/examples/jsm/postprocessing/RenderPass.js’;
import { SSAOPass } from ‘three/examples/jsm/postprocessing/SSAOPass.js’;

// Scene, Camera, Renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 500, 800, 1000 );
camera.lookAt( 0, 0, 0 );

const renderer = new THREE.WebGLRenderer();
//renderer.outputEncoding = THREE.sRGBEncoding
renderer.setClearColor(0x000000, 1); // Set black background
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true; // Enable shadow mapping
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Choose shadow type (soft shadows)

document.body.appendChild(renderer.domElement);

// Orbit Controls
const controls = new OrbitControls(camera, renderer.domElement);

// Lighting
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.6 );
scene.add( ambientLight );

const pointLight = new THREE.PointLight( 0xffffff, 1 );
camera.add( pointLight );

const directionalLight = new THREE.DirectionalLight( 0xffffff, 2 );
//directionalLight.position.set( 1, 0.75, 0.5 ).normalize();
directionalLight.position.set(5, 5, 5); // Position the light
directionalLight.castShadow = true; // Enable shadow casting
directionalLight.shadow.radius = 8;

// Configure shadow settings for the light
directionalLight.shadow.mapSize.width = 1024; // Higher value improves shadow quality
directionalLight.shadow.mapSize.height = 1024;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 20;

scene.add( directionalLight );

const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));

const ssaoPass = new SSAOPass(scene, camera, window.innerWidth, window.innerHeight);
ssaoPass.kernelRadius = 4;
ssaoPass.minDistance = 0.01;
ssaoPass.maxDistance = 0.05;
composer.addPass(ssaoPass);

// Enable tone mapping and gamma correction
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.0; // Adjust as needed
renderer.outputEncoding = THREE.sRGBEncoding;

// Load OBJ Model
const loader = new OBJLoader();
loader.load(
‘//some url to obj model’,
(object) => {

const geometry = object.children[0].geometry;

geometry.rotateY(Math.PI); 
geometry.scale( 0.02,0.02,0.02 );
geometry.translate(-320, 60, -100);

////all white, not shadow related
//const material = new THREE.MeshBasicMaterial({ color: 0xffffff });

const material = new THREE.MeshStandardMaterial({ 
    color: 0xffffff, 
    roughness: 0.9, // Higher roughness for a more diffuse appearance
    metalness: 0 // Non-metallic for a purely diffuse look
  });
  
const mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true; // Enable shadow casting
scene.add( mesh );

//scene.add(object);

},
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + ‘% loaded’);
},
(error) => {
console.error(‘An error occurred:’, error);
}
);

// Animation Loop
function animate() {
requestAnimationFrame(animate);
controls.update(); // Update OrbitControls
//renderer.render(scene, camera);
composer.render();
}
animate();

// Handle Window Resize
window.addEventListener(‘resize’, () => {

renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

composer.setSize(window.innerWidth, window.innerHeight);
ssaoPass.setSize(window.innerWidth, window.innerHeight);
});

try:
ssaoPass.renderToScreen = true;

maybe?

Thanks for your reply! Sorry for late reply, I just managed to add the line. Unfortunately, it does not work :frowning:

Ensure your model has valid normals (for example, call geometry.computeVertexNormals();) and that your camera’s near/far planes fully enclose the object. The screen can turn white if the geometry is out of depth range or if SSAOPass parameters are too extreme. Try something like:

camera.near = 0.1;
camera.far = 3000;
camera.updateProjectionMatrix();
geometry.computeVertexNormals();
ssaoPass.kernelRadius = 16;
ssaoPass.minDistance = 0.001;
ssaoPass.maxDistance = 0.1;

Also, consider reducing your light intensity or verifying your object is lit correctly. If it still appears white, try changing ssaoPass.output to SSAOPass.OUTPUT.Depth or SSAOPass.OUTPUT.Normal to debug what the SSAOPass is seeing. Lastly, confirm you’re updating composer and ssaoPass sizes on window resize.

Hello, thank you so much for your reply. I’ve tried the line of codes you gave and unfortunately it is still white.

When I updated the output, it is actually showing something

for depth,
and

for normal.

What does this mean?

When using recent releases, add an instance of OutputPass at the end of your pass chain:

const outputPass = new OutputPass();
composer.addPass( outputPass );

Besides, the following code is legacy:

renderer.outputEncoding = THREE.sRGBEncoding;

Just remove it since the default output color space is sRGB now.

1 Like

Hi, thank you for your reply. I have tried the above suggestion but it is still showing white screen. Maybe I shall restart again and perhaps try the sample threejs code with ssao with another obj first…

1 Like

If you can start from scratch, consider to use the new WebGPURenderer with its node material. It has a new FX-system which is more performant and flexible compared to the previous EffectComposer. The AO demo is: three.js webgpu - ambient occlusion (GTAO)

We have added a bunch of common post processing techniques which are listed here:

WebGPU Post Processing Demos

1 Like