Skip to content

Conversation

@aevyrie
Copy link
Member

@aevyrie aevyrie commented Jan 5, 2026

Objective

  • Implement contact shadows to add fine shadow detail where shadow cascades cannot.

Solution

  • Extend our existing pbr implementation using our existing raymarching functions.

Showcase

Screen.Recording.2026-01-04.at.7.19.25.PM.mp4
Screen.Recording.2026-01-04.at.7.36.03.PM.mp4
image image image image image image

Copy link
Member

@tychedelia tychedelia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding or updating an existing example?

@aevyrie
Copy link
Member Author

aevyrie commented Jan 5, 2026

Sure, I was going to ask the crowd where it would make sense to add to an example.

@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-Rendering Drawing game state to the screen M-Release-Note Work that should be called out in the blog due to impact S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Jan 5, 2026
@alice-i-cecile alice-i-cecile added this to the 0.19 milestone Jan 5, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 5, 2026

It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note.

Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes.

@JMS55
Copy link
Contributor

JMS55 commented Jan 5, 2026

Closes #16164

@JMS55
Copy link
Contributor

JMS55 commented Jan 5, 2026

Does it make sense to do the raymarching directly in the material shader? It might give better perf to pull it out to its own pass.

Also MeshletMesh needs testing with this feature (and in the various forward/deferref/prepass modes).

@pcwalton
Copy link
Contributor

pcwalton commented Jan 5, 2026

I have an example for contact shadows that I made in my old branch: https://github.com/pcwalton/bevy/blob/contact-shadows/examples/3d/contact_shadows.rs

Feel free to steal it if you want, or not (it's rather old and would need to be updated). Up to you :)

@pcwalton
Copy link
Contributor

pcwalton commented Jan 5, 2026

@JMS55 I don't think the raymarching can really be done anywhere else, because in forward you need to know what's in shadow right then. You can't really subtract a light after the fact. (Well, maybe you technically could make it work, but that'd be a huge can of worms.)

use_secant: u32,
};

// Settings for contact shadows.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention the Rust module where the Rust-side equivalent of this can be found in the comment, so folks can easily cross-reference to find out what the settings mean.

let L = normalize(view_bindings::clusterable_objects.data[light_id].position_radius.xyz - in.world_position.xyz);

let noise = utils::interleaved_gradient_noise(in.frag_coord.xy, view_bindings::globals.frame_count);
let normal_bias = in.world_normal * 0.005;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you pull this 0.005 out into a const somewhere? Ideally it'd be adjustable in a uniform, but at least we should put it at the top of a file somewhere so that the tunable settings are in one place.

shadow *= smoothstep(0.5, 1.0, rm_result.hit_penetration_frac);
}
}
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there no way you can avoid the duplication by pulling this out into a separate function?


let rm_result = raymarch::depth_ray_march_march(&rm);
if rm_result.hit {
shadow *= smoothstep(0.5, 1.0, rm_result.hit_penetration_frac);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you actually need zero derivatives at 0.5 and 1 or would linstep be more appropriate? I'm not sure what motivates the use of smoothstep here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible M-Release-Note Work that should be called out in the blog due to impact S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants