【Unity】將 Shadertoy 上的 Shader 移植到 Unity 里

Shadertoy 上有許多驚人的 Shader,不過要讓 Unity 用上需要進(jìn)行一系列的改寫锚烦。

本文并不完整,是自學(xué)時(shí)的一些記錄帝雇,僅供參考涮俄。

shader 代碼框架

在 Unity 中任意創(chuàng)建一個(gè) XXX.shader 文件,內(nèi)容大致如下:

Shader "Custom/Test"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _BackTex ("BackTex", 2D) = "white" {}
        _Mouse("Mouse", Vector) = (0.5,0.5,0.5,0.5)
        _iTime("iTime", Float) = 20.0
    }
    SubShader
    {
        Pass 
        {
            cull off

            CGPROGRAM

            // 這里將放入 shader 代碼
            
            ENDCG
        }
    }
    FallBack "Diffuse"
}

定義一系列宏銜接變量與函數(shù)

Shadertoy 上的 Shader 使用 GLSL 書寫摊求,需要給原 Shader 代碼添加一系列宏禽拔,從而銜接到 HLSL:

#define vec2 float2
#define vec3 float3
#define vec4 float4
#define mat2 float2x2
#define mat3 float3x3
#define mat4 float4x4
#define iGlobalTime _Time.y
#define mod fmod
#define mix lerp
#define fract frac
#define texture2D tex2D
#define iResolution _ScreenParams
#define gl_FragCoord ((_iParam.scrPos.xy/_iParam.scrPos.w) * _ScreenParams.xy)
#define PI2 6.28318530718
#define pi 3.14159265358979
#define halfpi (pi * 0.5)
#define oneoverpi (1.0 / pi)

實(shí)例

對于這個(gè) Shader刘离,原代碼如下:

// Heartfelt - by Martijn Steinrucken aka BigWings - 2017
// Email:countfrolic@gmail.com Twitter:@The_ArtOfCode
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

#define S(a, b, t) smoothstep(a, b, t)
//#define CHEAP_NORMALS
#define HAS_HEART
#define USE_POST_PROCESSING

vec3 N13(float p) {
    //  from DAVE HOSKINS
   vec3 p3 = fract(vec3(p) * vec3(.1031,.11369,.13787));
   p3 += dot(p3, p3.yzx + 19.19);
   return fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
}

vec4 N14(float t) {
    return fract(sin(t*vec4(123., 1024., 1456., 264.))*vec4(6547., 345., 8799., 1564.));
}
float N(float t) {
    return fract(sin(t*12345.564)*7658.76);
}

float Saw(float b, float t) {
    return S(0., b, t)*S(1., b, t);
}


vec2 DropLayer2(vec2 uv, float t) {
    vec2 UV = uv;
    
    uv.y += t*0.75;
    vec2 a = vec2(6., 1.);
    vec2 grid = a*2.;
    vec2 id = floor(uv*grid);
    
    float colShift = N(id.x); 
    uv.y += colShift;
    
    id = floor(uv*grid);
    vec3 n = N13(id.x*35.2+id.y*2376.1);
    vec2 st = fract(uv*grid)-vec2(.5, 0);
    
    float x = n.x-.5;
    
    float y = UV.y*20.;
    float wiggle = sin(y+sin(y));
    x += wiggle*(.5-abs(x))*(n.z-.5);
    x *= .7;
    float ti = fract(t+n.z);
    y = (Saw(.85, ti)-.5)*.9+.5;
    vec2 p = vec2(x, y);
    
    float d = length((st-p)*a.yx);
    
    float mainDrop = S(.4, .0, d);
    
    float r = sqrt(S(1., y, st.y));
    float cd = abs(st.x-x);
    float trail = S(.23*r, .15*r*r, cd);
    float trailFront = S(-.02, .02, st.y-y);
    trail *= trailFront*r*r;
    
    y = UV.y;
    float trail2 = S(.2*r, .0, cd);
    float droplets = max(0., (sin(y*(1.-y)*120.)-st.y))*trail2*trailFront*n.z;
    y = fract(y*10.)+(st.y-.5);
    float dd = length(st-vec2(x, y));
    droplets = S(.3, 0., dd);
    float m = mainDrop+droplets*r*trailFront;
    
    //m += st.x>a.y*.45 || st.y>a.x*.165 ? 1.2 : 0.;
    return vec2(m, trail);
}

