three.js
three.js copied to clipboard
WebGLRenderer: Add .renderShadowMap().
This can be used to manually update shadow maps, which can be convenient in case the user wants to set up the scene differently for shadow map rendering. This can be useful for example when showing a cutout view.
Fixed #23461
This contribution is funded by Higharc.
The example needs to be added to files.json
. Otherwise it does not appear in the side menu.
And please add the respective E2E screenshot via:
npm run make-screenshot webgl_shadowmap_manual_update
The PR checks should then be successful.
@Mugen87 Added the file to the examples listing and added the screenshot, PR checks passed now!
I had to diff the example in this PR to find the 3 lines which differ from the original example upon which it is based.
I think this will be confusing to users.
This can be useful for example when showing a cutout view.
Why not create an example of that, instead?
I did give a try to this feature. It works like a charm. I was able to bake a static shadow on the whole scene in 4k and then render a small dynamic shadow in 1k that calls renderShadowMap only on a few meshes:
(In this video the giant shadow camera helper is the shadow camera of the scene, and the small shadow camera helper is the dynamic that only renders the characters through renderShadowMap
)
https://user-images.githubusercontent.com/15867665/159166252-c066c3dd-53a5-42e6-82ba-2e05135f3e5d.mov
Also, to make full usage of it I would recommend a 4th parameter forceUpdate
Like so:
this.renderShadowMap = function ( lightsWithShadows, scene, camera, forceUpdate )
That will allow being able to manually force to render an object even though autoUpdate
and needsUpdate
are set to false. We need to disable both these values if with use renderShadowMap otherwise it would clash with the natural state of how shadowmap.render
works and call both methods per render.
In that case, the render method of WebGLShadowMap
would have a third condition in order to prevent the render of the shadow:
if ( shadow.autoUpdate === false && shadow.needsUpdate === false && forceUpdate === undefined ) continue;
Why not create an example of that, instead?
Agreed. This needs a simple example.
With that new feature it would be very interesting to also introduce Array usage on top of Mesh.Group for the second parameter of WebGLShadowMap.render
.
It will allow to prevent a complex filtering of the meshes that we want to apply shadow to. That way, instead of doing scene.traverse()
, we can just renderShadowMap(lights, [meshA, meshB], camera, true)
It could look like this:
function WebGLShadowMap( _renderer, _objects, _capabilities ) {
this.render = function ( lights, scene, camera, forceUpdate ) {
// bypass if we want to manually update the shadowmap for specific elements
if ( scope.autoUpdate === false && scope.needsUpdate === false && forceUpdate === undefined ) return;
// allow arrays
const elements = Array.isArray( scene ) ? scene : [ scene ];
for ( let vp = 0; vp < viewportCount; vp ++ ) {
//viewport
_frustum = shadow.getFrustum();
for ( let j = 0; j < elements.length; j ++ ) {
const element = elements[ j ];
renderObject( element, camera, shadow.camera, light, this.type );
}
}
//....
@mrdoob @Mugen87 Hey! Sorry that it took such a long time for me to get around to updating the example, but it should be much better now! The manually updated shadow map now includes an object that's not visible in normal rendering. DeepScan is complaining about an unrelated issue since this code was forked off of dev a while back - do I need to rebase this branch or merge dev into here?
Rebased this to pass the tests and made sure that the patch still works, @mrdoob time to merge this? 😁 I'd be really happy if we got this change in, hope you're not too busy! 🙏
@mrdoob Wanted to check the status of this PR once again, it's been in the approved state for a long time! It seems like the code is still valid for the latest versions of three.js, but I could rebase the branch again if needed. We're still using this feature at Higharc, it would be great if we could get some of our customizations upstream.
Sorry for the wait!
Would be great if you could rebase the PR yes.
Also, would it be possible to make it so WebGLRenderer
's render()
also uses renderShadowMap()
?