Converting a Shadertoy Multipass shader to Unity / HLSL ?

As a big Shadertoy fan - I’ve been enjoying porting these shaders into other platforms such as Processing (www.processing.org) - from here I have lots of control over animation and render output.

The new multipass feature on Shadertoy however is causing me problems with Processing. Shadertoy uses 16 bit image buffers to render data to, such as this shader,

But Processing can only create standard 8 bit image buffers. So I’m now trying to convert these mulitpass shaders into Unity - hoping I can use an 16 bit image buffer.

I have managed to get basic single pass Shadertoy examples working in Unity using this,

But now I’m stuck - I’m new to Unity - and to HLSL. Could anyone tell me how to code a Unity shader which can do multipass, i.e. rendering into a 16 bit image first, then a final output pass - exactly like the shader above.

Thanks!
Glenn.

1 Like

You want to look into Graphics.Blit(). I would suggest importing in the Standard Assets Image Effects and looking at some of the camera post processes. Bloom is a good, simple image effect that shows off doing multipass rendering, and the Motion Blur effect is a good example of creating a semi-permanent render texture that is reused over multiple frames.

Thanks! will look into this… :slight_smile:

Hi I Created Simple Converter from ShaderToy to Shaderlab Unity
Download Link: GitHub - smkplus/ShaderMan: Convert ShaderToy to Unity HLSL/CG
Youtube Link:
https://www.youtube.com/watch?v=ZncPTfT8wLg

I hope someone help me to develop it…

7 Likes

OMG. Perfect. I try to help. What is needed?

Hi,

could you help me with

i corrected

vec2 rotateCCW(vec2 p, float a)
{
mat2 m = mat2(cos(a), sin(a), -sin(a), cos(a));
return p * m;
}

vec2 rotateCW(vec2 p, float a)
{
mat2 m = mat2(cos(a), -sin(a), sin(a), cos(a));
return p * m;
}

to…

fixed2 rotateCCW(fixed2 p, fixed a)
{
fixed2x2 m = fixed2x2(cos(a), sin(a), -sin(a), cos(a));
return mul(p,m);
}

fixed2 rotateCW(fixed2 p, fixed a)
{
fixed2x2 m = fixed2x2(cos(a), -sin(a), sin(a), cos(a));
return mul(p,m);
}

manually and then i get this error

Output value ‘vert’ is not completely initialized
Compiling Vertex program

Hi I’m glad if you help me to improve this converter
I will Put ToDo list of needed in my github

This is incomplete but I hope help you…
download this shader:

3295593–255409–2dsigneddistancefunctions.shader (9.72 KB)

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader"ShaderMan/MyShader"{
Properties
{
_iResolution("iResolution", Vector) = (1,1,0,0)
_iMouse("iMouse", Vector) = (0,0,0,0)
}
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
};

uniform fixed3         _iResolution;     // viewport resolution in pixels
uniform fixed4     fragColor;
uniform fixed      iChannelTime[4];// channel playback time (in seconds)
uniform fixed3     iChannelResolution[4];// channel resolution (in pixels)
uniform fixed4     _iMouse;// mouse pixel coords. xy: current (if MLB down), zw: click
uniform fixed4     iDate;// (year, month, day, time in seconds)
uniform fixed      iSampleRate;// sound sample rate (i.e., 44100)



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

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


fixed smoothMerge(fixed d1, fixed d2, fixed k)
{
    fixed h = clamp(0.5 + 0.5*(d2 - d1)/k, 0.0, 1.0);
    return lerp(d2, d1, h) - k * h * (1.0-h);
}


fixed merge(fixed d1, fixed d2)
{
    return min(d1, d2);
}


fixed mergeExclude(fixed d1, fixed d2)
{
    return min(max(-d1, d2), max(-d2, d1));
}


fixed substract(fixed d1, fixed d2)
{
    return max(-d1, d2);
}


fixed intersect(fixed d1, fixed d2)
{
    return max(d1, d2);
}





fixed2 rotateCCW(fixed2 p, fixed a)
{
    fixed2x2 m = fixed2x2(cos(a), sin(a), -sin(a), cos(a));
    return mul(p,m);   
}


fixed2 rotateCW(fixed2 p, fixed a)
{
    fixed2x2 m = fixed2x2(cos(a), -sin(a), sin(a), cos(a));
    return mul(p,m);
}


