Skip to content

Conversation

JMS55
Copy link
Contributor

@JMS55 JMS55 commented Oct 3, 2025

Objective

  • Add initial support for indirect specular lighting (reflections) to Solari's realtime renderer

Solution

  • A new pass is added called specular_gi
    • For rough materials, we reuse the path from [diffuse] ReSTIR GI, and just shade using the specular BRDF
    • For smooth materials, we trace a new path with up to 3 bounces, terminating in the world cache once we've hit a rough enough surface
  • DLSS-RR guide buffers now use correct diffuse and specular albedos

Future

  • Specular motion vectors for DLSS-RR guiding are not yet implemented. I think I want to leave this for a future PR. For now they're hardcoded to zero.
  • Reflections can reveal the world cache
  • General quality is not great, there's probably some heuristics we can tune to reduce the noise, but at least it's a baseline to start with.

Showcase

Before
image

After
image

@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-Rendering Drawing game state to the screen S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 4, 2025
@JMS55
Copy link
Contributor Author

JMS55 commented Oct 5, 2025

Split the uncontroversial stuff off into a separate PR since this one needs some work #21391

@JMS55 JMS55 changed the title Solari: Specular material support Solari specular material support Oct 5, 2025
@JMS55 JMS55 marked this pull request as ready for review October 10, 2025 16:24
@JMS55 JMS55 requested a review from atlv24 October 10, 2025 16:25
@JMS55 JMS55 changed the title Solari specular material support Solari indirect specular support Oct 10, 2025
@JMS55 JMS55 requested a review from tychedelia October 10, 2025 16:29
let depth = textureLoad(depth_buffer, global_id.xy, 0);
if depth == 0.0 {
textureStore(diffuse_albedo, pixel_id, vec4(0.0));
textureStore(diffuse_albedo, pixel_id, vec4(0.5));
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be specular_albedo?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whoops yes, thanks for catching!

let B = TBN[1];
let N = TBN[2];
let wo = -wi;
let wo_tangent = vec3(dot(wo, T), dot(wo, B), dot(wo, N));
Copy link
Contributor

Choose a reason for hiding this comment

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

isnt this just a matmul

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, but the rest of bevy does it this way so we keep doing it this way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep

Comment on lines +58 to +59
var bias = dot(M1 * X.xy, Y.xy) / dot(M2 * X.xyw, Y.xyw);
let scale = dot(M3 * X.xy, Y.xy) / dot(M4 * X.xzw, Y.xyw);
Copy link
Contributor

Choose a reason for hiding this comment

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

are the swizzles right here? .xyw .xyw on the first line and .xzw .xyz on the second

Copy link
Contributor

Choose a reason for hiding this comment

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

From the DLSS RR integration guide,

float3 EnvBRDFApprox2(float3 SpecularColor, float alpha, float NoV) 
{ 
    NoV = abs(NoV); 
    // [Ray Tracing Gems, Chapter 32] 
    float4 X; 
    X.x = 1.f; 
    X.y = NoV; 
    X.z = NoV * NoV; 
    X.w = NoV * X.z; 
    float4 Y; 
    Y.x = 1.f; 
    Y.y = alpha; 
    Y.z = alpha * alpha; 
    Y.w = alpha * Y.z; 
    float2x2 M1 = float2x2(0.99044f, -1.28514f, 1.29678f, -0.755907f); 
    float3x3 M2 = float3x3(1.f, 2.92338f, 59.4188f, 20.3225f, -27.0302f, 
222.592f, 121.563f, 626.13f, 316.627f); 
    float2x2 M3 = float2x2(0.0365463f, 3.32707, 9.0632f, -9.04756); 
    float3x3 M4 = float3x3(1.f, 3.59685f, -1.36772f, 9.04401f, -16.3174f, 
9.22949f, 5.56589f, 19.7886f, -20.2123f); 
    float bias = dot(mul(M1, X.xy), Y.xy) * rcp(dot(mul(M2, X.xyw), Y.xyw)); 
    float scale = dot(mul(M3, X.xy), Y.xy) * rcp(dot(mul(M4, X.xzw), Y.xyw)); 
    // This is a hack for specular reflectance of 0 
    bias *= saturate(SpecularColor.g * 50); 
    return mad(SpecularColor, max(0, scale), max(0, bias)); 
} 
 
outSpecularAlbedo = EnvBRDFApprox2( GBuffer.SpecularAlbedo, GBuffer.fRoughness 
* GBuffer.fRoughness, NdotV ); 

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep it's correct

@JMS55 JMS55 added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Oct 11, 2025
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 S-Needs-Review Needs reviewer attention (from anyone!) to move forward S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants