Three.js: Less shadowmap rendering

Created on 8 Jul 2015  路  17Comments  路  Source: mrdoob/three.js

In different situations shadowmaps can be used for static objects that do not move often :

  • a procedural city (big shadow maps),
  • objects that move only when dragged....

In those situations we need shadowmap rendering, but not each frame. For example, once a part of a procedural city has been created, the buildings don't move but the shadow rendering still uses a lot of computational power.

Here is the suggestion of a shadowMapNeedsUpdate = true parameter to the WebGLRenderer the way verticesNeedUpdate work.

Its value is checked in the ShadowMapPlugin and set to false just after :

if( _renderer.shadowMapEnabled === false || _renderer.shadowMapNeedsUpdate === false ) return;

_renderer.shadowMapNeedsUpdate = false;

This way the shadowmap is rendered once at the first render call, and if the scene requires the realtime shadowmap it has to be precised in the render loop. Otherwise it has to be precised in the functions that move/create/delete objects.

Suggestion

Most helpful comment

Thanks for the suggestion! It was pretty easy to implement 馃槉

You can now do this:

renderer.shadowMap.autoUpdate = false;
renderer.shadowMap.needsUpdate = true; // when your scene changes

All 17 comments

In different situations shadowmaps can be used for static objects that do not move often :

a procedural city (big shadow maps),
objects that move only when dragged....

To use dynamic shadows for static objects is a VERY bad idea.
In those cases you need static lightMaps
Example: http://necromanthus.com/Test/html5/SMC.html

cheers

Thanks.

I use that way as much as i can too, also for moving objects when possible (car shadow in helloracer..).

But sometimes you cannot pre-draw even pre-bake shadows. In a procedural city you can't draw the casted shadow of one building on another, because you don't know what position they will have.
Other situations : a skinnedmesh that stops moving, an interactive scene where static objects can be dragged and need shadow casting....

I just hope it can help free computational power

But sometimes you cannot pre-draw even pre-bake shadows.

I think you're looking for something like mesh.shadowMapNeedsUpdate = true (or false);
In other words, that particular shadowMap needs to be computed only once (after mesh creation or movement).
And yes, that would be a very useful feature.

cheers

To use dynamic shadows for static objects is a VERY bad idea.

There are scenarios where you might want a static shadow on dynamic objects. In that case lighmaps are insufficient.

I might have overestimated the gain : i just applied the idea to draggable cubes (a simple scene that gives headaches to my 2012/intel5 laptop ) but see no difference in CPU usage (integrated GPU intel HD Graphics).

mesh.shadowMapNeedsUpdate

@RemusMar Wouldn't that be equivalent to renderer.shadowMapNeedsUpdate since there is one shadowmap per light source ?

Wouldn't that be equivalent to renderer.shadowMapNeedsUpdate since there is one shadowmap per light source ?

You need to disable the shadows computing for all the static objects.
So to spare processing power and to keep the best results (shadows) for the other dynamic objects,
you need something enabled/disabled "per mesh" (per object).

To me draggable cubes is a good example of what i need : i don't render the shadowmap unless a cube is dragged. It yet prevents the shadowmap rendering in a big ratio of time, depending the way the user interacts.

Computing shadows _per mesh_ would ask the webglrendertarget to remember each mesh'projection on the shadowmap and update the new projection and the old one am i right ? Hey wouldn't that be easy to code ? ^^ However drawing only the modified fragments is something beyond my skills.

Also as i wrote i see no difference at all on my GPU-CPU, in my updated draggable cubes example and without dragging anything. I'm not really a pro of realtime rendering yet but given this point, would the _per mesh_ solution be better ?

I test it elsewhere tonight and report if i see a real improvement.

You need "shadowMapNeedsUpdate = true (or false)" per mesh to make the difference between static and dynamic objects.
On the other hand keep in mind: the shadows are STILL drawn for ALL the meshes!
So you will see a performances boost only in case of hundreds/thousands of meshes.
Otherwise the boost is close to zero.

cheers

@RemusMar I did not precise the different situations i encounter are _only_ scenes with static meshes, like draggablecubes (i quote this example again as it matches those different situations). I mean, when nothing move both ideas behave the same, so completely preventing the shadowmap rendering is yet a first step.

Anyway, if ever the result is really ok for static cases, i see no decrease in CPU-GPU usage in the examples i'm testing.

What is STLL ? no google result at all.

i see no decrease in CPU-GPU usage in the examples i'm testing.

You need to perform a test with hundreds of objects and using the "per mesh" approach.

What is STLL ?

You STILL cast/receive shadows for all the models.
So that shadowMapNeedsUpdate is almost irrelevant for a few models.
You won't gain anything.

I have to go now.
cheers

Thanks for the suggestion! It was pretty easy to implement 馃槉

You can now do this:

renderer.shadowMap.autoUpdate = false;
renderer.shadowMap.needsUpdate = true; // when your scene changes

Hey so happy I found this. This feature is totally undocumented! https://threejs.org/docs/#api/renderers/WebGLRenderer I was already doing something like this but it wasn't as performant as this and this has massively increased performance in my app. Will open PR to get it into the docs.

@rohan-deshpande Can you please explain your use case? Are you re-rendering even if your scene hasn't changed? How is renderer.shadowMap.autoUpdate = false "massively" improving performance in your use case?

@WestLangley It basically allows computing the shadowmap just once.

I understand that. But if the scene is static, I was wondering if the user was using an animation loop unnecessarily.

Basically what @mrdoob said. It's a very similar situation to what @Astrak was describing

image

The building is static, but the camera can move, rotate etc., the game loop is constantly rendering and waiting for jobs from the animation queue. In this use case, I only need the shadows to be rendered once. After that, they never need to be updated. Except in the case of editing lights (which is what I'm doing here).

Was this page helpful?
0 / 5 - 0 ratings