fixed2 translate(fixed2 p, fixed2 t)
{
    return p - t;
}





fixed pie(fixed2 p, fixed angle)
{
    angle = radians(angle) / 2.0;
    fixed2 n = fixed2(cos(angle), sin(angle));
    return abs(p).x * n.x + p.y*n.y;
}


fixed circleDist(fixed2 p, fixed radius)
{
    return length(p) - radius;
}


fixed triangleDist(fixed2 p, fixed radius)
{
    return max(    abs(p).x * 0.866025 +
                   p.y * 0.5, -p.y)
                -radius * 0.5;
}


fixed triangleDist(fixed2 p, fixed width, fixed height)
{
    fixed2 n = normalize(fixed2(height, width / 2.0));
    return max(    abs(p).x*n.x + p.y*n.y - (height*n.y), -p.y);
}


fixed semiCircleDist(fixed2 p, fixed radius, fixed angle, fixed width)
{
    width /= 2.0;
    radius -= width;
    return substract(pie(p, angle),
                     abs(circleDist(p, radius)) - width);
}


fixed boxDist(fixed2 p, fixed2 size, fixed radius)
{
    size -= fixed2(radius,radius);
    fixed2 d = abs(p) - size;
      return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius;
}


fixed lineDist(fixed2 p, fixed2 start, fixed2 end, fixed width)
{
    fixed2 dir = start - end;
    fixed lngth = length(dir);
    dir /= lngth;
    fixed2 proj = max(0.0, min(lngth, dot((start - p), dir))) * dir;
    return length( (start - p) - proj ) - (width / 2.0);
}




fixed fillMask(fixed dist)
{
    return clamp(-dist, 0.0, 1.0);
}


fixed innerBorderMask(fixed dist, fixed width)
{
    //dist += 1.0;
    fixed alpha1 = clamp(dist + width, 0.0, 1.0);
    fixed alpha2 = clamp(dist, 0.0, 1.0);
    return alpha1 - alpha2;
}


fixed outerBorderMask(fixed dist, fixed width)
{
    //dist += 1.0;
    fixed alpha1 = clamp(dist, 0.0, 1.0);
    fixed alpha2 = clamp(dist - width, 0.0, 1.0);
    return alpha1 - alpha2;
}




fixed sceneDist(fixed2 p)
{
    fixed c = circleDist(        translate(p, fixed2(100, 250)), 40.0);
    fixed b1 =  boxDist(        translate(p, fixed2(200, 250)), fixed2(40, 40),     0.0);
    fixed b2 =  boxDist(        translate(p, fixed2(300, 250)), fixed2(40, 40),     10.0);
    fixed l = lineDist(            p,              fixed2(370, 220),  fixed2(430, 280),    10.0);
    fixed t1 = triangleDist(    translate(p, fixed2(500, 210)), 80.0,             80.0);
    fixed t2 = triangleDist(    rotateCW(translate(p, fixed2(600, 250)), _Time.y), 40.0);
   
    fixed m =     merge(c, b1);
    m =         merge(m, b2);
    m =         merge(m, l);
    m =         merge(m, t1);
    m =         merge(m, t2);
   
    fixed b3 = boxDist(        translate(p, fixed2(100, sin(_Time.y * 3.0 + 1.0) * 40.0 + 100.0)),
                               fixed2(40, 15),     0.0);
    fixed c2 = circleDist(    translate(p, fixed2(100, 100)),    30.0);
    fixed s = substract(b3, c2);
   
    fixed b4 = boxDist(        translate(p, fixed2(200, sin(_Time.y * 3.0 + 2.0) * 40.0 + 100.0)),
                               fixed2(40, 15),     0.0);
    fixed c3 = circleDist(    translate(p, fixed2(200, 100)),     30.0);
    fixed i = intersect(b4, c3);
   
    fixed b5 = boxDist(        translate(p, fixed2(300, sin(_Time.y * 3.0 + 3.0) * 40.0 + 100.0)),
                               fixed2(40, 15),     0.0);
    fixed c4 = circleDist(    translate(p, fixed2(300, 100)),     30.0);
    fixed a = merge(b5, c4);
   
    fixed b6 = boxDist(        translate(p, fixed2(400, 100)),    fixed2(40, 15),     0.0);
    fixed c5 = circleDist(    translate(p, fixed2(400, 100)),     30.0);
    fixed sm = smoothMerge(b6, c5, 10.0);
   
    fixed sc = semiCircleDist(translate(p, fixed2(500,100)), 40.0, 90.0, 10.0);
   
    fixed b7 = boxDist(        translate(p, fixed2(600, sin(_Time.y * 3.0 + 3.0) * 40.0 + 100.0)),
                               fixed2(40, 15),     0.0);
    fixed c6 = circleDist(    translate(p, fixed2(600, 100)),     30.0);
    fixed e = mergeExclude(b7, c6);
   
    m = merge(m, s);
    m = merge(m, i);
    m = merge(m, a);
    m = merge(m, sm);
    m = merge(m, sc);
    m = merge(m, e);
   
    return m;
}


