Porting from ShaderToy(GLSL) to shaderlab(HLSL/CG) unity not giving me the desired result.

I came across this beautiful shader from shadertoy which I am trying to implement in Unity. I managed to get the blur box background and also the random dots get generated. But I am not able to get the curl effect as shown in the original shader. Here is my code, where _MainText takes the default colour black and _MainTexBg has this texture attached,

108999-downloads.png

Shader "Unlit/MyFirstShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "black" {}
		_MainTexBg ("Curl Pattern Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _MainTexBg;
			float4 _MainTexBg_ST;

			float2 hash2( float n ) 
			{ 
				return frac(sin(float2(n,n+1.0))*float2(43758.5453123,22578.1459123)); 
			}

			// smoothstep interpolation of texture
			float4 ssamp( float2 uv, float oct )
			{
				uv = uv.xy / oct;
    
				//return texture( iChannel0, uv, -10.0 );
				float texSize = 8.;
    
				float2 x = uv * texSize - .5;
				float2 f = frac(x);
    
				// remove fractional part
				x = x - f;
    
				// apply smoothstep to fractional part
				f = f*f*(3.0-2.0*f);
    
				// reapply fractional part
				x = x + f;
    
				uv = (x+.5) / texSize;
    
				return tex2D( _MainTexBg, uv );
			}

			float2 e = float2(1./256., 0.);
			float4 dx( float2 uv, float oct ) 
			{ 
				return (ssamp(uv+e.xy,oct) - ssamp(uv-e.xy,oct)) / (2.*e.x); 
			}
			float4 dy( float2 uv, float oct ) 
			{ 
				return (ssamp(uv+e.yx,oct) - ssamp(uv-e.yx,oct)) / (2.*e.x); 
			}

			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				i.uv=1-i.uv;

				fixed4 col = tex2D(_MainTex, i.uv);
				col=mul(col,2.0);
				col = smoothstep(0.,1.,col);
				col.xyz = 1.-col.xyz;
				col.xyz = mul(col.xyz,pow(1. - 1.9*dot(i.uv-.5,i.uv-.5),.07));


				float4 res = float4(0.,0.,0.,0.);
				float scl = _ScreenParams.x/640.;

				// random paint drops
				//float fr = float(_Time.y);
				float period = _Time.y < 2.9 ? 30. : _Time.y < 47. ? 8. : 3.;
				float2 sparkPos = hash2(_Time.y+1.11) * _ScreenParams.xy;
				if( length(sparkPos-i.vertex)<5.*scl && i.vertex.x > 1. && i.vertex.y > 1. )
				{
					// everyones favourite colour gradient
					res = res + 2.5*float4(i.uv,0.5+0.5*sin(_Time.y),1.0);
				}

				float2 off = 0.* (float2(128.,128.)/_ScreenParams.xy) * unity_DeltaTime;

				float oct = .25;
				float2 curl1 = .001*float2( dy(i.uv,oct).x, -dx(i.uv,oct).x )*oct;
				oct = 5.; float sp = 0.1;
				curl1 = curl1 + .0002*float2( dy(i.uv+sp*_Time.y,oct).x, -dx(i.uv+sp*_Time.y,oct).x )*oct;

				off = off + curl1;
				off = mul(off,.4);

				res = res + .999*tex2D( _MainTexBg, i.uv - off);




				return col*res;

				
			}
			ENDCG
		}
	}
}

I am very new to shader programming. Thanks for your help.

I managed to import this shader to Unity. I attached [109136-shadertoy2unity-kindergarten-art-class-3.zip|109136] that you can export to your Assets folder.


Relevant parts of the rendering code:

Create a RenderTexture and assign it to bufferA_RT.

In OnPostRender() - (script attached to a Camera):

var screenTarget = RenderTexture.active;

// pass input channels
bufferA_Material.SetTexture(iChannel0_Id, bufferA_RT);
bufferA_Material.SetTexture(iChannel1_Id, bufferA_Channel1InputTexture);

// we need to render to a temporary buffer because rendering to a buffer that is used as shader input causes problems
var tempBuf = RenderTexture.GetTemporary(bufferA_RT.width, bufferA_RT.height, bufferA_RT.depth, bufferA_RT.format, RenderTextureReadWrite.Linear, bufferA_RT.antiAliasing);
Graphics.Blit(null, tempBuf, bufferA_Material);
Graphics.Blit(tempBuf, bufferA_RT);
RenderTexture.ReleaseTemporary(tempBuf);

// render to screen and use Image shader
image_Material.SetTexture(iChannel0_Id, bufferA_RT);
Graphics.Blit(null, screenTarget, image_Material);

