Git Product home page Git Product logo

n8ao's Introduction

N8AO

npm version github twitter

An efficient and visually pleasing implementation of SSAO with an emphasis on temporal stability and artist control.

AO is critical for creating a sense of depth in any 3D scene, and it does so by darkening parts of the scene that geometry blocks light from reaching. This effect is most noticeable in corners, crevices, and other areas where light is occluded. I'd recommend using this package in any scene that looks "flat" or "fake", or in any scene with vague depth cues and a lack of strong directional lighting.

Example (Source code in /example)

Scene w/ AO applied:

screenshot

(Left) Scene w/o AO, (Right) Scene w/ AO:

screenshot

Installation

From npm: npm install n8ao -> import {N8AOPass} from "n8ao"

From cdn: import {N8AOPass} from "https://unpkg.com/n8ao@latest/dist/N8AO.js"

Or just download dist/N8AO.js and import {N8AOPass} from "N8AO.js"

In order to ensure maximum compatibility, you must have the packages "three" and "postprocessing" defined in your environment - you can do this by CDN, as in the examples, or by installing them via npm.

Usage

It's very simple - N8AOPass is just a threejs postprocessing pass.

Import EffectComposer and:

const composer = new EffectComposer(renderer);
// N8AOPass replaces RenderPass
const n8aopass = new N8AOPass(
        scene,
        camera,
        width,
        height
    );
composer.addPass(n8aopass);

This is all you need to do. The effect should work out of the box with any vanilla three.js scene, and as long as the depth buffer is being written to, generate ambient occlusion.

Use of SMAAPass (as hardware antialiasing does NOT work with ambient occlusion) is recommended to reduce aliasing.

Gamma correction is enabled by default, but it should be disabled if you have a gamma correction pass later in your postprocessing pipeline, to avoid double-correcting your colors:

n8aopass.configuration.gammaCorrection = false;

Usage (Postprocessing)

If you are using the pmndrs/postprocessing package, N8AO is compatible with it. Simply do:

import { N8AOPostPass } from "n8ao";
import { EffectComposer, RenderPass } from "postprocessing";

// ... 

const composer = new EffectComposer(renderer);
/* The only difference is that N8AOPostPass requires a RenderPass before it, whereas N8AOPass replaces the render pass. Everything else is identical. */
composer.addPass(new RenderPass(scene, camera));
const n8aopass = new N8AOPostPass(
    scene,
    camera,
    width,
    height
);
composer.addPass(n8aopass)

/* SMAA Recommended */
composer.addPass(new EffectPass(camera, new SMAAEffect({
    preset: SMAAPreset.ULTRA
})));

N8AOPostPass's API is identical to that of N8AOPass (so all docs below apply), except it is compatible with pmndrs/postprocessing.

Small note: N8AOPostPass's configuration.gammaCorrection is automatically set to the correct value based on its position in your postprocessing pipeline. If it is the last pass, it is set to true. Otherwise, it is set to false. This is to ensure that gamma correction is only applied once. However, sometimes this automatic detection fails, so if you are getting washed out colors, try setting configuration.gammaCorrection to false, and if you are getting dark colors, try setting it to true.

Usage (Detailed)

N8AOPass is designed to be as easy to use as possible. It works with logarithmic depth buffers and orthographic cameras, supports materials with custom vertex displacement and alpha clipping, and automatically detects the presence of these things so you do not need to deal with user-side configuration.

However, some tweaking is often necessary to make sure your AO effect looks proper and does not suffer from artifacts. There are four principal parameters that control the visual "look" of the AO effect: aoRadius, distanceFalloff, intensity, and color. They can be changed in the following manner:

n8aopass.configuration.aoRadius = 5.0;
n8aopass.configuration.distanceFalloff = 1.0;
n8aopass.configuration.intensity = 5.0;
n8aopass.configuration.color = new THREE.Color(0, 0, 0);

They are covered below:

aoRadius: number - 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.

Image 1 Image 2 Image 3
Radius 1 Radius 5 Radius 10

distanceFalloff: number - 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.

Image 1 Image 2 Image 3
Distance Falloff 0.1 Distance Falloff 1 Distance Falloff 5

Migration Notice

The API changed slightly with N8AO 1.7 - the only change you should have to make is adjusting your distanceFalloff parameter - choosing 1.0 is a safe value. For the exact same results you had before, you can do distanceFalloff = 5.0 * oldDistanceFalloff / radius.

intensity: number - 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.

color: THREE.Color - 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.

Image 1 Image 2 Image 3
Color Black (Normal AO) Color Blue (Appropriate) Color Red (Too Bright)

Screen Space Radius

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.

When screenSpaceRadius is set to true, the aoRadius parameter represents the size of the ambient occlusion effect in pixels (recommended to be set between 16 and 64). The distanceFalloff parameter becomes a ratio, representing the percent of the screen space radius at which the AO should fade away - it should be set to 0.2 in most cases, but it accepts any value between 0 and 1 (technically even higher than 1, though that is not recommended).

Using your own render target

If you're utilizing the standard N8AOPass, there might be a situation where you have a pre-existing render target with a depth buffer that you'd prefer N8AOPass to use, instead of it generating a new one. To accomplish this, you can assign your render target to n8aopass.beautyRenderTarget.

N8AOPass will still render to n8aopass.beautyRenderTarget by default, but you can change this by setting n8aopass.configuration.autoRenderBeauty to false. If you do this, it's up to you to render the scene to n8aopass.beautyRenderTarget before using N8AOPass.

Finally, your render target must have a depth buffer attached to it. Otherwise, N8AOPass will not work and may fail silently.

You can attach a depth buffer to your render target by doing:

const renderTarget = new THREE.WebGLRenderTarget(width, height);
// If you just want a depth buffer
renderTarget.depthTexture = new THREE.DepthTexture(width, height, THREE.UnsignedIntType);
renderTarget.depthTexture.format = THREE.DepthFormat;
// If you want a depth buffer and a stencil buffer
renderTarget.depthTexture = new THREE.DepthTexture(width, height, THREE.UnsignedInt248Type);
renderTarget.depthTexture.format = THREE.DepthStencilFormat;

Performance

N8AOPass has a "half-resolution" mode for performance-critical applications. Enabling it is as simple as doing:

n8aopass.configuration.halfRes = true;

This will cause the AO to be calculated at half the resolution of the screen, and then upscaled to the full resolution. This is a great way to get a performance boost (generally 2x-4x) at the cost of some quality (the AO will lack fine details and temporal stability will be slightly reduced).

The half-resolution mode uses depth-aware upscaling by default, and this generally incurs a fixed cost of around 1ms. The AO effect looks horrible without depth-aware upscaling, so it is not recommended to disable it. However, if performance is truly that critical, you can do so by setting configuration.depthAwareUpsampling to false.

On top of half-resolution mode,N8AOPass comes with a wide variety of quality presets (which can be used with or without half-resolution mode), and you can even manually edit the settings to your liking. You can switch between quality modes (the default is Medium) by doing:

n8ao.setQualityMode("Low"); // Or any other quality mode

The quality modes are as follows:

Temporal stability refers to how consistent the AO is from frame to frame - it's important for a smooth experience.

Quality Mode AO Samples Denoise Samples Denoise Radius Best For
Performance (Less temporal stability, a bit noisy) 8 4 12 Mobile, Low-end iGPUs and laptops
Low (Temporally stable, but low-frequency noise) 16 4 12 High-End Mobile, iGPUs, laptops
Medium (Temporally stable and barely any noise) 16 8 12 High-End Mobile, laptops, desktops
High (Significantly sharper AO, barely any noise) 64 8 6 Desktops, dedicated GPUs
Ultra (Sharp AO, No visible noise whatsoever) 64 16 6 Desktops, dedicated GPUs

