three.js icon indicating copy to clipboard operation
three.js copied to clipboard

Possible improvements to Cascaded Shadow Maps

Open gkjohnson opened this issue 5 years ago • 11 comments

I thought I'd post a couple improvements for CSM I was thinking about in case anyone is interested and wants to pick them up.

  • Render all shadow cascades to a single shadow map target to save on shadow map branching and texture uniforms. Reference here and here

  • Add option to provide a scene bounding box or bounding sphere to the CSM object so the shadow render bounds can always encapsulate the scene.

  • Remove or rename the Frustum class in the /csm folder so it won't eventually conflict with Frustum in core.

gkjohnson avatar Mar 20 '20 17:03 gkjohnson

@mrdoob I think you've mentioned before that you might be interested in adding CSM to core -- how would you imagine adding it in? Technically CSM can be used with any shadowmap type (VSM, PCFS, PCFSS, etc) but can only be used with directional lights. If shadow map cascades are enabled should it be enabled on all directional lights? Or should it be a per light option?

gkjohnson avatar Mar 20 '20 17:03 gkjohnson

Or should it be a per light option?

Yep, the idea is to move the shadow type to the light.

mrdoob avatar Mar 21 '20 04:03 mrdoob

@mrdoob

Yep, the idea is to move the shadow type to the light.

Did you have any ideas on how to achieve this in the shader? It seems like you'd need to be able access an array using #defines in order to know type of shadow function is needed in the lights loop, which you can't do. We might be able to fake it, though, by inserting the unrolled loop index into define conditions:

#pragma unroll_loop_start
for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {

    directionalLight = directionalLights[ i ];
    getDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );

    #if DIR_LIGHT_SHADOW_TYPE_{{ UNROLLED_LOOP_INDEX }} == SHADOWMAP_TYPE_BASIC

        // ... perform basic shadow mapping ...

    #elif DIR_LIGHT_SHADOW_TYPE_{{ UNROLLED_LOOP_INDEX }} == SHADOWMAP_TYPE_PCF

        // ... perform PCF shadow mapping ...

    #elif DIR_LIGHT_SHADOW_TYPE_{{ UNROLLED_LOOP_INDEX }} == SHADOWMAP_TYPE_PCF_SOFT

        // ... perform PCF Soft shadow mapping ...

    #elif DIR_LIGHT_SHADOW_TYPE_{{ UNROLLED_LOOP_INDEX }} == SHADOWMAP_TYPE_VSM

        // ... perform VSM shadow mapping ...

    #endif

    RE_Direct( directLight, geometry, material, reflectedLight );

}
#pragma unroll_loop_end

gkjohnson avatar Apr 05 '20 05:04 gkjohnson

Oh... I see...

@Oletus any ideas?

mrdoob avatar Apr 12 '20 14:04 mrdoob

We already have this code inside the loops in lights_fragment_begin:

#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )

I think adding defines for every light index and relying on the loop being unrolled like @gkjohnson suggested is an okay way to do this.

Having a per-light shadow map type would make implementing filtering lights by object layer mask harder to implement though. This would be a very useful feature and has been previously suggested with the name "selective lighting", though the PR wasn't finished and didn't go anywhere. See #5180 #15223 #17396 . From the user perspective per-light shadow map type does make sense. And I'm all for CSMs in core! 👍

Oletus avatar Apr 13 '20 06:04 Oletus

Having a per-light shadow map type would make implementing filtering lights by object layer mask harder to implement though.

I'll have to study that PR more to understand how it's being implemented there but I would have figured that you'd filter the lights passed into material uniforms which would mean the shader code shouldn't be affected. I'm sure there are subtleties to it I'm missing, though.

From the user perspective per-light shadow map type does make sense. And I'm all for CSMs in core! 👍

I'm still mulling over ways to get CSM into core considering the current expectation is that every light have one only 1 shadowmap at most. Packing multiple shadowmaps into a single buffer could work but then we cut max shadowmap size down to 1 / 4 the hardware limit. That might be the most practical solution, though. Any ideas in that direction are welcome too!

gkjohnson avatar Apr 14 '20 05:04 gkjohnson

Hi, I was wondering if there is any progress on the CSM implementation. I am currently struggling with using CSM, since it needs to setup every affected material. This is especially difficult for loaded files.

I am not sure if it makes sense to integrate the CSM Shader into the default shader, but it would be great if there is an option to use a different default shader, when CSM is turned on. I could imagine by refractoring the CSM files the directional light can also be excluded from the CSM class. The approach of babylonjs is convenient and straightforward. Instead of normal shadow caster, one just uses the CSM and most things work similar. I could imagine threejs can profit from a simple solution, too, i.e. for games, maps with birds view on city - thats a bit my current aim.

dennemark avatar Aug 21 '20 10:08 dennemark

The approach of babylonjs is convenient and straightforward. Instead of normal shadow caster, one just uses the CSM and most things work similar.

Is there an example code of usage?

mrdoob avatar Aug 21 '20 14:08 mrdoob

I hope this is helpful https://doc.babylonjs.com/babylon101/shadows_csm in this playground there is a shadow (CSM) in one direction and shadow2 (normal shadowgenerator) in other direction https://www.babylonjs-playground.com/#IIZ9UU#40

dennemark avatar Aug 21 '20 14:08 dennemark

Is there any progress on this? It would be great to finally see CSM in the core!

LeviPesin avatar Jan 20 '22 15:01 LeviPesin

This would be great!

harrycollin avatar Dec 27 '23 22:12 harrycollin