Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Feature Request Better Environment BRDF approximation?

Discussion in 'Universal Render Pipeline' started by Arycama, Feb 2, 2021.

  1. Arycama

    Arycama

    Joined:
    May 25, 2014
    Posts:
    181
    Has anyone worked out a better Environment BRDF approximation for URP?

    Currently it's using the same formula from the legacy pipeline, which tends to wash out the scene, especially with rough surfaces which end up with a subtle sheen to them, due to the blurred reflection mip being applied too strongly.

    In a separate project I've switched to a precomputed term stored in a LUT, similar to HDRP and this helped greatly with environment reflections.

    There are several approximations from other engines, however none of these look correct in URP and seem to make the issue worse. I assume this is because they all use different BRDFs and roughness mappings. However I'm not sure how to map these to URP's BRDF.

    https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile

    https://knarkowicz.wordpress.com/2014/12/27/analytical-dfg-term-for-ibl/

    The above approximations are fairly complex formulas, Unity's approximation is very simple and I think the result is quite poor because of this:

    Code (CSharp):
    1.  
    2. brdfData.grazingTerm = saturate(smoothness + reflectivity);
    3.  
    4. // Computes the specular term for EnvironmentBRDF
    5. half3 EnvironmentBRDFSpecular(BRDFData brdfData, half fresnelTerm)
    6. {
    7.     float surfaceReduction = 1.0 / (brdfData.roughness2 + 1.0);
    8.     return surfaceReduction * lerp(brdfData.specular, brdfData.grazingTerm, fresnelTerm);
    9. }
    If anyone has worked out any improvements and wants to share them, that would be great!

    Otherwise, perhaps this is something the URP team can look into to make URP's rendering more in-line with other programs/engines.



    PS I'm not using shader graph at all, so integrating custom lighting formulas into my project isn't an issue.
     
  2. xgonzal2

    xgonzal2

    Joined:
    Jul 3, 2012
    Posts:
    62
    I've created my own Amplify shader template that does image based lighting differently from what URP does. Part of it uses a LUT too like HDRP but it has a few other things like a different way to compute the reflection vector used to sample the environment, different specular occlusion term, etc. I based most of the image based lighting work on the Frostbite engine paper linked below and a few other references. Both links below have sample code you can look at.

    Frostbite
    Filament

    All if not most of the functions I used to precompute the LUT are available in the core SRP package these days so maybe some of that work will make it to URP in the future.
     
    Arycama likes this.
  3. Arycama

    Arycama

    Joined:
    May 25, 2014
    Posts:
    181
    I've taken the same approach in another project with a custom SRP. (Eg a lookup table, also computed from some functions in the Core RP)

    However this is a mobile project and I was hoping to use an analytical approximation that fits the BRDF that URP uses, without requiring a lookup. However I'm not entirely sure how to derive it myself so I was wondering if anyone has done it already.
     
  4. BattleAngelAlita

    BattleAngelAlita

    Joined:
    Nov 20, 2016
    Posts:
    391
    BlackOps2 approximation works best, and it's pretty cheap.
     
    Arycama likes this.
  5. Arycama

    Arycama

    Joined:
    May 25, 2014
    Posts:
    181
    Thanks for that, I had a quick look at it a little while ago, but took another look and implemented it myself. Environment reflections aren't as washed out now.

    I'm not entirely sure if their glossiness mapping matches Unity's smoothness response, but the results seem to have helped either way.



    For anyone else interested, the code is below, taken from page 16 of: https://blog.selfshadow.com/publica...ourse/lazarov/s2013_pbs_black_ops_2_notes.pdf

    Code (CSharp):
    1. float3 EnvironmentBRDF(float g, float NoV, float3 rf0)
    2. {
    3.     float4 t = float4(1 / 0.96, 0.475, (0.0275 - 0.25 * 0.04) / 0.96, 0.25);
    4.     t *= float4(g, g, g, g);
    5.     t += float4(0, 0, (0.015 - 0.75 * 0.04) / 0.96, 0.75);
    6.     float a0 = t.x * min(t.y, exp2(-9.28 * NoV)) + t.z;
    7.     float a1 = t.w;
    8.     return saturate(lerp(a0, a1, rf0));
    9. }
    You'll have to use a custom shader and replace the "EnvironmentBRDFSpecular" call in the EnvironmentBRDF function.

    Would be cool if the URP team can derive a similar approximation for the current gloss remapping.
    The URP environment BRDF is pretty outdated (Was introduced in Unity 5), and makes URP less accurate with tools like Substance, creating workflow issues. (Eg back and forth tweaking of smoothness maps to get things looking shiny but not washed out)
     
    Last edited: Feb 18, 2021
    Neto_Kokku likes this.