float StaticDrops(vec2 uv, float t) {
    uv *= 40.;
    
    vec2 id = floor(uv);
    uv = fract(uv)-.5;
    vec3 n = N13(id.x*107.45+id.y*3543.654);
    vec2 p = (n.xy-.5)*.7;
    float d = length(uv-p);
    
    float fade = Saw(.025, fract(t+n.z));
    float c = S(.3, 0., d)*fract(n.z*10.)*fade;
    return c;
}

vec2 Drops(vec2 uv, float t, float l0, float l1, float l2) {
    float s = StaticDrops(uv, t)*l0; 
    vec2 m1 = DropLayer2(uv, t)*l1;
    vec2 m2 = DropLayer2(uv*1.85, t)*l2;
    
    float c = s+m1.x+m2.x;
    c = S(.3, 1., c);
    
    return vec2(c, max(m1.y*l0, m2.y*l1));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = (fragCoord.xy-.5*iResolution.xy) / iResolution.y;
    vec2 UV = fragCoord.xy/iResolution.xy;
    vec3 M = iMouse.xyz/iResolution.xyz;
    float T = iTime+M.x*2.;
    
    #ifdef HAS_HEART
    T = mod(iTime, 102.);
    T = mix(T, M.x*102., M.z>0.?1.:0.);
    #endif
    
    
    float t = T*.2;
    
    float rainAmount = iMouse.z>0. ? M.y : sin(T*.05)*.3+.7;
    
    float maxBlur = mix(3., 6., rainAmount);
    float minBlur = 2.;
    
    float story = 0.;
    float heart = 0.;
    
    #ifdef HAS_HEART
    story = S(0., 70., T);
    
    t = min(1., T/70.);                     // remap drop time so it goes slower when it freezes
    t = 1.-t;
    t = (1.-t*t)*70.;
    
    float zoom= mix(.3, 1.2, story);        // slowly zoom out
    uv *=zoom;
    minBlur = 4.+S(.5, 1., story)*3.;       // more opaque glass towards the end
    maxBlur = 6.+S(.5, 1., story)*1.5;
    
    vec2 hv = uv-vec2(.0, -.1);             // build heart
    hv.x *= .5;
    float s = S(110., 70., T);              // heart gets smaller and fades towards the end
    hv.y-=sqrt(abs(hv.x))*.5*s;
    heart = length(hv);
    heart = S(.4*s, .2*s, heart)*s;
    rainAmount = heart;                     // the rain is where the heart is
    
    maxBlur-=heart;                         // inside the heart slighly less foggy
    uv *= 1.5;                              // zoom out a bit more
    t *= .25;
    #else
    float zoom = -cos(T*.2);
    uv *= .7+zoom*.3;
    #endif
    UV = (UV-.5)*(.9+zoom*.1)+.5;
    
    float staticDrops = S(-.5, 1., rainAmount)*2.;
    float layer1 = S(.25, .75, rainAmount);
    float layer2 = S(.0, .5, rainAmount);
    
    
    vec2 c = Drops(uv, t, staticDrops, layer1, layer2);
   #ifdef CHEAP_NORMALS
        vec2 n = vec2(dFdx(c.x), dFdy(c.x));// cheap normals (3x cheaper, but 2 times shittier ;))
    #else
        vec2 e = vec2(.001, 0.);
        float cx = Drops(uv+e, t, staticDrops, layer1, layer2).x;
        float cy = Drops(uv+e.yx, t, staticDrops, layer1, layer2).x;
        vec2 n = vec2(cx-c.x, cy-c.x);      // expensive normals
    #endif
    
    
    #ifdef HAS_HEART
    n *= 1.-S(60., 85., T);
    c.y *= 1.-S(80., 100., T)*.8;
    #endif
    
    float focus = mix(maxBlur-c.y, minBlur, S(.1, .2, c.x));
    vec3 col = textureLod(iChannel0, UV+n, focus).rgb;
    
    
    #ifdef USE_POST_PROCESSING
    t = (T+3.)*.5;                                      // make time sync with first lightnoing
    float colFade = sin(t*.2)*.5+.5+story;
    col *= mix(vec3(1.), vec3(.8, .9, 1.3), colFade);   // subtle color shift
    float fade = S(0., 10., T);                         // fade in at the start
    float lightning = sin(t*sin(t*10.));                // lighting flicker
    lightning *= pow(max(0., sin(t+sin(t))), 10.);      // lightning flash
    col *= 1.+lightning*fade*mix(1., .1, story*story);  // composite lightning
    col *= 1.-dot(UV-=.5, UV);                          // vignette
                                                
    #ifdef HAS_HEART
        col = mix(pow(col, vec3(1.2)), col, heart);
        fade *= S(102., 97., T);
    #endif
    
    col *= fade;                                        // composite start and end fade
    #endif
    
    //col = vec3(heart);
    fragColor = vec4(col, 1.);
}

