Unity custom render textures
It seems like Unity's Custom Render Textures provides much of the functionality that I'd want to create strange glitchy/feedback effects.
The workflow is a little messy and nested, but we'll break it down here in text, cos I'm lazy to take screenshots.
Firstly you have a material, which has a shader (could be anything), but importantly, it uses a texture - our custom render texture.
The custom render texture itself takes a few different inputs - it needs a material to update it and "something" to initialise it with. The Initialisation could just be from a texture, but should you require something a bit more flexible, you can assign a material with a shader.
Both the update material and intialisation material shaders are a little different to the ones I've been covering here, in terms of structure. This is because they're specifically operating within the custom render texture workflow.
Firstly - the initialisation shader -
Shader "customRT/init_shader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
CGINCLUDE
#include "UnityCustomRenderTexture.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
half4 frag(v2f_init_customrendertexture i):SV_Target
{
fixed4 tex = tex2D(_MainTex,i.texcoord);
return tex;
}
ENDCG
SubShader
{
Pass
{
Name "Init"
CGPROGRAM
#pragma vertex InitCustomRenderTextureVertexShader
#pragma fragment frag
ENDCG
}
}
}
As usual it has a name and some properties - however we have to use the InitCustomRenderTextureVertexShader for our vertex shader - also note that the pragmas are all relegated to the lower pass. We also must include "UnityCustomRenderTexture.cginc".
The fragment shader part of this code is between a CGINCLUDE/ENDCG block and the rest of it is fairly business as usual.
The update shader is fairly similar -
Shader "customRT/update_shader"
{
Properties
{
_MainTex("Main Texture", 2D) = "grey"{}
mult("multiply",float) = 1.0
rdrift("red drift",float)=0.0
gdrift("green drift",float) = 0.0
}
CGINCLUDE
#include "UnityCustomRenderTexture.cginc"
sampler2D _MainTex;
float mult;
float rdrift;
float gdrift;
float2 rotateuv(float2 uv, float angle) {
float2x2 rot = float2x2(cos(angle), -sin(angle), sin(angle), cos(angle));
uv = mul(rot, uv);
return uv;
}
half4 frag(v2f_customrendertexture i) : SV_Target
{
float2 uv = i.globalTexcoord;
fixed4 col=tex2D(_SelfTexture2D,uv);
uv = rotateuv(uv, _Time.x);
fixed red= tex2D(_SelfTexture2D, uv).r*mult;
col.r += red*0.03;
fixed green = tex2D(_SelfTexture2D, uv ).g*mult;
col.g += green*0.04;
if (col.r > 0.95)col.r *= 0.1;
if (col.g > 0.9)col.g *= 0.05;
return half4(col);
}
ENDCG
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
Name "Update"
CGPROGRAM
#pragma vertex CustomRenderTextureVertexShader
#pragma fragment frag
ENDCG
}
}
}
This time the vertex shader drops the "init" part of the name, but again, we must use this specific one & include the cginc file as well.
Some useful stuff from the Unity docs -
The _SelfTexture2D texture is very useful - it is basically the "last frame rendered". On the custom render texture, there is a "double buffered" checkbox. That must be enabled for it to work (i think). It is useful because we can do things in a "solver" like fashion. In the example code I posted, I keep taking the previous frame & rotate the UVs, then add a fraction of the new red and green channel to it.
Keijiro has a good reaction diffusion example online, which I intend to dissect. There's also a good firey noise example online somewhere too. I'm very curious to see what I can do if I use video-stream as an input here!!
Comments
Post a Comment