Enhance ambient occlusion effect with dual-layer SSAO and additional parameters
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
import { BasicShadowMap, DirectionalLight, HalfFloatType, Mesh, NoToneMapping, PCFShadowMap, PCFSoftShadowMap, PointLight, SpotLight, UnsignedByteType } from "three";
|
||||
import { BloomEffect, DepthOfFieldEffect, EffectComposer, EffectPass, NormalPass, RenderPass, SMAAEffect, SMAAPreset, SSAOEffect, ToneMappingEffect, ToneMappingMode } from "postprocessing";
|
||||
const AMBIENT_OCCLUSION_LUMINANCE_INFLUENCE = 0.15;
|
||||
const MIN_AMBIENT_OCCLUSION_EFFECT_RADIUS = 0.02;
|
||||
const MAX_AMBIENT_OCCLUSION_EFFECT_RADIUS = 0.2;
|
||||
const MIN_AMBIENT_OCCLUSION_SAMPLES = 12;
|
||||
const COARSE_AMBIENT_OCCLUSION_RESOLUTION_SCALE = 0.5;
|
||||
const DETAIL_AMBIENT_OCCLUSION_RESOLUTION_SCALE = 0.75;
|
||||
const DETAIL_AMBIENT_OCCLUSION_RADIUS_SCALE = 0.35;
|
||||
const COARSE_AMBIENT_OCCLUSION_INTENSITY_SCALE = 0.45;
|
||||
const DETAIL_AMBIENT_OCCLUSION_INTENSITY_SCALE = 0.35;
|
||||
export function resolveBoxVolumeRenderPaths(settings) {
|
||||
if (!settings.enabled) {
|
||||
return {
|
||||
@@ -44,6 +51,12 @@ export function configureAdvancedRenderingRenderer(renderer, settings) {
|
||||
renderer.toneMapping = NoToneMapping;
|
||||
renderer.toneMappingExposure = settings.toneMapping.exposure;
|
||||
}
|
||||
function clampAmbientOcclusionEffectRadius(radius) {
|
||||
return Math.min(Math.max(radius, MIN_AMBIENT_OCCLUSION_EFFECT_RADIUS), MAX_AMBIENT_OCCLUSION_EFFECT_RADIUS);
|
||||
}
|
||||
function getAmbientOcclusionSampleCount(samples) {
|
||||
return Math.max(samples, MIN_AMBIENT_OCCLUSION_SAMPLES);
|
||||
}
|
||||
export function createAdvancedRenderingComposer(renderer, scene, camera, settings) {
|
||||
// The scene is always rendered into the composer's offscreen targets first,
|
||||
// so those targets need depth for correct visibility even when no effect samples it.
|
||||
@@ -60,13 +73,24 @@ export function createAdvancedRenderingComposer(renderer, scene, camera, setting
|
||||
// a real normal buffer is supplied, which turns SSAO into speckled noise.
|
||||
const normalPass = new NormalPass(scene, camera);
|
||||
composer.addPass(normalPass);
|
||||
effects.push(new SSAOEffect(camera, normalPass.texture, {
|
||||
const ambientOcclusionRadius = clampAmbientOcclusionEffectRadius(settings.ambientOcclusion.radius);
|
||||
const ambientOcclusionSamples = getAmbientOcclusionSampleCount(settings.ambientOcclusion.samples);
|
||||
const detailAmbientOcclusionRadius = Math.max(ambientOcclusionRadius * DETAIL_AMBIENT_OCCLUSION_RADIUS_SCALE, MIN_AMBIENT_OCCLUSION_EFFECT_RADIUS);
|
||||
composer.addPass(new EffectPass(camera, new SSAOEffect(camera, normalPass.texture, {
|
||||
depthAwareUpsampling: true,
|
||||
luminanceInfluence: AMBIENT_OCCLUSION_LUMINANCE_INFLUENCE,
|
||||
samples: settings.ambientOcclusion.samples,
|
||||
radius: Math.min(settings.ambientOcclusion.radius, MAX_AMBIENT_OCCLUSION_EFFECT_RADIUS),
|
||||
intensity: settings.ambientOcclusion.intensity
|
||||
}));
|
||||
resolutionScale: COARSE_AMBIENT_OCCLUSION_RESOLUTION_SCALE,
|
||||
samples: ambientOcclusionSamples,
|
||||
radius: ambientOcclusionRadius,
|
||||
intensity: settings.ambientOcclusion.intensity * COARSE_AMBIENT_OCCLUSION_INTENSITY_SCALE
|
||||
}), new SSAOEffect(camera, normalPass.texture, {
|
||||
depthAwareUpsampling: true,
|
||||
luminanceInfluence: AMBIENT_OCCLUSION_LUMINANCE_INFLUENCE,
|
||||
resolutionScale: DETAIL_AMBIENT_OCCLUSION_RESOLUTION_SCALE,
|
||||
samples: ambientOcclusionSamples,
|
||||
radius: detailAmbientOcclusionRadius,
|
||||
intensity: settings.ambientOcclusion.intensity * DETAIL_AMBIENT_OCCLUSION_INTENSITY_SCALE
|
||||
})));
|
||||
}
|
||||
if (settings.bloom.enabled) {
|
||||
effects.push(new BloomEffect({
|
||||
|
||||
@@ -37,7 +37,14 @@ import type {
|
||||
} from "../document/world-settings";
|
||||
|
||||
const AMBIENT_OCCLUSION_LUMINANCE_INFLUENCE = 0.15;
|
||||
const MIN_AMBIENT_OCCLUSION_EFFECT_RADIUS = 0.02;
|
||||
const MAX_AMBIENT_OCCLUSION_EFFECT_RADIUS = 0.2;
|
||||
const MIN_AMBIENT_OCCLUSION_SAMPLES = 12;
|
||||
const COARSE_AMBIENT_OCCLUSION_RESOLUTION_SCALE = 0.5;
|
||||
const DETAIL_AMBIENT_OCCLUSION_RESOLUTION_SCALE = 0.75;
|
||||
const DETAIL_AMBIENT_OCCLUSION_RADIUS_SCALE = 0.35;
|
||||
const COARSE_AMBIENT_OCCLUSION_INTENSITY_SCALE = 0.45;
|
||||
const DETAIL_AMBIENT_OCCLUSION_INTENSITY_SCALE = 0.35;
|
||||
|
||||
export interface ResolvedBoxVolumeRenderPaths {
|
||||
fog: BoxVolumeRenderPath;
|
||||
@@ -91,6 +98,14 @@ export function configureAdvancedRenderingRenderer(renderer: WebGLRenderer, sett
|
||||
renderer.toneMappingExposure = settings.toneMapping.exposure;
|
||||
}
|
||||
|
||||
function clampAmbientOcclusionEffectRadius(radius: number) {
|
||||
return Math.min(Math.max(radius, MIN_AMBIENT_OCCLUSION_EFFECT_RADIUS), MAX_AMBIENT_OCCLUSION_EFFECT_RADIUS);
|
||||
}
|
||||
|
||||
function getAmbientOcclusionSampleCount(samples: number) {
|
||||
return Math.max(samples, MIN_AMBIENT_OCCLUSION_SAMPLES);
|
||||
}
|
||||
|
||||
export function createAdvancedRenderingComposer(
|
||||
renderer: WebGLRenderer,
|
||||
scene: Scene,
|
||||
@@ -108,7 +123,7 @@ export function createAdvancedRenderingComposer(
|
||||
|
||||
composer.addPass(new RenderPass(scene, camera));
|
||||
|
||||
const effects: Array<SSAOEffect | BloomEffect | DepthOfFieldEffect | ToneMappingEffect | SMAAEffect> = [];
|
||||
const effects: Array<BloomEffect | DepthOfFieldEffect | ToneMappingEffect | SMAAEffect> = [];
|
||||
|
||||
if (settings.ambientOcclusion.enabled) {
|
||||
// postprocessing's internal depth-downsampling path writes zero normals unless
|
||||
@@ -116,14 +131,33 @@ export function createAdvancedRenderingComposer(
|
||||
const normalPass = new NormalPass(scene, camera);
|
||||
composer.addPass(normalPass);
|
||||
|
||||
effects.push(
|
||||
new SSAOEffect(camera, normalPass.texture, {
|
||||
depthAwareUpsampling: true,
|
||||
luminanceInfluence: AMBIENT_OCCLUSION_LUMINANCE_INFLUENCE,
|
||||
samples: settings.ambientOcclusion.samples,
|
||||
radius: Math.min(settings.ambientOcclusion.radius, MAX_AMBIENT_OCCLUSION_EFFECT_RADIUS),
|
||||
intensity: settings.ambientOcclusion.intensity
|
||||
})
|
||||
const ambientOcclusionRadius = clampAmbientOcclusionEffectRadius(settings.ambientOcclusion.radius);
|
||||
const ambientOcclusionSamples = getAmbientOcclusionSampleCount(settings.ambientOcclusion.samples);
|
||||
const detailAmbientOcclusionRadius = Math.max(
|
||||
ambientOcclusionRadius * DETAIL_AMBIENT_OCCLUSION_RADIUS_SCALE,
|
||||
MIN_AMBIENT_OCCLUSION_EFFECT_RADIUS
|
||||
);
|
||||
|
||||
composer.addPass(
|
||||
new EffectPass(
|
||||
camera,
|
||||
new SSAOEffect(camera, normalPass.texture, {
|
||||
depthAwareUpsampling: true,
|
||||
luminanceInfluence: AMBIENT_OCCLUSION_LUMINANCE_INFLUENCE,
|
||||
resolutionScale: COARSE_AMBIENT_OCCLUSION_RESOLUTION_SCALE,
|
||||
samples: ambientOcclusionSamples,
|
||||
radius: ambientOcclusionRadius,
|
||||
intensity: settings.ambientOcclusion.intensity * COARSE_AMBIENT_OCCLUSION_INTENSITY_SCALE
|
||||
}),
|
||||
new SSAOEffect(camera, normalPass.texture, {
|
||||
depthAwareUpsampling: true,
|
||||
luminanceInfluence: AMBIENT_OCCLUSION_LUMINANCE_INFLUENCE,
|
||||
resolutionScale: DETAIL_AMBIENT_OCCLUSION_RESOLUTION_SCALE,
|
||||
samples: ambientOcclusionSamples,
|
||||
radius: detailAmbientOcclusionRadius,
|
||||
intensity: settings.ambientOcclusion.intensity * DETAIL_AMBIENT_OCCLUSION_INTENSITY_SCALE
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user