fix: add checks to prevent NaN for BRDFs#1226
Conversation
WalkthroughHardcoded small epsilon constants in BRDF and hair specular shader calculations were replaced by unified named constants Changes
Sequence Diagram(s)sequenceDiagram
participant Shader
participant BRDF_Functions
Shader->>BRDF_Functions: Call BRDF or Hair Specular calculation
BRDF_Functions->>BRDF_Functions: Clamp denominators using max(value, EPSILON_DIVISION)
BRDF_Functions->>BRDF_Functions: Clamp dot products using max(value, EPSILON_DOT_CLAMP)
BRDF_Functions->>BRDF_Functions: Perform division or reciprocal safely
BRDF_Functions-->>Shader: Return stable BRDF/specular result
Possibly related issues
Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: .coderabbit.yaml 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
⏰ Context from checks skipped due to timeout of 90000ms (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
|
✅ A pre-release build is available for this PR: |
|
@coderabbitai don't we have an epsilon defined generally for hlsl that can be used? Please identify all uses and suggest consolidation if possible. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain@alandtse I'll search the codebase for existing epsilon definitions that could be used instead of the hardcoded 🏁 Script executed: Length of output: 53147 🏁 Script executed: Length of output: 19338 @alandtse Great question! After searching the codebase, I found several opportunities for epsilon consolidation: Current Epsilon Usage AnalysisNo centralized epsilon in Math.hlsli - it only contains PI, HALF_PI, and TAU constants. Current epsilon patterns:
Existing constants:
Consolidation RecommendationsOption 1: Add to Math.hlsli (Recommended) namespace Math
{
static const float EPSILON = 1e-6f; // Standard epsilon for division protection
static const float EPSILON_5 = 1e-5f; // Alternative epsilon (currently most common)
// ... existing constants
}Option 2: Local BRDF constant namespace BRDF
{
static const float EPSILON = 1e-6f; // For visibility function safeguards
// ... rest of BRDF functions
}Benefits of consolidation:
Current usage in BRDF.hlsli:
Would you like me to create a plan to implement this consolidation across the affected files? 🧠 Learnings used |
|
@jiayev any thoughts on just defining a centralized epsilon in like math and using that? @coderabbitai are there practical differences in the different variations of epsilon we're using? Please identify where they are, frequency, and whether it makes sense to standardize or allow its own precision. Please consider performance vs accuracy. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain@alandtse I'll analyze the practical differences between epsilon variations across the codebase, their usage patterns, and performance vs accuracy considerations. Based on the analysis, I'll provide recommendations on whether to standardize epsilon values or maintain precision-specific variants, considering both performance and accuracy implications. 🏁 Script executed: Length of output: 29411 @alandtse Based on my comprehensive analysis, here are the practical differences between epsilon variations and standardization recommendations: Epsilon Usage Patterns & FrequenciesCurrent Distribution:
Mathematical Context AnalysisThree distinct usage categories with different precision requirements: 1. Division Protection (Current: 1e-6f)// BRDF visibility functions - prevents /0 in reciprocal calculations
return rcp(max(Vis_SmithV * Vis_SmithL, 1e-6f));2. Dot Product Clamping (Current: 1e-5)// Ensures lighting terms don't go to zero
float NdotL = clamp(dot(N, L), 1e-5, 1);
float NdotV = saturate(abs(dot(N, V)) + 1e-5);3. Weight Normalization (Current: 1e-10)// Spherical harmonics - preserves contribution precision
return SphericalHarmonics::Scale(sum, rcp(wsum + 1e-10));Performance vs Accuracy TradeoffsPerformance Impact: ⚡ ZERO - Different epsilon values have no measurable performance cost on modern GPUs Accuracy Considerations:
Standardization RecommendationsOption A: Domain-Specific Constants (Recommended) namespace Math {
static const float EPSILON_DIVISION = 1e-6f; // For rcp() protection
static const float EPSILON_DOT_CLAMP = 1e-5f; // For NdotL/NdotV clamping
static const float EPSILON_WEIGHT_SUM = 1e-10f; // For weight normalization
}Option B: Conservative Single Value
Recommendation: Keep Domain-Specific PrecisionThe different epsilon values serve mathematically distinct purposes with different sensitivity requirements. Standardization within each domain (BRDF, PBR, Skylighting) makes sense, but one-size-fits-all would sacrifice either precision or introduce unnecessary conservatism. Immediate Action: Define the three constants in 🧠 Learnings used |
|
@coderabbitai shouldn't we use defines to match our current practice for constants in hlsl? Please draft a new issue with no assignee with these findings and suggestions for domain specific epsilons. Please ensure we've covered all the use cases of epsilon in the issue. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain@alandtse You're absolutely right about using The issue has been created with comprehensive analysis of all epsilon use cases and domain-specific recommendations using 🏁 Script executed: Length of output: 10692 🏁 Script executed: Length of output: 3969 Perfect! The GitHub issue has been successfully created at #1227 with comprehensive analysis of all epsilon use cases. Key Findings Confirmed:✅ Constant Definition Practices:
✅ Complete Epsilon Coverage:
✅ Issue Content:
The issue provides a complete roadmap for standardizing epsilon values while preserving the mathematical precision requirements for each domain. This will significantly improve code maintainability and consistency across the shader codebase. ✏️ Learnings added
🧠 Learnings used |
b9a4ee0 to
c050e67
Compare
|
@coderabbitai are the newly added defines good as domain-specific epsilons? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain@jiayev Perfect! The newly added defines are excellent domain-specific epsilons based on our comprehensive analysis. Let me verify the implementation: Excellent Implementation! ✅ The defines you've added are exactly the two highest-priority domain-specific epsilons from our analysis: EPSILON_DIVISION (1e-6f)
EPSILON_DOT_CLAMP (1e-5f)
Key Strengths:
This implementation provides the maximum benefit with minimal scope - covering the most frequently used epsilon patterns while maintaining mathematical precision requirements. The remaining specialized epsilons (1e-4, 1e-8, 1e-10) can be addressed in the follow-up issue #1227. Perfect foundation for epsilon standardization! 🎯 🏁 Script executed: Length of output: 2866 Absolutely excellent! ✅ The implementation is mathematically sound and perfectly executed: Perfect Implementation Confirmed:✅ Values & Usage:
✅ Mathematical Correctness:
✅ Code Quality:
Strategic Impact:This implementation provides the maximum ROI for epsilon standardization:
This is exactly what domain-specific epsilon standardization should look like! 🎯 The foundation is now perfectly set for extending this approach to the remaining specialized epsilons (distance thresholds, weight normalization, etc.) as outlined in issue #1227. 🧠 Learnings used |
… shaders (community-shaders#1227) Add domain-specific epsilon constants to Math.hlsli and replace hardcoded values throughout the codebase for consistency and maintainability. New constants added: - EPSILON_GLINTS (1e-8f): For glints ellipse ratio calculations - EPSILON_WEIGHT_SUM (1e-10f): For spherical harmonics weight normalization Replacements: - Skylighting.hlsli: 1e-10 → EPSILON_WEIGHT_SUM (rcp weight normalization) - radianceDisocc.cs.hlsl: 1e-10 → EPSILON_WEIGHT_SUM (rcp weight normalization) - Glints2023.hlsli: 1e-8 → EPSILON_GLINTS (ellipse ratio division) - TerrainVariation.hlsli: 1e-6 → EPSILON_DIVISION (weight sum normalization) - PBRMath.hlsli: 1e-6 → EPSILON_DIVISION (HairGaussian division guard) Notes on deviations from the issue description: - Common/BRDF.hlsli: 1e-6f occurrences were already replaced by EPSILON_DIVISION in PR community-shaders#1226. No changes needed. - Common/PBR.hlsli: Most 1e-5 occurrences replaced by EPSILON_DOT_CLAMP. One remaining occurrence (max(luma, 1e-5) in GetHairDiffuseAttenuationKajiyaKay) was intentionally left unchanged — it guards luminance-based division, not a dot product clamp, and its value doesn't match EPSILON_DIVISION (1e-6f). Left for follow-up. - DynamicCubemaps/DynamicCubemaps.hlsli: The hardcoded 0.00001 mentioned in the issue was not found in the current codebase. Left untouched. - Skylighting/Skylighting.hlsli: Two occurrences of 1e-10 (unitSH / 1e-10) were intentionally left unchanged — they construct a large fallback value for the interior case, not weight normalization guards. - ScreenSpaceGI/ScreenSpaceGI.hlsli and TerrainBlending/TerrainBlending.hlsli: The hardcoded 1e-4 values mentioned in the issue were not found in the current codebase. Left untouched. Closes community-shaders#1227
add checks to prevent NaN for the visibility component in BRDFs.
Summary by CodeRabbit