Skip to content

Commit

Permalink
Documentation/staging
Browse files Browse the repository at this point in the history
Regular docs sync to main.
  • Loading branch information
RobJessop authored and Evergreen committed Sep 30, 2023
1 parent bd51db4 commit 4937651
Show file tree
Hide file tree
Showing 3 changed files with 267 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
* [Post-processing](integration-with-post-processing.md)
* [How to configure](integration-with-post-processing.md#post-proc-how-to)
* [HDR Output](post-processing/hdr-output.md)
* [Custom Passes with HDR Output](post-processing/hdr-custom-pass.md)
* [Volumes](Volumes.md)
* [Volume Profile](Volume-Profile.md)
* [Volume Overrides](VolumeOverrides.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
# Scriptable Render Passes with HDR Output

High Dynamic Range (HDR) Output changes the inputs to your custom pass when it applies tone mapping and color space conversions. These changes can cause your custom pass to produce incorrect results. This means that when you use HDR Output and a custom pass that happens in or after the AfterRenderingPostProcessing injection point, you need to account for the changes HDR Output makes. To make a custom pass work with the changes HDR Output makes, you must manually perform [tone mapping and convert color space in a script](#tone-map-convert-color-space).

When you execute a custom pass in or before the BeforeRenderingPostProcessing injection point, you don't need to do anything else to make it work with HDR Output. This is because Unity executes your custom pass before it renders the HDR Output.

**Note**: You can avoid this problem when you use a camera stack to render camera output before Unity performs tone mapping. Unity then applies HDR Output processing to the last camera in the stack. To learn how to set up a camera stack, refer to [Camera stacking](../camera-stacking.md).

## <a name="tone-map-convert-color-space"></a>Tone map and convert color space in a script

To make a custom pass work with the changes HDR Output makes to color space and dynamic range, use the `SetupHDROutput` function to apply tone mapping and color space conversion to the material the custom pass alters:

1. Open the C# script which contains the Scriptable Render Pass you wish to use with HDR Output.
2. Add a method with the name `SetupHDROutput` to the Render Pass class.

The following script gives an example of how to use the `SetupHDROutput` function:

```c#
class CustomFullScreenRenderPass : ScriptableRenderPass
{
// Leave your existing Render Pass code here
static void SetupHDROutput(ref CameraData cameraData, Material material)
{
// This is where most HDR related code is added
}
}
```

3. Add an `if` statement to check whether HDR Output is active and if the camera has post-processing enabled. If either condition is not met, disable the HDR Output shader keywords to reduce resource usage.

```c#
static void SetupHDROutput(ref CameraData cameraData, Material material)
{
// If post processing is enabled, color grading has already applied tone mapping
// As a result the input here will be in the display colorspace (Rec2020, P3, etc) and in nits
if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
{

}
else
{
// If HDR output is disabled, disable HDR output-related keywords
// If post processing is disabled, the final pass will do the color conversion so there is
// no need to account for HDR Output
material.DisableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
}
}
```

4. Create variables to retrieve and store the luminance information from the display as shown below.

```c#
if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
{
// Get luminance information from the display, these define the dynamic range of the display.
float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;
}
else
{
// If HDR output is disabled, disable HDR output-related keywords
// If post processing is disabled, the final pass will do the color conversion so there is
// no need to account for HDR Output
material.DisableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
}
```

5. Retrieve the tonemapping component from the Volume Manager.

```c#
if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
{
var tonemapping = VolumeManager.instance.stack.GetComponent<Tonemapping>();

// Get luminance information from the display, these define the dynamic range of the display.
float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;
}
```

6. Add another `if` statement to check whether a tonemapping component is present. If a tonemapping component is found, this can override the luminance data from the display.

```c#
if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
{
var tonemapping = VolumeManager.instance.stack.GetComponent<Tonemapping>();

// Get luminance information from the display, these define the dynamic range of the display.
float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;

if (tonemapping != null)
{
// Tone mapping post process can override the luminance retrieved from the display
if (!tonemapping.detectPaperWhite.value)
{
paperWhite = tonemapping.paperWhite.value;
}
if (!tonemapping.detectBrightnessLimits.value)
{
minNits = tonemapping.minNits.value;
maxNits = tonemapping.maxNits.value;
}
}
}
```

7. Set the luminance properties of the material with the luminance data from the display and tonemapping.

```c#
if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
{
var tonemapping = VolumeManager.instance.stack.GetComponent<Tonemapping>();

// Get luminance information from the display, these define the dynamic range of the display.
float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;

if (tonemapping != null)
{
// Tone mapping post process can override the luminance retrieved from the display
if (!tonemapping.detectPaperWhite.value)
{
paperWhite = tonemapping.paperWhite.value;
}
if (!tonemapping.detectBrightnessLimits.value)
{
minNits = tonemapping.minNits.value;
maxNits = tonemapping.maxNits.value;
}
}

// Pass luminance data to the material, use these to interpret the range of values the
// input will be in.
material.SetFloat("_MinNits", minNits);
material.SetFloat("_MaxNits", maxNits);
material.SetFloat("_PaperWhite", paperWhite);
}
```

8. Retrieve the color gamut of the current color space and pass it to the material.

```c#
// Pass luminance data to the material, use these to interpret the range of values the
// input will be in.
material.SetFloat("_MinNits", minNits);
material.SetFloat("_MaxNits", maxNits);
material.SetFloat("_PaperWhite", paperWhite);

// Pass the color gamut data to the material (colorspace and transfer function).
HDROutputUtils.GetColorSpaceForGamut(cameraData.hdrDisplayColorGamut, out int colorspaceValue);
material.SetInteger("_HDRColorspace", colorspaceValue);
```

9. Enable the HDR Output shader keywords.

```c#
// Pass the color gamut data to the material (colorspace and transfer function).
HDROutputUtils.GetColorSpaceForGamut(cameraData.hdrDisplayColorGamut, out int colorspaceValue);
material.SetInteger("_HDRColorspace", colorspaceValue);

// Enable HDR shader keywords
material.EnableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
```

10. Call the SetupHDROutput method in your Execute() function to ensure that HDR Output is accounted for whenever this Scriptable Render Pass is in use.

## Complete Script Example

The following is the complete code from the example:

```c#
class CustomFullScreenRenderPass : ScriptableRenderPass
{
// Leave your existing Render Pass code here
static void SetupHDROutput(ref CameraData cameraData, Material material)
{
// If post processing is enabled, color grading has already applied tone mapping
// As a result the input here will be in the display colorspace (Rec2020, P3, etc) and in nits
if (cameraData.isHDROutputActive && cameraData.postProcessEnabled)
{
var tonemapping = VolumeManager.instance.stack.GetComponent<Tonemapping>();

// Get luminance information from the display, these define the dynamic range of the display.
float minNits = cameraData.hdrDisplayInformation.minToneMapLuminance;
float maxNits = cameraData.hdrDisplayInformation.maxToneMapLuminance;
float paperWhite = cameraData.hdrDisplayInformation.paperWhiteNits;

if (tonemapping != null)
{
// Tone mapping post process can override the luminance retrieved from the display
if (!tonemapping.detectPaperWhite.value)
{
paperWhite = tonemapping.paperWhite.value;
}
if (!tonemapping.detectBrightnessLimits.value)
{
minNits = tonemapping.minNits.value;
maxNits = tonemapping.maxNits.value;
}
}

// Pass luminance data to the material, use these to interpret the range of values the
// input will be in.
material.SetFloat("_MinNits", minNits);
material.SetFloat("_MaxNits", maxNits);
material.SetFloat("_PaperWhite", paperWhite);

// Pass the color gamut data to the material (colorspace and transfer function).
HDROutputUtils.GetColorSpaceForGamut(cameraData.hdrDisplayColorGamut, out int colorspaceValue);
material.SetInteger("_HDRColorspace", colorspaceValue);

// Enable HDR shader keywords
material.EnableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
}
else
{
// If HDR output is disabled, disable HDR output-related keywords
// If post processing is disabled, the final pass will do the color conversion so there is
// no need to account for HDR Output
material.DisableKeyword(HDROutputUtils.ShaderKeywords.HDR_INPUT);
}
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,36 @@ To activate HDR output, follow these steps.
If you switch to a URP Asset that does not have HDR enabled, URP disables HDR Output until you change to a URP Asset with HDR enabled.

> **Note**: If HDR Output is active, the grading mode falls back to HDR, even if there is a different Color Grading Mode active in the URP Asset.
> **Note**: When HDR Output is active the color grading mode is HDR by default, even if a different Color Grading Mode is active in the URP Asset.
## Understand HDR Output implementation

Unity's HDR Output is split into the following steps which always occur in this order:

1. [Tone mapping](#tone-mapping)
2. [Transfer Function](#transfer-function)

### Tone mapping

Tone mapping is the first step in the HDR Output process. In this step, Unity balances the exposure and hue of the scene according to the target display's dynamic range. Dynamic range is determined by the following properties:

* **Minimum brightness**
* **Maximum brightness**
* **Paper white brightness**

For more information on these properties, see [Important tone mapping values](#important-tone-mapping-values).

At the same time, Unity performs the color space conversion. Unity converts the colors from the default Rec. 709 color space to the target display's color space. This maps the colors in the scene to the wider gamut of colors of the target display and ensures Unity utilizes the full color gamut available on the display.

For more information, see [HDR tone mapping in URP](#hdr-tone-mapping-in-urp) and [configure HDR tone mapping settings](#configure-hdr-tone-mapping-settings).

### Transfer function

The second step of HDR Output is the transfer function. The transfer function converts the output of the rendering process to levels of brightness of a given display. Unity determines the correct transfer function for the display and uses it to encode the output according to the standard the display expects. This enables Unity to use the correct level of precision for the gamma and create accurate exposure levels on the target display.

## HDR tone mapping in URP

After you enable **Allow HDR Display Output**, you must configure [Tonemapping](./../post-processing-tonemapping.md) settings for your HDR input.
After you enable **Allow HDR Display Output**, you must configure [tone mapping](./../post-processing-tonemapping.md) settings for your HDR input.

In order to configure these settings effectively, you need to understand how certain values related to tone mapping determine the visual characteristics of your HDR output.

Expand All @@ -45,15 +70,15 @@ However, in HDR mode, URP uses Paper White values to determine the brightness of

As a result, Paper White values determine the brightness of UI elements in HDR mode, especially white elements, whose brightness matches Paper White values.

## Configure HDR Tone Mapping settings
## Configure HDR tone mapping settings

You can select and adjust Tonemapping modes in the [Volume](./../Volumes.md) component settings. You can also adjust some aspects of your HDR Tonemapping configuration with a script (see the [HDROutputSettings API](#the-hdroutputsettings-api)).
You can select and adjust tone mapping modes in the [Volume](./../Volumes.md) component settings. You can also adjust some aspects of your HDR tone mapping configuration with a script (see the [HDROutputSettings API](#the-hdroutputsettings-api)).

After you enable **Allow HDR Display Output**, HDR Tonemapping options become visible in the Volume component.
After you enable **Allow HDR Display Output**, HDR tone mapping options become visible in the Volume component.

### Tone mapping modes

URP provides two **Tonemapping** modes: **Neutral** and **ACES**. Each Tonemapping mode has some unique properties.
URP provides two **Tonemapping** modes: **Neutral** and **ACES**. Each tone mapping mode has some unique properties.

* **Neutral** mode is especially suitable for situations where you do not want the tone mapper to color grade your content.
* **ACES** mode uses the ACES reference color space for feature films. It produces a cinematic, contrasty result.
Expand Down Expand Up @@ -92,13 +117,13 @@ The [HDROutputSettings](https://docs.unity3d.com/ScriptReference/HDROutputSettin

These values are also listed on the HDR output display table on the Rendering Debugger. To access the table, navigate to **Window** > **Analysis** > **Render Pipeline Debugger** > **Rendering** > **HDR Output**.

## Offscreen Rendering
## Use Offscreen Rendering with HDR Output

When using offscreen rendering techniques, not all cameras in a scene output directly to the display. For example, when Unity is rendering the output to a Render Texture. In these situations, you use the output of the camera before rendering post-processing.
When you use offscreen rendering techniques, not all cameras in a scene output directly to the display, for example, when Unity renders the output to a Render Texture. In these situations, use the output of the camera before rendering post-processing.

Unity does not apply HDR Output processing to the output of cameras which use offscreen rendering techniques. This prevents HDR Output processing being applied twice to the camera's output.
Unity does not apply HDR Output processing to the output of cameras which use offscreen rendering techniques. This prevents HDR Output processing from being applied twice to the camera's output.

## SDR Rendering
## Use Standard Dynamic Range (SDR) Rendering with HDR Output enabled

HDR Output relies on HDR Rendering to provide pixel values in the correct format for tone mapping and color encoding. The values after HDR tone mapping are in nits and exceed 1. This differs from SDR Rendering where the pixel values are between 0 and 1. As a result of this, the use of SDR Rendering with HDR Output can cause the rendered image to look underexposed or oversaturated.

Expand Down

0 comments on commit 4937651

Please sign in to comment.