Documentation

Unity Engine


User Manual

Script Reference

Unity Engine


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.
Read time 4 minutesLast updated 21 days ago

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. For an explanation of the two raster spaces and which coordinates each texture takes, refer to Introduction to foveated rendering.

Prerequisites

Before you begin, make sure that:
  • Your project uses the Universal Render Pipeline (URP) and meets the conditions in Foveated rendering support reference.
  • 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)

DefaultLinearNon-uniform
RawLinearLinear
CenterLinearNon-uniform
TiledLinearNon-uniform
PixelLinearNon-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

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:

Correct coordinate space

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 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:
    #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 nodevoid 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

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