Shader for Buf A - ( bufferA_Material uses this):

Shader "ShaderToy/KindergartenArtClass3-BufA"
{
	Properties
	{
		_Channel0 ("iChannel0", 2D) = "black" {}
		_Channel1 ("iChannel1", 2D) = "black" {}
	}
	SubShader
	{
		// No culling or depth
		Cull Off ZWrite Off ZTest Always

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
			};


			/*
				Common variables/functions for ShaderToy fragment programs
			*/

			#define iChannel0 _Channel0
			sampler2D iChannel0;

			#define iChannel1 _Channel1
			sampler2D iChannel1;

			#define iResolution _ScreenParams
			// float3;

			#define iTime _Time.y
			// float;

			#define iTimeDelta unity_DeltaTime.x
			// float;

			#define iFrame ((int)(_Time.y / iTimeDelta))
			// int;

			#define iMouse _MousePos
			float4 iMouse;

			float mod(float x, float y) { return x - y * floor(x / y); }


			/*
				Common shader mains for ShaderToy fragment programs
			*/

			void mainImage(out float4 fragColor, float2 fragCoord);

			v2f vert(appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv * iResolution.xy;
				return o;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				float4 fragColor;
				mainImage(fragColor, i.uv);
				return fragColor;
			}



			/*
				Kindergarten Art Class III - Buf A
				https://www.shadertoy.com/view/4ltXR4
			*/

			float2 hash2(float n) { return frac(sin(float2(n, n + 1.0))*float2(43758.5453123, 22578.1459123)); }

			// smoothstep interpolation of texture
			float4 ssamp(float2 uv, float oct)
			{
				uv /= oct;

				//return tex2D( iChannel0, uv, -10.0 );
				float texSize = 8.;

				float2 x = uv * texSize - .5;
				float2 f = frac(x);

				// remove fractional part
				x -= f;

				// apply smoothstep to fractional part
				f = f * f*(3.0 - 2.0*f);

				// reapply fractional part
				x += f;

				uv = (x + .5) / texSize;

				//uv.y = 1 - uv.y;
				//return tex2D(iChannel1, uv);
				return tex2Dbias(iChannel1, float4(uv, 0., -10.0));
			}

			// it's important to mark this static as otherwise it will not contain the assigned value
			static float2 e = float2(1. / 256., 0.);
			float4 dx(float2 uv, float oct) { return (ssamp(uv + e.xy, oct) - ssamp(uv - e.xy, oct)) / (2.*e.x); }
			float4 dy(float2 uv, float oct) { return (ssamp(uv + e.yx, oct) - ssamp(uv - e.yx, oct)) / (2.*e.x); }


			void mainImage(out float4 fragColor, float2 fragCoord)
			{
				float2 uv = fragCoord / iResolution.xy;
				float4 res = (float4)0.;
				float scl = iResolution.x / 640.;

				// random paint drops
				float fr = float(iFrame);
				float period = iTime < 2.9 ? 30. : iTime < 47. ? 8. : 3.;
				if (mod(fr, period) == 0.)
				{
					float2 sparkPos = hash2(iTime + 1.11) * iResolution.xy;
					if (length(sparkPos - fragCoord)<5.*scl && fragCoord.x > 1. && fragCoord.y > 1.)
					{
						// everyones favourite colour gradient
						res += 2.5*float4(uv, 0.5 + 0.5*sin(iTime), 1.0);
					}
				}

				// mouse paint
				if (length(fragCoord - iMouse.xy) < 5.*scl && iMouse.z > 0.)
				{
					// added sin gives pulsing feel
					res += .7*float4(uv, 0.5 + 0.5*sin(iTime), 1.0)*(.6 + .5*-sin(iTime*10.5));
				}

				// lookup offset
				float2 off = 0.* ((float2)128. / iResolution.xy) * iTimeDelta;

				float oct = .25;
				float2 curl1 = .001*float2(dy(uv, oct).x, -dx(uv, oct).x)*oct;
				oct = 5.; float sp = 0.1;
				curl1 += .0002*float2(dy(uv + sp * iTime, oct).x, -dx(uv + sp * iTime, oct).x)*oct;

				off += curl1;
				off *= .4;

				res += .999*tex2D(iChannel0, uv - off);

				fragColor = res;
			}

			ENDCG
		}
	}
}

As you can see I used some macros to ease the conversion.

I believe you need two separate shaders. The main large shader you have here (“Buf A” code in shadertoy) would be rendered into a RenderTexture and then another shader (the “Image” code in shadertoy) would render that RenderTexture to the screen or a quad or something.