fixed sceneSmooth(fixed2 p, fixed r)
{
    fixed accum = sceneDist(p);
    accum += sceneDist(p + fixed2(0.0, r));
    accum += sceneDist(p + fixed2(0.0, -r));
    accum += sceneDist(p + fixed2(r, 0.0));
    accum += sceneDist(p + fixed2(-r, 0.0));
    return accum / 5.0;
}





fixed shadow(fixed2 p, fixed2 pos, fixed radius)
{
    fixed2 dir = normalize(pos - p);
    fixed dl = length(p - pos);
   
    // fracion of light visible, starts at one radius (second fixed added in the end);
    fixed lf = radius * dl;
   
    // distance traveled
    fixed dt = 0.01;

    for (int i = 0; i < 64; ++i)
    {               
        // distance to scene at current position
        fixed sd = sceneDist(p + dir * dt);

        // early out when this ray is guaranteed to be full shadow
        if (sd < -radius)
            return 0.0;
       
        // width of cone-overlap at light
        // 0 in center, so 50% overlap: add one radius outside of loop to get total coverage
        // should be '(sd / dt) * dl', but '*dl' outside of loop
        lf = min(lf, sd / dt);
       
        // move ahead
        dt += max(1.0, abs(sd));
        if (dt > dl) break;
    }

    // multiply by dl to get the real projected overlap (moved out of loop)
    // add one radius, before between -radius and + radius
    // normalize to 1 ( / 2*radius)
    lf = clamp((lf*dl + radius) / (2.0 * radius), 0.0, 1.0);
    lf = smoothstep(0.0, 1.0, lf);
    return lf;
}



fixed4 drawLight(fixed2 p, fixed2 pos, fixed4 color, fixed dist, fixed range, fixed radius)
{
    // distance to light
    fixed ld = length(p - pos);
   
    // out of range
    if (ld > range) return fixed4(0.0,0.0,0.0,0.0);
   
    // shadow and falloff
    fixed shad = shadow(p, pos, radius);
    fixed fall = (range - ld)/range;
    fall *= fall;
    fixed source = fillMask(circleDist(p - pos, radius));
    return (shad * fall + source) * color;
}


fixed luminance(fixed4 col)
{
    return 0.2126 * col.r + 0.7152 * col.g + 0.0722 * col.b;
}


void setLuminance(inout fixed4 col, fixed lum)
{
    lum /= luminance(col);
    col *= lum;
}


fixed AO(fixed2 p, fixed dist, fixed radius, fixed intensity)
{
    fixed a = clamp(dist / radius, 0.0, 1.0) - 1.0;
    return 1.0 - (pow(abs(a), 5.0) + 1.0) * intensity + (1.0 - intensity);
    return smoothstep(0.0, 1.0, dist / radius);
}




