scripting custom render texture creation, assignment, shaders

I got a little fed up of dragging the (wrong) custom render texture swatches onto materials in the inspector (slightly down to my crap naming conventions & Unity's project window only showing the first 8 letters of each name- can this be changed?!), so I decided to figure out a C# script that could make this easier. The entire script is way below - I'm just going to highlight a few important lines.

  Shader shader = Shader.Find("custom/createdTextureShader");

This finds a shader that you've created externally. You could have a public shader variable at the top instead, so you could drop stuff into the Inspector.

 _init_mat = new Material(init_shader);

 Here we make a new material, using a specified shader type.


 _init_mat.SetTexture("_initTex", init_texture);

Then we give it a texture file. _initTex is a property I've specified for the init_shader. Typically there is a _MainTex by default. I just wanted to see if you could specify arbitrary property names - you can! Another method of doing this is by using id values. I've commented out some lines where I tried to get this working (it didn't haha)

      _tex = new CustomRenderTexture(512, 512);
        _tex.name = GetType().Name;
        _tex.depth = 0;
        _tex.Create();

Next we make _tex, a new custom render texture with specified 512 resolution. I'm not entirely sure what the name part is for...I stole this part of the code from a Unity forum post. The _tex.depth setting to 0 is "necessary" for the double buffered switching to work. I prefer setting it to zero here instead of using the ZTest always in the shader. Maybe there'll come a time where I'll see why this isn't great. Lastly we create the tex with _tex.Create();   

  _tex.initializationSource = CustomRenderTextureInitializationSource.Material;

  _double.updateMode = CustomRenderTextureUpdateMode.OnDemand;

These lines really annoyed me. Pretty much noone on the internet has written about them, or how to set them. I guess it is "basic" knowledge for those in the know! Anyway this is how to set the initialisation source/updatemode or any other enumerated drop down option, I guess.

void OnDisable()
    {
        _tex.Release();
        Destroy(_intermediate_mat);
        Destroy(_tex);
        Destroy(_update_mat);
        Destroy(_CRTmat);
        Destroy(_init_mat);
        Destroy(_real_final_mat);
        _double.Release();
        Destroy(_double);
    }

 Finally - we should do some housekeeping and destroy all the textures and materials we've created.

Final code below -

 

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

public class create_custom_RT : MonoBehaviour
{
    Material _update_mat;
    Material _CRTmat;
    Material _init_mat;
    Material _real_final_mat;
    Material _intermediate_mat;
    public Texture2D init_texture;
    public RenderTexture update_texture;
    
    
    CustomRenderTexture _tex;
    CustomRenderTexture _double;
    

    void OnEnable()
    {
        Shader shader = Shader.Find("custom/createdTextureShader");
        Shader init_shader = Shader.Find("custom/create_shader_init");
        Shader finalshader = Shader.Find("custom/standardShader");

        _init_mat = new Material(init_shader);


//        int init_texture_id=init_shader.FindPropertyIndex("_initTex");//not using this method of id
      
  //      int init_texture_main_id = init_shader.FindPropertyIndex("_MainTex");//not using this method of id
        

        _init_mat.SetTexture("_initTex", init_texture);
    

        _update_mat = new Material(shader);
        _update_mat.SetTexture("_MainTex", update_texture);

        _tex = new CustomRenderTexture(512, 512);
        _tex.name = GetType().Name;
        _tex.depth = 0;
        _tex.Create();
        
        _tex.material = _update_mat;
       

        _tex.initializationSource = CustomRenderTextureInitializationSource.Material;
        _tex.initializationMaterial = _init_mat;

        _tex.doubleBuffered = true;

        _tex.initializationMode = CustomRenderTextureUpdateMode.OnLoad;
        _tex.updateMode = CustomRenderTextureUpdateMode.OnDemand;
        _tex.updatePeriod = 0.0333f;
        
        _CRTmat = new Material(finalshader);
        _CRTmat.mainTexture = _tex;

        _intermediate_mat = new Material(shader);
        _intermediate_mat.SetTexture("_MainTex", _tex);

        _double = new CustomRenderTexture(512, 512);
        _double.name = GetType().Name;
        _double.depth = 0;
        _double.Create();
        _double.material = _intermediate_mat;
        _double.initializationSource = CustomRenderTextureInitializationSource.Material;
        _double.initializationMaterial = _CRTmat;
        _double.doubleBuffered = true;
        _double.initializationMode = CustomRenderTextureUpdateMode.OnLoad;
        _double.updateMode = CustomRenderTextureUpdateMode.OnDemand;
        _double.updatePeriod = 0.333f;


        _real_final_mat = new Material(finalshader);
        _real_final_mat.mainTexture = _double;




        GetComponent<Renderer>().material = _real_final_mat;
        

    }

    private void Update()
    {
        _tex.Update();
        _double.Update();
    }

    void OnDisable()
    {
        _tex.Release();
        Destroy(_intermediate_mat);
        Destroy(_tex);
        Destroy(_update_mat);
        Destroy(_CRTmat);
        Destroy(_init_mat);
        Destroy(_real_final_mat);
        _double.Release();
        Destroy(_double);
    }
}

Comments

Popular posts from this blog

setting VFX graph properties using C#