Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Custom post-processing stack - blitting multiple times in the same script

Discussion in 'Scripting' started by dogs_, Jul 17, 2020.

  1. dogs_

    dogs_

    Joined:
    Mar 14, 2016
    Posts:
    30
    I have a series of post-processing effects that I want to run in immediate succession on the same camera (much like the post-processing stack, but for my own shaders), but for some reason my stack seems to break or corrupt the final rendertexture before blitting to the screen (the final result is pure black). However I also have a generic post-processing script that blits with just 1 material, and if I add multiple of those to the same camera then it works as intended, but that doesn't seem super efficient.

    Here is the single material post-processor:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [ExecuteInEditMode]
    6. public class GenericPostProcessor : MonoBehaviour {
    7.  
    8.     public Material mat;
    9.  
    10.     void OnRenderImage (RenderTexture source, RenderTexture destination) {
    11.         Graphics.Blit (source, destination, mat);
    12.     }
    13.  
    14. }
    15.  
    and here is the custom stack:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [ExecuteInEditMode]
    6. public class GenericPostProcessorStack : MonoBehaviour {
    7.  
    8.     public Material[] mats;
    9.  
    10.     void OnRenderImage (RenderTexture source, RenderTexture destination) {
    11.         for (int i = 0; i < mats.Length; i++) {
    12.             Graphics.Blit (source, destination, mats[i]);
    13.             if (i < mats.Length - 1) {
    14.                 source = destination;
    15.             }
    16.         }
    17.     }
    18.  
    19. }
    20.  
    The line "source = destination" seems to be what is causing the problem (if my array of materials is only 1 element long then there is no issue) and I have the feeling that I should be using temporary rendertextures for multiple blits, but I haven't been able to find resources for the syntax required or the best practices etc.

    Should I be using a temporary texture? Can I blit from the source to itself multiple times before blitting to the destination? Is there a better way to do this?
    Thanks.
     
  2. bentontr

    bentontr

    Joined:
    Jun 9, 2017
    Posts:
    39
    Hey there,
    I do something similar with a custom post processing stack in my game. I think you are on the right track with the temporary render textures as that is what I do. Here is some sample code that might help you out:

    Code (CSharp):
    1.         if (_blitMaterials.Count == 0)
    2.         {
    3.             Graphics.Blit(source, destination);
    4.             return;
    5.         }
    6.  
    7.         RenderTexture tempA = null;
    8.         RenderTexture tempB = null;
    9.         RenderTexture tempC = null;
    10.  
    11.         switch (_blitMaterials.Count)
    12.         {
    13.             case 4:
    14.                 tempA = RenderTexture.GetTemporary(source.width, source.height, 0, source.format);
    15.                 tempB = RenderTexture.GetTemporary(source.width, source.height, 0, source.format);
    16.                 tempC = RenderTexture.GetTemporary(source.width, source.height, 0, source.format);
    17.  
    18.                 Graphics.Blit(source, tempA, _blitMaterials[0]);
    19.                 Graphics.Blit(tempA, tempB, _blitMaterials[1]);
    20.                 Graphics.Blit(tempB, tempC, _blitMaterials[2]);
    21.                 Graphics.Blit(tempC, destination, _blitMaterials[3]);
    22.                 break;
    23.             case 3:
    24.                 tempA = RenderTexture.GetTemporary(source.width, source.height, 0, source.format);
    25.                 tempB = RenderTexture.GetTemporary(source.width, source.height, 0, source.format);
    26.  
    27.                 Graphics.Blit(source, tempA, _blitMaterials[0]);
    28.                 Graphics.Blit(tempA, tempB, _blitMaterials[1]);
    29.                 Graphics.Blit(tempB, destination, _blitMaterials[2]);
    30.                 break;
    31.             case 2:
    32.                 tempA = RenderTexture.GetTemporary(source.width, source.height, 0, source.format);
    33.  
    34.                 Graphics.Blit(source, tempA, _blitMaterials[0]);
    35.                 Graphics.Blit(tempA, destination, _blitMaterials[1]);
    36.                 break;            
    37.             default:
    38.                 Graphics.Blit(source, destination, _blitMaterials[0]);
    39.                 break;
    40.         }
    41.  
    42.         if (tempA != null)
    43.         {
    44.             RenderTexture.ReleaseTemporary(tempA);
    45.         }
    46.  
    47.         if (tempB != null)
    48.         {
    49.             RenderTexture.ReleaseTemporary(tempB);
    50.         }
    51.  
    52.         if (tempC != null)
    53.         {
    54.             RenderTexture.ReleaseTemporary(tempC);
    55.         }
    The switch statement is a little messy, but you could try that first and then work on getting it working in a loop if you have a large number of variable materials.
     
  3. dogs_

    dogs_

    Joined:
    Mar 14, 2016
    Posts:
    30
    Temps fixed it! I think the problem was "renderTexture = otherRenderTexture". It seems to be a syntax error but it doesn't get picked up by the console.

    Here is the code I ended up using:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [ExecuteInEditMode]
    6. public class GenericPostProcessorStack : MonoBehaviour {
    7.  
    8.     public Material[] mats;
    9.  
    10.     void OnRenderImage (RenderTexture source, RenderTexture destination) {
    11.         RenderTexture tempSrc = RenderTexture.GetTemporary (source.width, source.height, source.depth, source.format);
    12.         RenderTexture tempDst = RenderTexture.GetTemporary (source.width, source.height, source.depth, source.format);
    13.         //^grab two temp textures that are the same as the source;
    14.  
    15.         Graphics.Blit (source, tempSrc); //blit the source into the tempSrc;
    16.  
    17.         for (int i = 0; i < mats.Length; i++) { //for all the materials;
    18.             if ((float) i % 2.0f == 0.0f) { //if i is even blit from src to dst, if not then dst to src.
    19.                 Graphics.Blit (tempSrc, tempDst, mats[i]);
    20.             } else {
    21.                 Graphics.Blit (tempDst, tempSrc, mats[i]);
    22.             }
    23.         }
    24.  
    25.         if ((float) mats.Length % 2.0f == 0.0f) { //if the total number of materials is even;
    26.             //then we blit from the tempSrc;
    27.             Graphics.Blit (tempSrc, destination); //final blit from tempSrc to dest;
    28.         } else { //if not;
    29.             //then we blit from the tempDst;
    30.             Graphics.Blit (tempDst, destination); //final blit from tempDst to dest;
    31.         }
    32.  
    33.         RenderTexture.ReleaseTemporary (tempSrc);
    34.         RenderTexture.ReleaseTemporary (tempDst);
    35.         //^release the temp textures;
    36.     }
    37. }
    38.  
     
    Ghat-Smith likes this.