UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

193 lines (159 loc) 8.03 kB
import type { N8AOPostPass } from "n8ao"; import { Color, DepthFormat, DepthStencilFormat, DepthTexture, PerspectiveCamera, UnsignedInt248Type, UnsignedIntType, WebGLRenderTarget } from "three"; import { MODULES } from "../../../engine/engine_modules.js"; import { serializable } from "../../../engine/engine_serialization.js"; import { validate } from "../../../engine/engine_util_decorator.js"; import { getParam } from "../../../engine/engine_utils.js"; import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js"; import { VolumeParameter } from "../VolumeParameter.js"; import { registerCustomEffectType } from "../VolumeProfile.js"; const debugN8AO = getParam("debugN8AO"); // https://github.com/N8python/n8ao /**See (N8AO documentation)[https://github.com/N8python/n8ao] */ export enum ScreenSpaceAmbientOcclusionN8QualityMode { Performance = 0, Low = 1, Medium = 2, High = 3, Ultra = 4, } /** Screen Space Ambient Occlusion (SSAO) effect. * @category Effects * @group Components * @link [N8AO documentation](https://github.com/N8python/n8ao) */ export class ScreenSpaceAmbientOcclusionN8 extends PostProcessingEffect { get typeName() { return "ScreenSpaceAmbientOcclusionN8"; } get pass(): N8AOPostPass { return this._ssao; } @validate() @serializable() gammaCorrection: boolean = true; /** The most important parameter for your ambient occlusion effect. * Controls the radius/size of the ambient occlusion in world units. * Should be set to how far you want the occlusion to extend from a given object. * Set it too low, and AO becomes an edge detector. * Too high, and the AO becomes "soft" and might not highlight the details you want. * The radius should be one or two magnitudes less than scene scale: * if your scene is 10 units across, the radius should be between 0.1 and 1. If its 100, 1 to 10. * @default 1 */ @serializable(VolumeParameter) aoRadius: VolumeParameter = new VolumeParameter(1); /** The second most important parameter for your ambient occlusion effect. * Controls how fast the ambient occlusion fades away with distance in proportion to its radius. * Defaults to 1, and behind-the-scenes, is a calculated as a ratio of your radius (0.2 * distanceFalloff is the size used for attenuation). * Decreasing it reduces "haloing" artifacts and improves the accuracy of your occlusion, * but making it too small makes the ambient occlusion disappear entirely. * @default 1 */ @serializable(VolumeParameter) falloff: VolumeParameter = new VolumeParameter(1); /** A purely artistic control for the intensity of the AO - runs the ao through the function pow(ao, intensity), * which has the effect of darkening areas with more ambient occlusion. * Useful to make the effect more pronounced. * An intensity of 2 generally produces soft ambient occlusion that isn't too noticeable, * whereas one of 5 produces heavily prominent ambient occlusion. * @default 1 */ @serializable(VolumeParameter) intensity: VolumeParameter = new VolumeParameter(1); /** The color of the ambient occlusion. By default, it is black, but it can be changed to any color * to offer a crude approximation of global illumination. * Recommended in scenes where bounced light has a uniform "color", * for instance a scene that is predominantly lit by a blue sky. * The color is expected to be in the sRGB color space, and is automatically converted to linear space for you. * Keep the color pretty dark for sensible results. * @default new Color(0, 0, 0) */ @serializable(VolumeParameter) color: VolumeParameter = new VolumeParameter(new Color(0, 0, 0)); /** If you want the AO to calculate the radius based on screen space, you can do so by setting configuration.screenSpaceRadius to true. * This is useful for scenes where the camera is moving across different scales a lot, * or for scenes where the camera is very close to the objects. * @default false */ @validate() @serializable() screenspaceRadius: boolean = false; /** * The quality of the ambient occlusion effect. * @default ScreenSpaceAmbientOcclusionN8QualityMode.Medium */ @validate() @serializable() quality: ScreenSpaceAmbientOcclusionN8QualityMode = ScreenSpaceAmbientOcclusionN8QualityMode.Medium; private _ssao?: N8AOPostPass; onValidate(): void { if (this._ssao) { this._ssao.setQualityMode(ScreenSpaceAmbientOcclusionN8QualityMode[this.quality]); this._ssao.configuration.gammaCorrection = this.gammaCorrection; this._ssao.configuration.screenSpaceRadius = this.screenspaceRadius; } } onCreateEffect(): EffectProviderResult { const cam = this.context.mainCamera! as PerspectiveCamera; const width = this.context.domWidth; const height = this.context.domHeight; const ssao = this._ssao = new MODULES.POSTPROCESSING_AO.MODULE.N8AOPostPass( this.context.scene, cam, width, height ) as N8AOPostPass; ssao.name = "SSAO_N8"; const mode = ScreenSpaceAmbientOcclusionN8QualityMode[this.quality]; ssao.setQualityMode(mode); ssao.configuration.transparencyAware = false; // ssao.needsSwap = false; const renderTarget = new WebGLRenderTarget(width, height); ssao.configuration.beautyRenderTarget = renderTarget; ssao.configuration.autoRenderBeauty = false; // // If you just want a depth buffer // renderTarget.depthTexture = new DepthTexture(width, height, UnsignedIntType); // renderTarget.depthTexture.format = DepthFormat; // // If you want a depth buffer and a stencil buffer // renderTarget.depthTexture = new DepthTexture(width, height, UnsignedInt248Type); // renderTarget.depthTexture.format = DepthStencilFormat; ssao.configuration.gammaCorrection = this.gammaCorrection; ssao.configuration.screenSpaceRadius = this.screenspaceRadius; if (debugN8AO) { // ssao.debug = debugN8AO; ssao.enableDebugMode(); console.log(ssao); setInterval(() => { console.log("SSAO", ssao.lastTime); }, 1000); setInterval(() => { // ssao.enabled = !ssao.enabled; console.log("SSAO", ssao.enabled, { ssao, autoRenderBeauty: ssao.configuration.autoRenderBeauty }); }, 4000) } this.intensity.onValueChanged = newValue => { ssao.configuration.intensity = newValue; } this.falloff.onValueChanged = newValue => { ssao.configuration.distanceFalloff = newValue; } this.aoRadius.onValueChanged = newValue => { ssao.configuration.aoRadius = newValue; } this.color.onValueChanged = newValue => { if (!ssao.color) ssao.color = new Color(); ssao.configuration.color.copy(newValue); } // const normalPass = new MODULES.POSTPROCESSING.MODULE.NormalPass(this.context.scene, cam); // const depthDownsamplingPass = new MODULES.POSTPROCESSING.MODULE.DepthDownsamplingPass({ // normalBuffer: normalPass.texture, // resolutionScale: .1 // }); // const arr = new Array(); // arr.push(normalPass); // arr.push(depthDownsamplingPass); // arr.push(ssao); return ssao; } } registerCustomEffectType("ScreenSpaceAmbientOcclusionN8", ScreenSpaceAmbientOcclusionN8);