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.

Question Is there a way to override current reflection probe for a renderer/material/globally?

Discussion in 'General Graphics' started by jperryoddgames, Jun 30, 2021.

  1. jperryoddgames

    jperryoddgames

    Joined:
    Sep 18, 2017
    Posts:
    45
    Question:
    I'm wondering if there's a way to control the reflection probe used by Unity's
    UNITY_BRDF_PBS
    shader function.
    To clarify, I'm aware that the Renderer class has a
    probeAnchor
    property that can be set to a transform, but this will not work for our case.

    The problem/use case:
    • We allow the player to customize paint finishes in the game.
    • We display UI graphics for several paint presets. These UI graphics use a normal map to display the glossiness of the paint, so the player can easily see how reflective the paint is.
    • Despite these graphics belonging to a screen-space canvas, they're still affected by the current probe for the game's main camera. Moving the camera in-game will cause the UI graphics to change reflections and sometimes receive incorrect lighting when the selected probe changes.
    Additional notes:
    I'd imagine the easiest way to achieve this would be to set an override probe during a render callback like OnPreRender or OnRenderObject, etc. Does unity already offer something like this? Otherwise, is there any way to directly pass a cubemap or something in shader-land?
     
  2. StaggartCreations

    StaggartCreations

    Joined:
    Feb 18, 2015
    Posts:
    1,938
    I'm not entirely sure, but it may be possible through a MaterialPropertyBlock by setting the unity_SpecCube0 texture property, normally the closest dominant probe cubemap is assigned to this. But I don't think this would work in deferred rendering.

    For overriding the skybox/global reflection you could set RenderSettings.defaultReflectionMode to "Custom" and assign a cubemap to RenderSettings.customReflection in something like OnPreRender, then reset it in OnPostRender.
     
  3. jperryoddgames

    jperryoddgames

    Joined:
    Sep 18, 2017
    Posts:
    45
    Thanks for the reply. I tried out your suggestions this morning but it doesn't look like they'll work for our use case.

    First, some extra info about the project:
    • We're using RawImage for the UI graphics (I've edited the original post to mention this)
    • The project is set up to use forward rendering

    Setting unity_SpecCube0:
    Because we're using RawImage, I couldn't try using a MaterialPropertyBlock, however I did try setting the
    unity_SpecCube0
    property directly on the image's material. Unfortunately I can see in the Frame Debugger window that it's being reset to the camera's current reflection probe at some point.
    I tried setting the texture in LateUpdate. I also tried to use OnWillRenderObject but it turns out the method is not called on UI elements, as stated in the docs page.

    RenderSettings class:
    I also attempted to use the
    RenderSettings
    class as suggested. I simply tested on regular GameObjects since the OnWillRenderObject method doesn't work for UI elements as mentioned above.

    I set the code up to set the
    RenderSettings.customReflection
    property only when I was holding down the Shift key so I could easily see the difference.
    It looks like the
    customReflection
    property doesn't actually override reflection probes, rather it's only applied to objects that are not already affected by a probe. This makes sense since it pairs with the
    defaultReflectionMode
    property which can be set to Skybox or Custom.
    To clarify, I found that background objects that weren't inside the probe's area were changing, but foreground objects were not. Disabling the reflection probe in the scene changed the behaviour such that all objects were now being affected by the customReflection property.

    If anyone has any other suggestions I'd love to hear them. Thanks again @StaggartCreations for the reply
     
  4. RyanKeable

    RyanKeable

    Joined:
    Oct 16, 2013
    Posts:
    62
    why don't you just write a custom shader with your own cubemap sample and pass through a specific CubeMap to be rendered?

    How much of your paint's qualities are determined by Unity's Standard Shader?
     
  5. StaggartCreations

    StaggartCreations

    Joined:
    Feb 18, 2015
    Posts:
    1,938
    Worth a shot! I assumed a MaterialPropertyBlock would work since the cubemap is set up on a per-object basis, but this probably happens deep in the render loop.

    If you want a specific cubemap to apply to a specific object, you could create a reflection probe that only encapsulates said object, and give it a priority value of something like 999. This way it should be passed on as unity_SpecCube0 for that specific renderer. This way you could piggyback on existing functionality.

    Didn't even know UI could pick up on reflection probes. But if all fails, a custom shader like @RyanKeable mentions will offer full control. The nasty thing is though that this requires to replicate all PBR shading functionality, just to have it use a custom BRDF function.
     
  6. RyanKeable

    RyanKeable

    Joined:
    Oct 16, 2013
    Posts:
    62
    Yes it can be a pain to write out a full Unity PBR shader and intercept one lighting pass inside of it (I've done it a few times now >.< haha)

    There should be better ways to point specific probes to specific objects
     
  7. jperryoddgames

    jperryoddgames

    Joined:
    Sep 18, 2017
    Posts:
    45
    Pretty sure we would have to write a custom shader to get this working, I've had no luck with other methods.
    It would be nice though if Unity provided a better way to directly override reflection probes for any given draw-call.
    Thanks for the input guys