Need Help with Godot 4.4 Shadow Shaders for VR Therapy Applications

Need Help with Godot 4.4 Shadow Shaders for VR Therapy Applications

Hello there!

Firstly, i’m a frenchy. In advance, please accept my apologies for bad translating

I’m working on a therapeutic VR project for a friend whose developing an healthcare platform (you can check out their work at https://socialdream.fr), and I’m running into some performance issues with shadow rendering in Godot 4.4.

Background:
The application is designed for anxiety therapy using immersive environments. We need realistic shadows for presence and immersion, but the current implementation is causing frame drops on Quest 2 devices, which is obviously problematic for VR comfort.

Current Setup:

  • Godot 4.4.0 stable
  • Using Forward+ renderer with clustered lighting
  • Custom shader material for ground surfaces
  • Directional light with shadow mapping enabled
  • Target: 90fps on Quest 2 (currently getting ~60fps with heavy scenes)

Technical Questions:

  1. Shadow Map Resolution: I’m currently using 2048x2048 shadow maps. Would reducing to 1024x1024 significantly impact visual quality in VR? The viewing distance is typically 2-10 meters from objects.

  2. Shader Optimization: Has anyone experimented with simplified shadow calculations in fragment shaders for VR? I’m thinking about implementing a basic PCF (Percentage Closer Filtering) instead of the default shadow filtering.

  3. LOD for Shadows: Is there a way to disable shadow casting for objects beyond a certain distance threshold without affecting the shadow receiving? I couldn’t find a clean solution in the documentation.

Code Snippet (Current Shadow Calculation):

float shadow_calculation(vec4 frag_pos_light_space) {
    vec3 proj_coords = frag_pos_light_space.xyz / frag_pos_light_space.w;
    proj_coords = proj_coords * 0.5 + 0.5;
    
    float closest_depth = texture(shadow_map, proj_coords.xy).r;
    float current_depth = proj_coords.z;
    
    float bias = 0.005;
    float shadow = current_depth - bias > closest_depth ? 1.0 : 0.0;
    
    return shadow;
}

The therapeutic context requires stable performance since any stuttering can break immersion and potentially trigger discomfort in patients. I’ve tried adjusting the shadow bias and implementing cascade shadow maps, but I’m wondering if there are VR-specific optimizations I’m missing.

More Context:
The scenes typically include:

  • 1-2 directional lights (sun/moon simulation)
  • 3-5 spot lights for ambient lighting
  • Dynamic objects that need to cast shadows
  • Naturalistic environments (forests, beaches, etc.)

Has anyone successfully optimized shadow rendering for therapeutic VR applications? Any suggestions for balancing visual fidelity with performance would be greatly apreciated!

Thanks in advance for any insights!

NB: Forgot to mention we’re also considering switching to mobile renderer, but I’m concerned about loosing some of the visual quality that’s really important for the therapeutic effectiveness.

The Quest 2 is getting long in the tooth – it’s 5 years old at this point. Unfortunately, rendering 90 FPS in a scene with shadow maps is asking a lot from it. Remember that VR needs to render the scene twice (one from each eye’s viewpoint), so the base cost for anything will always be much greater than in non-VR scenarios.

Even if you reduced shadow resolution to the lowest possible value (256x256) and disabled shadow filtering in the project settings, you’ll likely run into CPU overhead issues that simply can’t be resolved.

To achieve 90 FPS on a highly resource-constrained device, your best bet is to avoid using any kind of real-time lighting and bake lightmaps instead. Set the global illumination mode on all your lights to Static and hide your light nodes after baking, so that their real-time part is fully disabled. This will cause dynamic objects to not receive direct light though, as only indirect lighting is baked in light probes. Fixing this would require implementing a new GI mode as described in this proposal.

Using this approach also means that dynamic objects won’t be able to cast shadows, so consider using blob shadows by using PlaneMesh with a blob shadow texture (and place it so it follows the dynamic object with a raycast). Using the Decal node also works, but it’s much slower than a raycasted plane approach on this kind of hardware.

NB: Forgot to mention we’re also considering switching to mobile renderer, but I’m concerned about loosing some of the visual quality that’s really important for the therapeutic effectiveness.

You’re likely using Mobile on the Quest already (check the Project Settings’ .mobile override for the rendering method project setting). If you were to use Forward+ there, you would probably get much less than 60 FPS, given how greater its base cost is.