# Update shader graph effects for foveated rendering

> Choose a Screen Position node mode that matches the texture you sample, and remap Raw mode coordinates with a Custom Function node.

Shader graphs that sample screen-space textures can produce incorrect results on XR platforms that use variable rate rasterization (VRR). The pixels Unity renders no longer form a regular grid. The **Screen Position** node supplies the coordinates that most of these effects sample with, so the mode you select determines whether the effect samples the correct part of a texture.

To adapt a hand-coded shader instead, refer to [Adapt custom shaders for foveated rendering](/engine/6000.7/manual/xr/graphics/foveated-rendering/custom-shaders.md). For an explanation of the two raster spaces and which coordinates each texture takes, refer to [Introduction to foveated rendering](/engine/6000.7/manual/xr/graphics/foveated-rendering/introduction.md).

## Prerequisites

Before you begin, make sure that:

* Your project uses the Universal Render Pipeline (URP) and meets the conditions in [Foveated rendering support reference](/engine/6000.7/manual/xr/graphics/foveated-rendering/support.md).
* You have a shader graph that performs screen-space calculations.

## Choose a Screen Position node mode

The **Screen Position** node in Shader Graph provides coordinates that you often use to sample textures that foveated rendering affects. The **Mode** setting of this node determines the coordinate space the node provides. In most modes, the coordinate space is non-uniform when Unity renders with VRR. The **Raw** mode, in contrast, is linear in all cases.

The following table shows the coordinate space each mode provides:

| **Mode**    | **UV coordinate space with variable rate shading (VRS) and non-foveated rendering** | **UV coordinate space with variable rate rasterization (VRR)** |
| ----------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| **Default** | Linear                                                                              | Non-uniform                                                    |
| **Raw**     | Linear                                                                              | Linear                                                         |
| **Center**  | Linear                                                                              | Non-uniform                                                    |
| **Tiled**   | Linear                                                                              | Non-uniform                                                    |
| **Pixel**   | Linear                                                                              | Non-uniform                                                    |

If you use the **Screen Position** node's **Raw** mode to sample a non-uniform texture, the results are incorrect.

To illustrate the situation, consider a shader graph with a **Screen Position** node connected to a **Scene Depth** node that, in turn, connects to the base color of a fragment shader.


**Shader graph with a Screen Position node connected to a Scene Depth node:**
![](/api/media?file=/engine/6000.7/media/images/xr-sg-depth-to-color.png)

The shader renders colors according to the depth values in the scene depth buffer, and works correctly under foveated rendering. It uses the **Default** mode **Screen Position** node. That mode returns its results in the same space as the depth buffer and most other textures Unity creates. If you change the mode to **Raw**, the results are no longer correct when foveated rendering is active on a platform that uses VRR.

In the following example, the left image shows the shader on a quad, using the correct coordinate space to sample the scene depth buffer. The right image shows the same shader using the wrong coordinate space for the sampled texture. Notice how the sampled texture no longer lines up with the scene geometry:

1. **Before**


   **Correct coordinate space:**
   ![](/api/media?file=/engine/6000.7/media/images/xr-foveated-render-depth-view-fixed.webp)

2. **After**


   **Mismatched coordinate space:**
   ![](/api/media?file=/engine/6000.7/media/images/xr-foveated-render-depth-view-broken.webp)

Correct sampling (left) compared to mismatched sampling (right).

## Remap Raw mode coordinates with a Custom Function node

If your shader graph depends on the **Raw** screen position and can't use any of the other modes, remap the **Raw** coordinates with a **Custom Function** node. First, normalize the coordinates, and then use the [foveated rendering shader functions](/engine/6000.7/manual/xr/graphics/foveated-rendering/shader-functions.md) inside a second node to remap them.

To remap the **Raw** coordinates:

1. Create a **Custom Function** node that references a file containing the following:

   ```lang-hlsl
   #include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
   #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"

   // Receives normalized screen coordinates (xy divided by w) from a preceding normalization node
   void CorrectedScreenPosition_float(float2 normalizedScreenPosition, out float2 correctedScreenPosition)
   {
       correctedScreenPosition = FoveatedRemapLinearToNonUniform(normalizedScreenPosition);
   }
   ```

2. Route the **Raw** coordinates through the node.

> **Note:**
>
> You must create the **Custom Function** node to reference a file in this case, because if you use the **String** type, the `#include` statements are inside the function body and cause syntax errors. Set its input type to **Vector2** to match the normalized `float2` output from the preceding node.

For example, the following shader graph routes the **Raw** coordinates through two **Custom Function** nodes:


**Shader graph that converts the Raw UV coordinates with Custom Function nodes:**
![](/api/media?file=/engine/6000.7/media/images/xr-sg-raw-depth-to-color.png)

The first **Custom Function** node normalizes the **Raw** coordinates by dividing the x and y elements by the w element (`B = A.xy/A.ww`). The second **Custom Function** node uses `FoveatedRemapLinearToNonUniform` to map the linear coordinates to the non-uniform space when necessary. When foveated rendering isn't active, or the current platform doesn't use VRR for foveated rendering, `FoveatedRemapLinearToNonUniform` returns the linear coordinates unchanged. The shader therefore samples the scene depth correctly in all situations.

## Additional resources

* [Foveated rendering shader compatibility workflow](/engine/6000.7/manual/xr/graphics/foveated-rendering/shader-workflow.md)
* [Shader Graph Custom Function node](https://docs.unity3d.com/Packages/com.unity.shadergraph@latest?subfolder=/manual/Custom-Function-Node.html)
* [Core RP Library package documentation](https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest?subfolder=/manual/index.html)
