Adding Dynamic Post-Processing in 2018.2

Adding dynamic post-processing in Unity 2018.2 is incredibly easy. It doesn't beat the post-processing volumes available in 2018.3, but this is the next best thing. For this example, I will be using two packages, the Post Processsing Stack and the Standard Asset Package, both available from the Unity Asset store. I will be using the first person character prefab from the standard asset package, but of course, you can easily integrate this example into your own project.

Download Unity Project

Download C# Script

Download the Post Processing Stack

From the asset store built into the Unity engine, you can download and import the post-processing plugin directly into your project.

Attach Post-Processing Behavior Script to Camera

Simply click on "Add Component" in the inspector window, and search and add the Post-Processing Behavior script that you just imported from the asset store.

Create Post-Processing Profile

From there, right-click in your project window and create a Post-Processing Profile (Create > Post-Processing Profile). Click on the profile and in the inspector window you'll see a wide array of attributes to edit. By default, all but fog are checked off, but by simply clicking the checkbox you can turn on and off certain effects. For this demonstration, I will be using Depth of Field, Color Grading and Chromatic Aberration. All of these attributes can be edited, including enabling and disabling them all with code.

You might notice that any changes you make to the profile won't actually make changes to the actual game. The Post-Processing Behavior you added to the camera needs to use the profile to determine how to interpret the scene. Simply add Post-Processing Behavior you just created and add it to the field "Profile" under the Post-Processing Behavior script under the camera and voilĂ ! Once the profile is attached to the camera, further adjustments will be shown live, both in the editor and in-game.

Changing The Post-Processing Profile In Code

Create a new C# script (I called mine 'Script_profile_update'). All code requires the post-processing library in order to work. Simply include it like so:

using UnityEngine.PostProcessing;

Change Simple Values

public PostProcessingProfile editProf;
float defaultCAIntensity = 0.15f;

ChromaticAberrationModel.Settings CASettings = editProf.chromaticAberration.settings; //get current profile values
            CASettings.intensity = 1; //change the chromatic intensity to 1 and set to temporary profile CASettings
            editProf.chromaticAberration.settings = CASettings; //overwrite profile with new value

All values in the Post-Processing Profile are accessible this way. Grain is GrainModel, Color Grading is ColorGradingModel, and so on. By itself, changing the values of CASettings isn't going to make changes to the profile, think of it as a temporary variable that holds changes. The last line overwrites the values of the profile. This is the reason why we need either a float to hold default values, or another Post-Processing Profile to feed on (example below).

public PostProcessingProfile prof1;
public PostProcessingProfile prof2;

/*Get settings from profile 2 and overwrite settings for profile 1*/
prof1.chromaticAberration.settings = prof2.chromaticAberration.settings;

Changing Color Grading


/*Edit Color Grading settings*/
ColorGradingModel.Settings CGSettings = editProf.colorGrading.settings; //get current profile values
float newRed = CGSettings.channelMixer.red.x; //gets current value of red under the 'red' channel of the color grader
if (CGSettings.channelMixer.red.x < 2f){ //if current red value is less than max
        newRed += 0.01f; //increase amount of red by 0.01 every tick
}
CGSettings.channelMixer.red = new Vector3(newRed, 0f, 0f); //change the amount of red in the color grader
editProf.colorGrading.settings = CGSettings; //overwrite profile with new value

This is arguably the more challenging field to edit. The values are stored not as a traditional float, but as a vector3 variable.
You have to specify which channel you're wanting to edit, in this case, I want red (channelMixer.red). All vector3 variables store 3 values (x, y, z), so if I wanted to find the value of green under the red channel, I would type out channelMixer.red.y. I used this method to gradually increase the value of red every tick before reaching the max value of 2. I made a new Vector3 variable and attached it to the temporary profile variable CGSettings. I then overwrote the main profile with the updated settings.

Enabling and Disabling Effects


editProf.depthOfField.enabled = true; //enables the DOF in profile

This is the easiest thing to edit. I will be using this to turn on depth of field, which has a focus distance set to 0.1 when the player presses 'F' to interact.


public GameObject uiPickup; //the UI popup image

/*UI pickup example*/

if (Input.GetKeyDown(KeyCode.F) && enter){
                
                if (uiPickup.activeSelf) //checks whether the UI is visible
                {
                    /*If true*/
                    uiPickup.SetActive(false); //remove UI image
                    editProf.depthOfField.enabled = false; //disables the DOF in profile
                }else{
                    /*If false*/
                    editProf.depthOfField.enabled = true; //enables the DOF in profile
                    uiPickup.SetActive(true); //makes UI image visible in canvas
                }
            }

Full Script With Collision Events


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.PostProcessing;

public class Script_profile_update : MonoBehaviour {

    public PostProcessingProfile editProf; //the Post-Processing Profile you want to edit
    public GameObject uiPickup; //the UI popup image

    bool enter = false; //whether the player is in colliding volume

    /*Default Post-Processing values*/
    float defaultCAIntensity = 0.15f;

void Update () {
        /*Edit Post-Processing Volume after when in collider*/
        if (enter)
        {
            /*Edit Chromatic Aberration settings*/
            ChromaticAberrationModel.Settings CASettings = editProf.chromaticAberration.settings; //get current profile values
            CASettings.intensity = 1; //change the chromatic intensity to 1 and set to temporary profile CASettings
            editProf.chromaticAberration.settings = CASettings; //overwrite profile with new value

            /*Edit Color Grading settings*/
            ColorGradingModel.Settings CGSettings = editProf.colorGrading.settings; //get current profile values
            float newRed = CGSettings.channelMixer.red.x; //gets current value of red under the 'red' channel of the color grader
            if (CGSettings.channelMixer.red.x < 2f){ //if current red value is less than max
                newRed += 0.01f; //increase amount of red by 0.01 every tick
            }
            CGSettings.channelMixer.red = new Vector3(newRed, 0f, 0f); //change the amount of red in the color grader
            editProf.colorGrading.settings = CGSettings; //overwrite profile with new value

            /*UI pickup example*/
            if (Input.GetKeyDown(KeyCode.F) && enter){
                
                if (uiPickup.activeSelf){ //checks whether the UI is visible
                    /*If true*/
                    uiPickup.SetActive(false); //remove UI image
                    editProf.depthOfField.enabled = false; //disables the DOF in profile
                }else{
                    /*If false*/
                    editProf.depthOfField.enabled = true; //enables the DOF in profile
                    uiPickup.SetActive(true); //makes UI image visible in canvas
                }
            }
        }
    }

    /*Detect whether player can interact with object*/
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            enter = true;
        }
    }
    
    /*Detect when the player exits the collider*/
    void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            enter = false;
        }
    }
}