fixed4 frag(v2f i) : SV_Target{

{
    fixed2 p = i.uv.xy * _iResolution.xy + fixed2(0.5,0.5);
    //fixed2 p = i.uv.xy * 512.0 + fixed2(0.5,0.5);
    fixed2 c = _iResolution.xy / 2.0;

    //fixed dist = sceneSmooth(p, 5.0);
    fixed dist = sceneDist(p);
   
    fixed2 light1Pos = _iMouse.xy;
    //fixed2 light1Pos =  fixed4(0,0,0,0);
    fixed4 light1Col = fixed4(0.75, 1.0, 0.5, 1.0);
    setLuminance(light1Col, 0.4);
   
    fixed2 light2Pos = fixed2(_iResolution.x * (sin(_Time.y + 3.1415) + 1.2) / 2.4, 175.0);
    fixed4 light2Col = fixed4(1.0, 0.75, 0.5, 1.0);
    setLuminance(light2Col, 0.5);
   
    fixed2 light3Pos = fixed2(_iResolution.x * (sin(_Time.y) + 1.2) / 2.4, 340.0);
    fixed4 light3Col = fixed4(0.5, 0.75, 1.0, 1.0);
    setLuminance(light3Col, 0.6);
   
    // gradient
    fixed4 col = fixed4(0.5, 0.5, 0.5, 1.0) * (1.0 - length(c - p)/_iResolution.x);
    // grid
    col *= clamp(min(fmod(p.y, 10.0), fmod(p.x, 10.0)), 0.9, 1.0);
    // ambient occlusion
    col *= AO(p, sceneSmooth(p, 10.0), 40.0, 0.4);
    //col *= 1.0-AO(p, sceneDist(p), 40.0, 1.0);
    // light
    col += drawLight(p, light1Pos, light1Col, dist, 150.0, 6.0);
    col += drawLight(p, light2Pos, light2Col, dist, 200.0, 8.0);
    col += drawLight(p, light3Pos, light3Col, dist, 300.0, 12.0);
    // shape fill
    col = lerp(col, fixed4(0.5, 0.5, 0.5, 1.0), fillMask(dist));
    // shape outline
    col = lerp(col, fixed4(0.4, 0.4, 0.4, 1.0), innerBorderMask(dist, 1.5));

    return  clamp(col, 0.0, 1.0);
}

}ENDCG
}
}
}

``

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


public class RaycastInfoToShader : MonoBehaviour
{
    void Update ()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit)) {
            Vector4 iResolution = GetComponent<Renderer>().material.GetVector ("_iResolution");

            Vector4 iMouse = new Vector4(hit.textureCoord.x * iResolution.x, hit.textureCoord.y * iResolution.y, 0, 0);

            GetComponent<Renderer> ().material.SetVector ("_iMouse", iMouse);
        }
    }
}

Thanks.
This is the working version. ShaderMan/MyShader
Use this and the RaycastInfoToShader.cs on the plane for mouse movement.

using UnityEngine;
using System.Collections;

public class ShaderToy : MonoBehaviour
{
    public float speed = 1;

    public int horizontalResolution = 320;
    public int verticalResolution = 240;

    public Material Material = null;

    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        Material.SetFloat("_Speed", speed);
        //Graphics.Blit(source, destination, Material);

        RenderTexture scaled = RenderTexture.GetTemporary(horizontalResolution, verticalResolution);
        Graphics.Blit(source, scaled, Material);
        Graphics.Blit(scaled, destination);
        RenderTexture.ReleaseTemporary(scaled);
    }
}

You could also hang ShaderToy.cs to the camera and put any of your materials in.
Then it renders your shadertoy shaders to the camera.

next working on the fft sound input

hello :slight_smile: I checked this wonderfull shadertoy converter … it works great for single pass shaders … but how about multipass shaders like these :

how to convert this kind of shaders to Unity ?

I hope you can help me :slight_smile:

best regards

Chris

hello again :slight_smile:

there is bug in matrix multiplication conversion … after conversion we have a*m but must be mul(a,m)

Hello,

i think you cannot replace mod with fmod
in CodeFix.cs 241
Input = Regex.Replace(Input, “mod”, “fmod”);

for positive numbers is ok,
for negative numbers not

fmod (HLSL) will output a positive number
mod (GLSL) will output a negative number

you can define a macro
#define ModFix(x, y) (x - y * floor(x / y))

found it here after some hours of wondering why

Hey,

the fft sound is nearly done.
I have some problems to have correct output for this great shader…

Here s i my fix so far.
Probably you have an idea.

Works so far in an XRAY Variant.)

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
//https://www.shadertoy.com/view/Msl3Rr
Shader"ShaderMan/Cubescape"
{
    Properties
    {
        _MainTex("_MainTex", 2D) = "white"{}
        _SecondTex("SecondTex", 2D) = "white"{}
        _iMouse("iMouse", Vector) = (0,0,0,0)
        _iResolution("iResolution", Vector) = (1,1,0,0)
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma fragmentoption ARB_precision_hint_fastest
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            uniform fixed4     fragColor;
            uniform fixed      iChannelTime[4];            // channel playback time (in seconds)
            uniform fixed3     iChannelResolution[4];    // channel resolution (in pixels)
            uniform fixed4     iMouse;                    // mouse pixel coords. xy: current (if MLB down), zw: click
            uniform fixed4     iDate;                    // (year, month, day, time in seconds)
            uniform fixed      iSampleRate;                // sound sample rate (i.e., 44100)
            sampler2D _MainTex;
            sampler2D _SecondTex;

            float4 _iMouse;
            uniform fixed3         _iResolution;            // viewport resolution in pixels

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

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.screenCoord.xy = ComputeScreenPos(o.vertex);
                return o;
            }
            // Created by inigo quilez - iq/2013
            // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

            //---------------------------------

            #define ANTIALIAS 1

            fixed hash( fixed n ) { return frac(sin(n)*13.5453123); }

            fixed maxcomp( in fixed3 v ) { return max( max( v.x, v.y ), v.z ); }

            fixed dbox( fixed3 p, fixed3 b, fixed r )
            {
                return length(max(abs(p)-b,0.0))-r;
            }

            fixed4 texcube( sampler2D sam, in fixed3 p, in fixed3 n )
            {
                fixed4 x = tex2D( sam, p.yz );
                fixed4 y = tex2D( sam, p.zx );
                fixed4 z = tex2D( sam, p.yx );
                fixed3 a = abs(n);
                return (x*a.x + y*a.y + z*a.z) / (a.x + a.y + a.z);
            }

            //---------------------------------

            fixed freqs[4];

            fixed3 mapH( in fixed2 pos )
            {
                fixed2 fpos = frac( pos );
                fixed2 ipos = floor( pos );
  
                fixed f = 0.0;  
                fixed id = hash( ipos.x + ipos.y*57.0 );
                //mul?
                f += freqs[0] * clamp(1.0 - abs(id-0.20)/0.30, 0.0, 1.0 );
                f += freqs[1] * clamp(1.0 - abs(id-0.40)/0.30, 0.0, 1.0 );
                f += freqs[2] * clamp(1.0 - abs(id-0.60)/0.30, 0.0, 1.0 );
                f += freqs[3] * clamp(1.0 - abs(id-0.80)/0.30, 0.0, 1.0 );

                f = pow( clamp( f, 0.0, 1.0 ), 2.0 );
                fixed h = 2.5*f;

                return fixed3( h, id, f );
            }

            fixed3 map( in fixed3 pos )
            {
                fixed2  p = frac( pos.xz );
                fixed3  m = mapH( pos.xz );
                fixed d = dbox( fixed3(p.x-0.5,pos.y-0.5*m.x,p.y-0.5), fixed3(0.3,m.x*0.5,0.3), 0.1 );
                return fixed3( d, m.yz );
            }

            const fixed surface = 0.001;

            fixed3 trace( fixed3 ro, in fixed3 rd, in fixed tmin, in fixed tmax )
            {
                ro += tmin*rd;
  
                fixed2 pos = floor(ro.xz);
                fixed3 rdi = 1.0/rd;
                fixed3 rda = abs(rdi);
                fixed2 rds = sign(rd.xz);
                fixed2 dis = (pos-ro.xz+ 0.5 + rds*0.5) * rdi.xz;
  
                fixed3 res = fixed3( -1.0 , -1.0 , -1.0 );

                // traverse regular grid (in 2D)
                fixed2 mm = fixed2(0.0,0.0);
                [unroll(100)]
            for( int i=0; i<28; i++ )
                {
                    fixed3 cub = mapH( pos );

                    #if 1
                        fixed2 pr = pos+0.5-ro.xz;
                        fixed2 mini = (pr-0.5*rds)*rdi.xz;
                        fixed s = max( mini.x, mini.y );
                        if( (tmin+s)>tmax ) break;
                    #endif
      
      
                    // intersect box
                    fixed3  ce = fixed3( pos.x+0.5, 0.5*cub.x, pos.y+0.5 );
                    fixed3  rb = fixed3(0.3,cub.x*0.5,0.3);
                    fixed3  ra = rb + 0.12;
                    fixed3  rc = ro - ce;
                    fixed tN = maxcomp( -rdi*rc - rda*ra );
                    fixed tF = maxcomp( -rdi*rc + rda*ra );
                    if( tN < tF )//&& tF > 0.0 )
                    {
                        // raymarch
                        fixed s = tN;
                        fixed h = 1.0;
                        [unroll(100)]
                        for( int j=0; j<24; j++ )
                        {
                            h = dbox( rc+s*rd, rb, 0.1 );
                            s += h;
                            if( s>tF ) break;
                        }

                        if( h < (surface*s*2.0) )
                        {
                            res = fixed3( s, cub.yz );
                            break;
                        }
          
                    }

                    // step to next cell      
                    mm = step( dis.xy, dis.yx );
                    dis += mm*rda.xz;
                    pos += mm*rds;
                }

                res.x += tmin;
  
                return res;
            }


            fixed softshadow( in fixed3 ro, in fixed3 rd, in fixed mint, in fixed maxt, in fixed k )
            {
                fixed res = 1.0;
                fixed t = mint;
                [unroll(100)]
                for( int i=0; i<50; i++ )
                {
                    fixed h = map( ro + rd*t ).x;
                    res = min( res, k*h/t );
                    t += clamp( h, 0.05, 0.2 );
                    if( res<0.001 || t>maxt ) break;
                }
                return clamp( res, 0.0, 1.0 );
            }

            fixed3 calcNormal( in fixed3 pos, in fixed t )
            {
                fixed2 e = fixed2(1.0,-1.0)*surface*t;
                return normalize( e.xyy*map( pos + e.xyy ).x +
                                  e.yyx*map( pos + e.yyx ).x +
                                  e.yxy*map( pos + e.yxy ).x +
                                  e.xxx*map( pos + e.xxx ).x );
            }

            const fixed3 light1 = fixed3(  0.70, 0.52, -0.45 );
            const fixed3 light2 = fixed3( -0.71, 0.000,  0.71 );
            const fixed3 lpos = fixed3(0.0,0.0,0.0) + 6.0 * fixed3(  0.70, 0.52, -0.45 );
            //const fixed3 lpos = fixed3(0.0,0.0,0.0) + 6.0 * light1;

            fixed2 boundingVlume( fixed2 tminmax, in fixed3 ro, in fixed3 rd )
            {
                fixed bp = 2.7;
                fixed tp = (bp-ro.y)/rd.y;
                if( tp>0.0 )
                {
                    if( ro.y>bp ) tminmax.x = max( tminmax.x, tp );
                    else          tminmax.y = min( tminmax.y, tp );
                }
                bp = 0.0;
                tp = (bp-ro.y)/rd.y;
                if( tp>0.0 )
                {
                    if( ro.y>bp ) tminmax.y = min( tminmax.y, tp );
                }
                return tminmax;
            }

            fixed3 doLighting( in fixed3 col, in fixed ks,
                             in fixed3 pos, in fixed3 nor, in fixed3 rd )
            {
                fixed3  ldif = lpos - pos;
                fixed llen = length( ldif );
                ldif /= llen;
                fixed con = dot( light1,ldif);
                fixed occ = lerp( clamp( pos.y/4.0, 0.0, 1.0 ), 1.0, max(0.0,nor.y) );
                fixed2 sminmax = fixed2(0.01, 5.0);

                fixed sha = softshadow( pos, ldif, sminmax.x, sminmax.y, 32.0 );;
      
                fixed bb = smoothstep( 0.5, 0.8, con );
                fixed lkey = clamp( dot(nor,ldif), 0.0, 1.0 );
                fixed3  lkat = fixed3(1.0,1.0,1.0);
                      lkat *= fixed3(bb*bb*0.6+0.4*bb,bb*0.5+0.5*bb*bb,bb).zyx;
                      lkat /= 1.0+0.25*llen*llen;      
                      lkat *= 30.0;
                      lkat *= sha;
                fixed lbac = clamp( 0.1 + 0.9*dot( light2, nor ), 0.0, 1.0 );
                      lbac *= smoothstep( 0.0, 0.8, con );
                      lbac /= 1.0+0.2*llen*llen;      
                      lbac *= 4.0;
                fixed lamb = 1.0 - 0.5*nor.y;
                      lamb *= 1.0-smoothstep( 10.0, 25.0, length(pos.xz) );
                      lamb *= 0.25 + 0.75*smoothstep( 0.0, 0.8, con );
                      lamb *= 0.25;
      
                fixed3 lin  = 1.0*fixed3(0.20,0.05,0.02)*lamb*occ;
                     lin += 1.0*fixed3(1.60,0.70,0.30)*lkey*lkat*(0.5+0.5*occ);
                     lin += 1.0*fixed3(0.70,0.20,0.08)*lbac*occ;
                     lin *= fixed3(1.3,1.1,1.0);

                col = col*lin;

                fixed3 spe = ks*lkey*lkat*(0.5+0.5*occ)*5.0*
                           pow( clamp(dot(normalize(ldif-rd), nor),0.0,1.0), 4.0 ) *
                           (0.04+0.96*pow(clamp(dot(nor,-rd),0.0,1.0),5.0));

                col += (0.5+0.5*ks)*0.5*spe*fixed3(1.0,0.9,0.7);

                return col;
            }

            fixed3x3 setLookAt( in fixed3 ro, in fixed3 ta, fixed cr )
            {
                fixed3  cw = normalize(ta-ro);
                fixed3  cp = fixed3(sin(cr), cos(cr),0.0);
                fixed3  cu = normalize( cross(cw,cp) );
                fixed3  cv = normalize( cross(cu,cw) );
                return fixed3x3( cu, cv, cw );
            }

            fixed3 render( in fixed3 ro, in fixed3 rd )
            {
                fixed3 col = fixed3( 0.0 , 0.0 , 0.0 );

                fixed2 tminmax = fixed2(0.0, 40.0 );

                tminmax = boundingVlume( tminmax, ro, rd );

                // raytrace
                fixed3 res = trace( ro, rd, tminmax.x, tminmax.y );
                if( res.y > -0.5 )
                {
                    fixed t = res.x;
                    fixed3 pos = ro + t*rd;
                    fixed3 nor = calcNormal( pos, t );

                    // material  
                    col = 0.5 + 0.5*cos( 6.2831*res.y + fixed3(0.0, 0.4, 0.8) );
                    fixed3 ff = texcube( _SecondTex, 0.1*fixed3(pos.x,4.0*res.z-pos.y,pos.z), nor ).xyz;
                    col *= ff.x;

                    // lighting
                    col = doLighting( col, ff.x, pos, nor, rd );
                    col *= 1.0 - smoothstep( 20.0, 40.0, t );
                }
                return col;
            }



            fixed4 frag(v2f i) : SV_Target{

            {
                freqs[0] = tex2D( _MainTex, fixed2( 0.01, 0.25 ) ).x;
                freqs[1] = tex2D( _MainTex, fixed2( 0.07, 0.25 ) ).x;
                freqs[2] = tex2D( _MainTex, fixed2( 0.15, 0.25 ) ).x;
                freqs[3] = tex2D( _MainTex, fixed2( 0.30, 0.25 ) ).x;
                //-----------
                //fixed time = 5.0 + 0.2*_Time.y + 20.0*_iMouse.x/1;
                fixed time = 5.0 + 0.2*_Time.y + 20.0*_iMouse.x / _iResolution.x;

                fixed2 _i_uv = i.uv;

                fixed3 tot = fixed3(0.0,0.0,0.0);

                //#ifdef ANTIALIAS
                //[unroll(2)]
                //for( int j=0; j<ANTIALIAS; j++ )
                //[unroll(2)]
                //for( int i=0; i<ANTIALIAS; i++ )
                //{
                        //fixed2 off = fixed2(fixed(i),fixed(j))/fixed(ANTIALIAS);
                    //#else
                        fixed2 off = fixed2(0.0,0.0);
                    //#endif
                  
                        fixed2 xy = (-_iResolution.xy + 2.0 * (_i_uv)) / _iResolution.y;
                        //fixed2 xy = (-1 + 2.0 * (_i_uv)) / 1;
                        //fixed2 xy = (-1 + 2.0 * (_i_uv + off)) / 1;
                        //fixed2 xy = (-1+2.0*(i.uv)) / 1;
                        //fixed2 xy = (-1+2.0*(i.uv+off)) / 1;

                        // camera  
                        fixed3 ro = fixed3( 8.5*cos(0.2+.33*time), 5.0+2.0*cos(0.1*time), 8.5*sin(0.1+0.37*time) );
                        fixed3 ta = fixed3( -2.5+3.0*cos(1.2+.41*time), 0.0, 2.0+3.0*sin(2.0+0.38*time) );
                        fixed roll = 0.2*sin(0.1*time);

                        // camera tx
                        fixed3x3 ca = setLookAt( ro, ta, roll );
                        //fixed3 rd = normalize( ca * fixed3(xy.xy,1.75) );
                        //fixed3 rd = normalize( mul(ca, fixed3(xy.xy,1.75)) );
                        fixed3 rd = normalize(mul(fixed3(xy.xy, 1.75), ca));


      
                        fixed3 col = render( ro, rd );
                        col = pow( col, fixed3(0.4545,0.4545,0.4545) );
                        col = pow( col, fixed3(0.8,0.95,1.0) );
                        col = clamp(col,0.0,1.0);
                        tot += col;
      
                    //#ifdef ANTIALIAS
                //}
                //tot /= fixed(ANTIALIAS*ANTIALIAS);
                //#endif  
  
                // vigneting
                //fixed2 q = i.uv.xy/ _iResolution.xy;
                fixed2 q = _i_uv.xy / _iResolution.xy;
                tot *= 0.2 + 0.8*pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.1 );

                return  fixed4( tot, 1.0 );
            }


            }ENDCG
        }
    }
}