Generally, half-res mode at "Ultra" quality is slightly slower than full-res mode at "Performance" quality, but produces significantly better results.

If you wish to make entirely custom quality setup, you can manually change aoSamples, denoiseSamples and the denoiseRadius in the configuration object.

n8aopass.configuration.aoSamples = 16;
n8aopass.configuration.denoiseSamples = 8;
n8aopass.configuration.denoiseRadius = 12;

Either way, changing the quality or any of the above variables is expensive as it forces a recompile of all the shaders used in the AO effect. It is recommended to do this only once, at the start of your application. Merely setting the values each frame to some constant does not trigger recompile, however.

Debug Mode

If you want to track the exact amount of time the AO render pass is taking in your scene, you can enable debug mode by doing:

n8aopass.enableDebugMode(); // Disable with n8aopass.disableDebugMode();

Then, the n8aopass.lastTime variable, which is normally undefined, will have a value set each frame which represents the time, in milliseconds, the AO took to render (the value typically lags behind a few frames due to the CPU and GPU being slightly out of sync). This is useful for debugging performance issues.

Note that debug mode relies on WebGL features that are not available in all browsers - so make sure you are using a recent version of a Chromium browser while debugging. If your browser does not support these extra features (EXT_disjoint_timer_query_webgl2), debug mode will not work and an error will be thrown. The rest of the AO will still function as normal.

Display Modes

N8AOPass comes with a variety of display modes that can be used to debug/showcase the AO effect. They can be switched between by doing:

n8aopass.setDisplayMode("AO"); // Or any other display mode

The display modes available are:

Display Mode Description
Combined Standard option, composites the AO effect onto the scene to modulate lighting - what you should use in production screenshot
AO Shows only the AO effect as a black (completely occluded) and white (no occlusion) image screenshot
No AO Shows only the scene without the AO effect screenshot
Split Shows the scene with and without the AO effect side-by-side (divided by a white line in the middle) screenshot
Split AO Shows the AO effect as a black and white image, and the scene with the AO effect applied side-by-side (divided by a white line in the middle) screenshot

Transparency

