Performant soft shadows THREE Js


I was wondering if there is a way in THREE Js to get very performant soft shadows for indoor scenes without the need to bake them to texture with a 3D render software.

As I see it SSAO works pretty good in THREE Js to achieve the result I’m after, but needs to calculate every frame. My scenes are static (no animation or repositioning of objects) but the SSAO seems to be dynamic. Not sure if this can be made static as well while the user navigates through the scene.

Another option would be baking the SSAO to texture once when the scene is loaded. But not sure how to achieve this and is dynamic UV unwrap possible to bake the data?

I want the soft shadows to run super smooth on mobile devices for indoor scenes with approximately 20000 tris. Some meshes are textured. So when using a baking technique the effect needs to multiply the existing texture.

If there are better ways in THREE to achieve the result I’m after, please share.

everything i tried is expensive and riddled with limitations, but for smaller models it could work. since your scenes are static i don’t see why you not want to bake them, that is the only truly performant choice and will look better than anything that’s calculated runtime. if you still want to try, here are a few methods you can experiment with, they’re react but the shaders are plain three universal:

baked shadows: Threejs journey - CodeSandbox
contact shadows: Shoe configurator - CodeSandbox
dynamic lightmaps: Adaptive lightmaps - CodeSandbox
percent closer soft shadows: Soft shadows - CodeSandbox
faking soft shadows w/ ssao dialed up to 11: Performance scaling - CodeSandbox
low resolution + pointlights: Minecraft - CodeSandbox


Hi drcmda,
Progressive LightMapping seems very interesting to me.
I’ll have a closer look into this.

Thanks for the info.

Maybe this could help :3

render.shadowMap.autoUpdate = false;
render.shadowMap.needsUpdate= true;

this take and shows the first frame of your shadows and then they become static


For real? I had no idea we can do that :heart_eyes:

I implemented it as follow. When all data is loaded I wait for 100 milliseconds to disable dynamic shadows

    loadingManager.onProgress = ( url, itemsLoaded, itemsTotal ) =>
      if(itemsLoaded == itemsTotal)
        setTimeout(()=>{renderer.shadowMap.autoUpdate = false;}, 100);

When a sunlight repositions, also causing to call a render pass, I use

renderer.shadowMap.needsUpdate = true;

Now I dive into AO techniques to fake soft shadows GI effects.

Thanks for the info

Dynamic lightmapping and soft shadows looks very promising to me. Great job!
Are these techniques usable without react? Are there examples or so?

they are just shaders. you find both in the official three examples, though you have to untangle them from the example code they’re wired into, they’re not readily usable ootb.

for softShadows i’ve made a small vanilla abstraction: GitHub - pmndrs/drei: 🌭 useful helpers for react-three-fiber you can use in your project as is, it mutates THREE.ShaderChunk.shadowmap_pars_fragment:

import { softShadows } from '@react-three/drei'


this won’t add react or any other dependency to your bundle. you could also just copy the code: drei/softShadows.tsx at 2088076e77d636cf001317475173fc44ae2071ac · pmndrs/drei · GitHub

the other one, the lightmap, that’s more complex and needs lots of things functioning around it, it is best abstracted into a component. but i find it pretty much unusable, it has countless of issues depending on your models, uvs and so on.


Would it be possible to use this dynamic path tracing technique:

And bake it to a texture in three js for all meshes after lets say 200 samples to make the bake static?

if you want soft shadow, use a light array with a diameter, obvious … the very attribute of the Sun making soft shadows…the very thing that proves the staged Apollo landing pics - shadows too tight.

If Three does NOT do it, I’d look at POVray code and implement in next release. There ought to be like 3 levels.

1 Like

Hi all,

I find this topic very interesting. I saw this example : three.js webgl - progressive lightmap accumulation

I wonder if it could be possible to modify this code, only for static scene, to save the result of this lighting and shadow and be able to reaload it after ?

It could be very interesting for static scene to calculate something like GI and save it (as lighting texture or something equivalent)…

Thanks to all !