改寫后結(jié)果如下:

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

Shader "Custom/rainWindowTest"
{
    Properties
    {
        _BackTex ("BackTex", 2D) = "white" {}
        _Mouse("Mouse", Vector) = (0.5,0.5,0.5,0.5)
        _iTime("Time", Float) = 20.0
    }
    SubShader
    {
        Pass 
        {
            cull off

            Tags { "RenderType"="Opaque" }

            CGPROGRAM

            #pragma target 3.0

            #pragma vertex vert
            #pragma fragment mainImage

            #include "UnityCG.cginc"

            #define vec2 float2
            #define vec3 float3
            #define vec4 float4
            #define mat2 float2x2
            #define mat3 float3x3
            #define mat4 float4x4
            #define iGlobalTime _Time.y
            #define mod fmod
            #define mix lerp
            #define fract frac
            #define texture2D tex2D
            #define iResolution _ScreenParams
            // #define iResolution float4(800,450,1+(1/800),1+(1/450))
            #define gl_FragCoord ((_iParam.scrPos.xy/_iParam.scrPos.w) * _ScreenParams.xy)

            #define PI2 6.28318530718
            #define pi 3.14159265358979
            #define halfpi (pi * 0.5)
            #define oneoverpi (1.0 / pi)

            #define S(a, b, t) smoothstep(a, b, t)
            //#define CHEAP_NORMALS
            // #define HAS_HEART
            #define USE_POST_PROCESSING



            // #define iMouse _Mouse
            #define iMouse float4(_Mouse.x,_Mouse.y*_ScreenParams.y/450,_Mouse.z,_Mouse.w)
            float4 _Mouse;
            // #define iTime _iTime
            #define iTime _Time.y
            float _iTime;
            // #define iChannel0 _MainTex
            Texture2D _MainTex;
            float4 _MainTex_ST;  // _MainTex_ST.xy 縮放量,_MainTex_ST.zw 偏移值
            #define iChannel0 _BackTex
            Texture2D _BackTex;
            // float4 _BackTex_ST;

            SamplerState sampler_MainTex; // 對紋理進(jìn)行采樣
            SamplerState sampler_BackTex; // 對紋理進(jìn)行采樣

            struct v2f{
                float4 position : SV_POSITION;
            };

            v2f vert(float4 v:POSITION) : SV_POSITION {
                v2f o;
                o.position = UnityObjectToClipPos (v);
                return o;
            }

            vec3 N13(float p) {
                //  from DAVE HOSKINS
                vec3 p3 = fract(vec3(p,p,p) * vec3(.1031,.11369,.13787));
                p3 += dot(p3, p3.yzx + 19.19);
                return fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
            }

            vec4 N14(float t) {
                return fract(sin(t*vec4(123., 1024., 1456., 264.))*vec4(6547., 345., 8799., 1564.));
            }
            float N(float t) {
                return fract(sin(t*12345.564)*7658.76);
            }

            float Saw(float b, float t) {
                return S(0., b, t)*S(1., b, t);
            }


            vec2 DropLayer2(vec2 uv, float t) {
                vec2 UV = uv;
                
                uv.y += t*0.75;
                vec2 a = vec2(6., 1.);
                vec2 grid = a*2.;
                vec2 id = floor(uv*grid);
                
                float colShift = N(id.x); 
                uv.y += colShift;
                
                id = floor(uv*grid);
                vec3 n = N13(id.x*35.2+id.y*2376.1);
                vec2 st = fract(uv*grid)-vec2(.5, 0);
                
                float x = n.x-.5;
                
                float y = UV.y*20.;
                float wiggle = sin(y+sin(y));
                x += wiggle*(.5-abs(x))*(n.z-.5);
                x *= .7;
                float ti = fract(t+n.z);
                y = (Saw(.85, ti)-.5)*.9+.5;
                vec2 p = vec2(x, y);
                
                float d = length((st-p)*a.yx);
                
                float mainDrop = S(.4, .0, d);
                
                float r = sqrt(S(1., y, st.y));
                float cd = abs(st.x-x);
                float trail = S(.23*r, .15*r*r, cd);
                float trailFront = S(-.02, .02, st.y-y);
                trail *= trailFront*r*r;
                
                y = UV.y;
                float trail2 = S(.2*r, .0, cd);
                float droplets = max(0., (sin(y*(1.-y)*120.)-st.y))*trail2*trailFront*n.z;
                y = fract(y*10.)+(st.y-.5);
                float dd = length(st-vec2(x, y));
                droplets = S(.3, 0., dd);
                float m = mainDrop+droplets*r*trailFront;
                
                //m += st.x>a.y*.45 || st.y>a.x*.165 ? 1.2 : 0.;
                return vec2(m, trail);
            }

            float StaticDrops(vec2 uv, float t) {
                uv *= 40.;
                
                vec2 id = floor(uv);
                uv = fract(uv)-.5;
                vec3 n = N13(id.x*107.45+id.y*3543.654);
                vec2 p = (n.xy-.5)*.7;
                float d = length(uv-p);
                
                float fade = Saw(.025, fract(t+n.z));
                float c = S(.3, 0., d)*fract(n.z*10.)*fade;
                return c;
            }

            vec2 Drops(vec2 uv, float t, float l0, float l1, float l2) {
                float s = StaticDrops(uv, t)*l0; 
                vec2 m1 = DropLayer2(uv, t)*l1;
                vec2 m2 = DropLayer2(uv*1.85, t)*l2;
                
                float c = s+m1.x+m2.x;
                c = S(.3, 1., c);
                
                return vec2(c, max(m1.y*l0, m2.y*l1));
            }

            vec4 mainImage(v2f i): SV_Target
            {
                vec2 fragCoord = i.position;
                vec2 uv = (fragCoord.xy-.5*iResolution.xy) / iResolution.y;
                vec2 UV = fragCoord.xy/iResolution.xy;
                vec3 M = iMouse.xyz/iResolution.xyz;
                float T = iTime+M.x*2.;
                
                #ifdef HAS_HEART
                    T = mod(iTime, 102.);
                    T = mix(T, M.x*102., M.z>0.?1.:0.);
                #endif
                
                
                float t = T*.2;
                
                float rainAmount = iMouse.z>0. ? M.y : sin(T*.05)*.3+.7;
                
                float maxBlur = mix(3., 6., rainAmount);
                float minBlur = 2.;
                
                float story = 0.;
                float heart = 0.;
                
                #ifdef HAS_HEART
                    story = S(0., 70., T);
                    
                    t = min(1., T/70.);                     // remap drop time so it goes slower when it freezes
                    t = 1.-t;
                    t = (1.-t*t)*70.;
                    
                    float zoom= mix(.3, 1.2, story);        // slowly zoom out
                    uv *=zoom;
                    minBlur = 4.+S(.5, 1., story)*3.;       // more opaque glass towards the end
                    maxBlur = 6.+S(.5, 1., story)*1.5;
                    
                    vec2 hv = uv-vec2(.0, -.1);             // build heart
                    hv.x *= .5;
                    float s = S(110., 70., T);              // heart gets smaller and fades towards the end
                    hv.y-=sqrt(abs(hv.x))*.5*s;
                    heart = length(hv);
                    heart = S(.4*s, .2*s, heart)*s;
                    rainAmount = heart;                     // the rain is where the heart is
                    
                    maxBlur-=heart;                         // inside the heart slighly less foggy
                    uv *= 1.5;                              // zoom out a bit more
                    t *= .25;
                #else
                    float zoom = -cos(T*.2);
                    // uv *= .7+zoom*.3;  // 不縮放鏡頭
                #endif
                UV = (UV-.5)*(.9)+.5;
                
                float staticDrops = S(-.5, 1., rainAmount)*2.;
                float layer1 = S(.25, .75, rainAmount);
                float layer2 = S(.0, .5, rainAmount);
                
                
                vec2 c = Drops(uv, t, staticDrops, layer1, layer2);
                #ifdef CHEAP_NORMALS
                    vec2 n = vec2(dFdx(c.x), dFdy(c.x));// cheap normals (3x cheaper, but 2 times shittier ;))
                #else
                    vec2 e = vec2(.001, 0.);
                    float cx = Drops(uv+e, t, staticDrops, layer1, layer2).x;
                    float cy = Drops(uv+e.yx, t, staticDrops, layer1, layer2).x;
                    vec2 n = vec2(cx-c.x, cy-c.x);      // expensive normals
                #endif
                
                
                #ifdef HAS_HEART
                    n *= 1.-S(60., 85., T);
                    c.y *= 1.-S(80., 100., T)*.8;
                #endif
                
                float focus = mix(maxBlur-c.y, minBlur, S(.1, .2, c.x));
                // vec3 col = tex2Dlod(iChannel0, UV+n, focus).rgb;
                vec3 col = _MainTex.SampleLevel(sampler_MainTex, UV+n, focus).rgb;
                
                
                #ifdef USE_POST_PROCESSING
                    t = (T+3.)*.5;                                      // make time sync with first lightnoing
                    float colFade = sin(t*.2)*.5+.5+story;
                    col *= mix(vec3(1.,1.,1.), vec3(.8, .9, 1.3), colFade); // subtle color shift
                    float fade = S(0., 10., T);                         // fade in at the start
                    float lightning = sin(t*sin(t*10.));                // lighting flicker
                    lightning *= pow(max(0., sin(t+sin(t))), 10.);      // lightning flash
                    col *= 1.+lightning*fade*mix(1., .1, story*story);  // composite lightning
                    col *= 1.-dot(UV-=.5, UV);                          // vignette
                    
                    #ifdef HAS_HEART
                        col = mix(pow(col, vec3(1.2,1.2,1.2)), col, heart);
                        fade *= S(102., 97., T);
                    #endif
                    
                    col *= fade;                                        // composite start and end fade
                #endif

                UV+=float2(0.5,0.5);

                col=_BackTex.SampleLevel(sampler_BackTex, UV+n, focus).rgb;
                
                //col = vec3(heart);
                vec4 fragColor = vec4(col, 1.);

                return fragColor;
            }
            
            ENDCG
        }
    }
    FallBack "Diffuse"
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末睹栖,一起剝皮案震驚了整個(gè)濱河市硫惕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌野来,老刑警劉巖恼除,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異曼氛,居然都是意外死亡豁辉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門舀患,熙熙樓的掌柜王于貴愁眉苦臉地迎上來徽级,“玉大人,你說我怎么就攤上這事聊浅〔颓溃” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵低匙,是天一觀的道長旷痕。 經(jīng)常有香客問我,道長顽冶,這世上最難降的妖魔是什么欺抗? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮强重,結(jié)果婚禮上绞呈,老公的妹妹穿的比我還像新娘。我一直安慰自己间景,他們只是感情好报强,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拱燃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪力惯。 梳的紋絲不亂的頭發(fā)上碗誉,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機(jī)與錄音父晶,去河邊找鬼哮缺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛甲喝,可吹牛的內(nèi)容都是我干的尝苇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼糠溜!你這毒婦竟也來了淳玩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤非竿,失蹤者是張志新(化名)和其女友劉穎蜕着,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體红柱,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡承匣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锤悄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片韧骗。...
    茶點(diǎn)故事閱讀 39,688評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖零聚,靈堂內(nèi)的尸體忽然破棺而出袍暴,到底是詐尸還是另有隱情,我是刑警寧澤握牧,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布容诬,位于F島的核電站,受9級特大地震影響沿腰,放射性物質(zhì)發(fā)生泄漏览徒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一颂龙、第九天 我趴在偏房一處隱蔽的房頂上張望习蓬。 院中可真熱鬧,春花似錦措嵌、人聲如沸躲叼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枫慷。三九已至,卻和暖如春浪规,著一層夾襖步出監(jiān)牢的瞬間或听,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工笋婿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留誉裆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓缸濒,卻偏偏與公主長得像足丢,于是被迫代替她去往敵國和親粱腻。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容