Unity Unite China 2024: A Parallel Universe? Unity's Global Impact and Local Innovations For the…
Scripting tips for for our post-processing effects in URP
Unity’s Universal Render Pipeline (URP) marks a significant advancement in graphics rendering within Unity development. Tailored for diverse platforms, URP efficiently manages rendering, achieving a harmonious blend of visual sophistication and optimized performance. Its architecture, built on modern graphics APIs, ensures stunning visuals while prioritizing efficiency.
Essentially transforming the legacy Unity’s graphics pipeline, also known as built-in pipeline, URP offers a cohesive framework for creating impressive visuals across platforms. Leveraging Shader Graphs and Render Features, developers gain enhanced flexibility in crafting visually dynamic scenes, encompassing real-time lighting and post-processing effects.
Despite the vast possibilities, navigating URP may present challenges due to its extensive settings and new workflow compared to built-in pipeline. In this article, we address a couple of common questions asked by our community: how to control our post processing effects using scripting. We’ll cover Beautify and Radiant Global Illumination examples.
Overriding values in Beautify 3 for URP via Scripting
Before going into code examples, please note that all our assets contain example scripts in the demo scenes that illustrate a basic usage of scripting.
The following script provides an example of how to interact with the Beautify asset in Unity’s Universal Render Pipeline (URP). Let’s break it down:
Initialization:
using Beautify.Universal;
...
Beautify beautify;
void Start()
{
beautify = BeautifySettings.settings;
}
- A variable
beautify
of typeBeautify.Universal.Beautify
is declared (Beautify.Universal is the namespace for Beautify in URP). - In the
Start
method, it’s assigned the value ofBeautifySettings.settings
. The settings class is an utility class provided by Beautify that simplifies the task of accessing the profile values in the current volume (assuming there’s one in the scene). If you have different volumes in the scene, you will have to manually get a reference to the profile of the desired volume (check the Radiant Global Illumination example).
Update Method:
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
beautify.bloomIntensity.Override(0);
beautify.anamorphicFlaresIntensity.Override(0);
}
}
- The
Update
method is called once per frame. - The condition checks if the space key is pressed (
Input.GetKeyDown(KeyCode.Space)
). - If the condition is true, it overrides the Beautify settings for
bloomIntensity
andanamorphicFlaresIntensity
to 0.
Explanation:
beautify.bloomIntensity.Override(0);
: This line sets the bloom intensity to 0, effectively turning off the bloom effect.beautify.anamorphicFlaresIntensity.Override(0);
: This line sets the anamorphic flares intensity to 0, turning off anamorphic flares.
In URP, the post-processing volume system works with overrides. Each effect exposes different options and in order to set them with your own values you must not only assign a value to them (0 in the example above) but also you must “override” them (override means that the value you specify must be actually used instead of any other default value).
Toggle ON/OFF Radiant Global Ilumination
Let’s break down the script for toggling the Radiant GI effect in Unity URP projects and we will explain the most important parameters:
using RadiantGI.Universal;
...
void Update() {
// Check if the space key is pressed
if (Input.GetKeyDown(KeyCode.Space)) {
// Get the VolumeProfile component from the current GameObject
VolumeProfile volumeProfile = GetComponent<Volume>()?.profile;
// Throw an exception if the VolumeProfile is not found
if (!volumeProfile) throw new System.NullReferenceException(nameof(VolumeProfile));
// Declare a variable for RadiantGlobalIllumination
RadiantGlobalIllumination radiant;
// Try to get the RadiantGlobalIllumination component from the VolumeProfile
// Throw an exception if it's not found
if (!volumeProfile.TryGet(out radiant)) throw new System.NullReferenceException(nameof(radiant));
// Override the indirect intensity to 0, effectively toggling off the effect
radiant.indirectIntensity.Override(0f);
}
}
- VolumeProfile: retrieves the
VolumeProfile
component attached to the current GameObject. Throws an exception if not found. - RadiantGlobalIllumination: attempts to get the
RadiantGlobalIllumination
component from the VolumeProfile. Throws an exception if not found. - Effect Toggle: overrides the
indirectIntensity
property of RadiantGlobalIllumination to 0, effectively turning off the indirect illumination effect.
In summary, this script allows users to toggle the Radiant GI effect on and off in Unity URP projects by pressing the space key during runtime. The using RadiantGI.Universal;
directive makes referencing Radiant GI-related types and members more concise.
GetComponent<Volume>()
: This method retrieves theVolume
component attached to the GameObject this script is on. TheVolume
component is commonly used in Unity’s Universal Render Pipeline (URP) for applying post-processing effects using the Volume framework.?.profile
: This is the null-conditional operator (?.
) introduced in C# 6. It allows checking fornull
before accessing a property or invoking a method on an object. If the object on the left side of?.
isnull
, the entire expression returnsnull
. In this case:- If
GetComponent<Volume>()
returnsnull
(meaning there’s noVolume
component), the entire expression evaluates tonull
. - If
GetComponent<Volume>()
is notnull
, it accesses theprofile
property of theVolume
component.
- If
This usage helps prevent null reference exceptions. If GetComponent<Volume>()
returns null
, volumeProfile
will be assigned null
without throwing an exception. If it’s not null
, volumeProfile
will hold the value of the profile
property.
In the context of Unity’s URP, a VolumeProfile
is a container for post-processing settings. It holds a collection of VolumeComponent
instances, each responsible for a specific post-processing effect. In this script, it allows checking if a VolumeProfile
is present on the GameObject before proceeding with further operations.
This is it! We hope these examples help clarifying some concepts. If not, please let us know in the forum/Discord.