N8AO supports transparency as best as it can - transparent objects with depthWrite disabled will not occlude anything and look completely correct. Transparent object with depthWrite enabled may lead to slight artifacts, but on the whole look fine (as long as their alpha value isn't too low).

The transparency solution used by N8AO is based of auxillary render target storing the accumulated alpha for each pixel - meaning that in order for transparency to work, all transparent objects will be rendered twice. This normally isn't a problem, but if you have a lot of transparent objects that fill up a large portion of the screen, it can be a significant performance hit.

Transparency is automatically enabled in scenes that have transparent objects in them, but can be set manually via configuration.transparencyAware:

n8aopass.configuration.transparencyAware = true;

Setting this value disables automatic transparency detection.

You can also force N8AO to treat a transparent object as opaque (useful if you are using transparency in a non-traditional manner and want N8AO to ignore it - for instance, with three.js's ShadowMesh), by setting treatAsOpaque to true in the object's userData:

mesh.userData.treatAsOpaque = true;

Accumulation

When the camera is still, you can enable the accumulation of samples across frames, which will reduce noise and improve the quality of the AO effect. This is done by setting configuration.accumulate to true:

n8aopass.configuration.accumulate = true;

For the best results, denoiseRadius should be set to 0 and denoiseSamples should be set to 1. This will ensure that the AO effect is not blurred, and that the accumulation is purely temporal.

The accumulation effect works best in scenes with no motion - as it does not calculate motion vectors and will only work with the camera still. If the camera is moving, the accumulation effect will be disabled automatically. But if an object is moving, N8AO won't be able to pick up on that and the object's ambient occlusion will become blurred.

Stencil

N8AOPass supports stencil buffers, but you must enable them via configuration.stencil:

n8aopass.configuration.stencil = true;

N8AOPostPass does not have such an option, as pmndrs/postprocessing has its own API for stencil buffers, which is shown below:

 const composer = new EffectComposer(renderer, {
        stencilBuffer: true, // stencil
        depthBuffer: true,
        frameBufferType: THREE.HalfFloatType
});
const renderPass = new RenderPass(scene, camera);
renderPass.clearPass.setClearFlags(true, true, true); // Ensures that the render pass clears the stencil buffer
composer.addPass(renderPass);
const n8aopass = new N8AOPostPass(
        scene,
        camera,
        clientWidth,
        clientHeight
    );
composer.addPass(n8aopass);

Compatibility

N8AOPass is compatible with all modern browsers that support WebGL 2.0 (WebGL 1 is not supported), but using three.js version r152 or later is recommended.

The pass is self-contained, and renders the scene automatically. The render target containing the scene texture (and depth) is available as n8aopass.beautyRenderTarget if you wish to use it for other purposes (for instance, using a depth buffer later in the rendering pipeline). All pass logic is self-contained and the pass should not be hard to modify if necessary.

Limitations

Like all screen space methods, geometry that is offscreen or is blocked by another object will not actually occlude anything. Haloing is still a minor issue in some cases, but it is not very noticeable.

Generally, the effect will appear to be grounded completely in world-space, with few view dependent artifacts. Only if one is specifically looking for them will they be found.

Contributing

Clone the repo:

git clone https://github.com/N8python/n8ao.git

Start the dev server:

npm run dev

The example can be accessed localhost:8080/example. The source code for the example is in /example.

License

A CC0 license is used for this project. You can do whatever you want with it, no attribution is required. However, if you do use it, I'd love to hear about it!

Credits

Too many papers and inspirations to count, but here's a list of resources that have been helpful to me:

https://threejs.org/examples/?q=pcss#webgl_shadowmap_pcss https://www.shadertoy.com/view/4l3yRM https://learnopengl.com/Advanced-Lighting/SSAO https://github.com/mrdoob/three.js/blob/dev/examples/jsm/postprocessing/SSAOPass.js https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/SSAOEffect.js~SSAOEffect.html https://github.com/Calinou/free-blue-noise-textures https://iquilezles.org/articles/multiresaocc/

n8ao's People

Contributors

codyjasonbennett avatar naive17 avatar strandedkitty avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

n8ao's Issues

N8AO + Bloom doesn't work when multisampling enabled

I have a pmndrs/postprocessing setup that looks like this:

RenderPass
N8AOPass #1
N8AOPass #2
EffectPass with Bloom + SMAA

With composer.multisampling set to 0, it works as expected. If I set multisampling to anything other than 0, both N8AOPass #2 and the Bloom pass stop producing any results. (As if they're disabled.)

You mentioned in discord that multisampling sometimes causes artifacts with SSAO, but it would be nice to have the option.

when camera far number too big have some problem...

I am developing a map application based on three. js, and I need to set the camera far number very big ,such as 1e10,
At this point, the color of distant objects will turn black, such as "sky.js“, and I don't know what happened...

normal

image

with ao

image

Fragment shader error resulting in black objects

I am using N8AO via @react-three/postprocessing. On most devices - both mobile and desktop - it works well.

However, I recently got a Pixel Fold device, and noticed that all of the objects utilizing n8ao are completely black. (It may be worth noting that the objects seem to be black specifically because I'm using the default black color for the AO. If I change the AO color, then the objects just become "tinted" with the chosen color.)

Inspecting the device, I see the following error(s):

THREE.WebGLProgram: Shader Error 0 - VALIDATE_STATUS false

Program Info Log: Fragment shader is not compiled.

0:125: S0032: no default precision defined for variable 'vec2[4]'0:125: S0032: no default precision defined for variable 'vec2[4]'
Screenshot 2024-02-12 at 7 23 42 PM

If I remove this effect, the issue goes away (though I obviously lose my AO).

Based on the error, I tried setting a default precision on the whole gl object I'm providing to my r3f Canvas, but that doesn't seem to fix it. I also tried using a React error boundary around the effect so it could be disabled in cases where it wouldn't work, but I'm guessing the error is happening outside of what React sees, so it didn't fix it.

I verified that my device supports WebGL2.

I tried on Chrome, Firefox, and the Samsung browser on the Pixel Fold, and they all exhibit the same behavior on that device.

Working (Macbook Pro) Not working (Pixel Fold)
Screenshot 2024-02-12 at 7 42 06 PM image

Live website

I know there are several layers of abstraction at play (react-postprocessing, postprocessing, react-three-fiber), but it seems that using other effects don't exhibit the same issue, so I'm assuming it's something to do with this effect. I'm happy to file this elsewhere if the issue isn't here though.

Issues w/ AO at large distances from the origin

When I integrated your AO plug-in into the map application, I found that the Ambient occlusion function failed. My test found that my model was located at a position far from the (0,0,0) point, such as (13487434.764630988, -6.397349827894406, -3741689.4034150834). At this time, my camera's observation position would also be at a large number of positions. When I moved the model to the (0,0,0) point, the Ambient occlusion function could work normally again, I think if the position of the camera is too large, it will cause the function to fail?

AO Visible in Direct Light

The SSAO looks excellent, but it is rendering in direct lighting. Is there a way for luminance to affect the ssao in some way? Thanks for this library!

Shader errors?

Hi @N8python, I'm trying to use n8ao in a scene on a custom mapbox layer and running into the following two errors, would you have any idea what these may be and how to resolve?

image

image

Debug Mode Question / Issue

I am seeing that my lastTime is sometimes double what my entire total frame render time is? How is this possible?

I am running at 60FPS, but the lastTime variable in debug mode is showing 20-30ms which would put me out of 60FPS.

Also, thank you so much for this incredible work. I have been trying everything available for literally years and this is the first thing to actually work and have good documentation! Kudos!

About the new AO color implementation

My understanding is that AO is about darkening, but this isn't always the case in your new AO color implementation.

gl_FragColor = vec4( mix(sceneTexel.rgb, color, 1.0 - finalAo), sceneTexel.a);

If color is black (default), everything is fine. However, imagine the scenario when color is brighter than the sceneTexel. The AO color would actually lighten up the pixel. Shouldn't the AO color be a "multiply" operation, something like this?

gl_FragColor = vec4( sceneTexel.rgb * mix(color, vec3(1.0), finalAo), sceneTexel.a);

Incompatible with ThreeJS Helpers

When TransformControls, ShadowMaterial, and/or GridHelper are rendering, the AO buffer seems to get overwritten or confused. The N8AO settings affect those effects.

If anyone can't get N8AO working no matter what they do, remove all helpers or shadowmaterial from your world and reload.

Colors issue with THREE.js r156

Hello,
I've been using N8AO with THREE.js r150.
After upgrade to THREE.js r156 the colors are washed out, is there anything that can be done on my side or is it an incompatibility with this release?

pass.setRenderer is not a function

When I instantiate it like this:

const composer = new EffectComposer(renderer);
// N8AOPass replaces RenderPass
const n8aopass = new N8AOPass(
        scene,
        camera,
        width,
        height
    );
composer.addPass(n8aopass);

I get this error:

postprocessing.esm.js:7768 Uncaught TypeError: pass.setRenderer is not a function
    at EffectComposer.addPass (postprocessing.esm.js:7768:10)

I am using this packages:

"three": "^0.152.2",
"postprocessing": "^6.31.0",

excluding objects

Thank you for your amazing work! Would it be possible to exclude certain objects from AO? I have several PNG Sprites that have transparent backgrounds. the AO effect makes the transparent backgrounds "visible". Would be great if I could exclude these sprites from the AO pass.

Multiple instances of Three js being imported

heyyyy !!! 👋

so I'm testing the pass and I got this warning WARNING: Multiple instances of Three.js being imported.

so checked the node modules folder and there's another node modules inside your npm package
n8

and the package.json has

 "dependencies": {
        "three": "^0.152.2"
    },

I guess three should be peerDependency instead of regular dependency like in https://github.com/pmndrs/postprocessing/blob/3e6ea9d8fddd2ca2d269e2182752f8199b8248af/package.json#L88-L89

Awesome work as always !!

Dramatically boost performance by lowering AO resolution

I love the look of N8AO! However, the render performance for low end machines isn't really good enough even on very low settings, I want to hit 60fps ideally across all devices which is critical for my usage case. At the moment I would have to turn off N8AO if the FPS dropped below this level.

Now, if the render window is much smaller, the render performance improves dramatically. This is as you would expect - half the resolution reduces the pixel count by a factor of 4, quarter resolution reduces it by a factor of 16, etc.

So, I would love an option where you can change the resolution of the AO, but the regular render pass images stays at the normal resolution. Ideally, the AO shading would then be applied with bilinear filtering so it doesn't look pixelated on top of the regular image. The performance would ROCKET and any drop in image quality would be acceptable for these low end devices.

Not only that, but being able to adjust the quality modes AND the AO resolution would allow for more flexibility. In some use cases, a combination of using a lower AO resolution with higher quality mode (less noise) may look aesthetically more pleasing.

Is there any way to integrate with fog?

Nice work on this, it's performing very well when testing so far.

One potential issue I'm encountering is that the AO effect is drawn over the top of any fog in the scene. I'm assuming because this effect is a screen space one it's not possible to actually draw it onto the material shaders before the fog. But I wondered if there was some depth information available and we could fade the opacity of the effect based on distance from the camera or something else that would give a reasonable approximation?

Is this kind of thing possible currently or any plans to implement?

.setDisplayMode Overlay

Would it be possible to make the pass produce the shadows only, rather than doing the renderPass together? Essentially this would be like using .setDisplayMode("AO") but instead of white/black debug output we have transparent/black output onto the previous pass... you could call it something like .setDisplayMode("Overlay")

So in a project we could then have something like this:

  • renderPass
  • Some other passes and effects
  • N8AO ❤
  • Some other passes and effects

By having the option to separate it this way, we would have more flexibility with the final image.

But there is more! By having separate passes, N8AO could use a different scene, camera or camera.layers for it's pass. This would allow us to use different geometry/objects for N8AO, or make some objects include/exclude N8AO (e.g. if a static object has prebaked shading, it might be desirable for that to not use N8AO).

This would make N8AO the ultimate SSAO solution for everybodies three.js projects!

AO from single side materials

Hello, my wall materials side is THREE.FrontSide, when i move camera to outside of room, AO calculate wrong, sample picture is attached, how we can ignore single side materials for AO,

best regards,

image

material.clone is not a function

very excited about this little package and it works perfectly — well almost!

  • using postprocessing
  • latest versions of postprocessing and three

works great when I'm applying it to a GLB model but in another scene with an OBJ, throws an error:

material.clone is not a function
    at OverrideMaterialManager.cloneMaterial (postprocessing.esm.js:5373:1)
    at OverrideMaterialManager.setMaterial (postprocessing.esm.js:5398:1)
    at new OverrideMaterialManager (postprocessing.esm.js:5315:1)
    at new RenderPass (postprocessing.esm.js:5525:1)

not the biggest deal, wanted to redo that scene either way, just wanted to let you know!

Option to accumulate over multiple frames

Hi, would it be possible to add an option to accumulate AO over multiple frames? Some models look quite bad with lower quality settings (especially light surfaces) & cranking up the quality isn't always an option for lower end devices. I would love to help on this but my knowledge on GLSL is lacking 😄

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.