Here is example of converted ShaderToy multi-pass shader (self-accumulated buffer) to Unity, using compute shader and two render textures:

Source code:

//Simplified version of shader, which full version was created by Florian Berger: https://www.shadertoy.com/view/MsGSRd
//Translated from ShaderToy to Unity by Przemyslaw Zaworski, 18.12.2017, https://github.com/przemyslawzaworski/Unity3D-CG-programming
//Additional support: Seyed Morteza Kamaly, https://github.com/smkplus
//To simulate self-accumulated buffer, I use two render textures which are swapped between every render frame.
//Usage: apply fluid_dynamics.cs script to gameobject, select fluid_dynamics.compute and any material with _MainTex free slot,
//for example built-in Unlit/Texture.

#pragma kernel CSMain

Texture2D<float4> reader;
RWTexture2D<float4> writer;
SamplerState _LinearClamp;

[numthreads(8,8,1)]
void CSMain (uint2 id : SV_DispatchThreadID)
{
    float2 f = float2(id.x,id.y);  //fragCoord
    float2 b = float2(0.31,0.95);
    float2 iResolution=float2(1024,1024); //texture resolution
    float2 v = float2(0.0,0.0);
    float4 c = float4(0,0,0,1);   //initial color
    for(int l=0;l<20;l++)
    {
        if ( dot(b,b) > pow(iResolution.y,2.0) ) break;
        float2 p = b;
        for(int i=0;i<5;i++)
        {         
            float2 pos = f+p;
            float rot=0.0;
            for(int i=0;i<5;i++)
            {
                rot+=dot(reader.SampleLevel(_LinearClamp,float2(frac((pos+p)/iResolution.xy)),0).xy-float2(0.5,0.5),mul(float2(1,-1),p.yx));
                p=float2(0.31*p.x+0.95*p.y,-0.95*p.x+0.31*p.y);
            }
            v+=p.yx* rot/5.0/dot(b,b);     
            p=float2(0.31*p.x+0.95*p.y,-0.95*p.x+0.31*p.y);
        }
        b*=2.0;
    }  
    float4 color=reader.SampleLevel(_LinearClamp,frac((f+v*float2(-2,2))/iResolution.xy),0);
    float2 s=(f.xy/iResolution.xy)*2.0-float2(1.0,1.0);
    color.xy += (0.01*s.xy / (dot(s,s)/0.1+0.3));
    c = color;
    writer[id]=c;
}
//Load fluid_dynamics.compute into Unity 3D engine.
using UnityEngine;

public class fluid_dynamics : MonoBehaviour
{
    public ComputeShader compute_shader;
    RenderTexture A;
    RenderTexture B;
    public Material material;   
    int handle_main;
 
    void Start()
    {
        A = new RenderTexture(1024,1024,0);
        A.enableRandomWrite = true;
        A.Create();   
        B = new RenderTexture(1024,1024,0);
        B.enableRandomWrite = true;
        B.Create();   
        handle_main = compute_shader.FindKernel("CSMain");
    }
       
    void Update()
    {
        compute_shader.SetTexture(handle_main, "reader", A);   
        compute_shader.SetTexture(handle_main, "writer", B);
        compute_shader.Dispatch(handle_main, A.width / 8, A.height / 8, 1);
        compute_shader.SetTexture(handle_main, "reader", B);   
        compute_shader.SetTexture(handle_main, "writer", A);
        compute_shader.Dispatch(handle_main, B.width / 8, B.height / 8, 1);
        material.mainTexture = B;
    }
}
3 Likes

Amazing!!!
works fine!
but some platform don’t support compute shaders :frowning:
have you any idea?