Jak mogę odtworzyć efekt cząsteczki zniekształcającej Quantum Break?


68

Quantum Break ma ten fantastyczny efekt cząsteczkowy, jest to efekt zniekształceń jak rozbite szkło. Chcę wiedzieć, jak mogę odtworzyć ten efekt? Możesz to zobaczyć poniżej, a pełny film jest dostępny na YouTube :

record_2018_02_05_16_34_26_307

record_2018_02_01_22_27_44_971


4
„To pytanie nie otrzymało wystarczającej uwagi”. ?
Alexandre Vaillancourt

@AlexandreVaillancourt Po prostu przypinam to pytanie, aby uzyskać więcej wyświetleń i zwracam uwagę, ponieważ uważam, że jest to użyteczne. Nie mogłem znaleźć lepszego powodu z powodów związanych z nagrodą Jeśli jest jakiś problem, zmienię swój powód. Dzięki
Seyed Morteza Kamali

2
Jednak celem nagród nie jest po prostu „przypinanie” pytań; twoje uzasadnienie jest nieco nieszczere. Celem nagród jest zwrócenie uwagi na pytania, które wymagają odpowiedzi lub nagrodzenie istniejących odpowiedzi, czego twoje nie robią. Istnieją już mechanizmy (HNQ, do których trafiło wiele Twoich postów), aby nagradzać tematy, które zdaniem społeczności są przydatne i interesujące.
Josh

2
Nie bądź chciwy. Masz już wystarczającą liczbę wyświetleń i głosów
Casanova

@JoshPetrie masz rację Przepraszam, że nie powtarzam tego stanu. Wstydzę się, że możesz usunąć moje pytanie z funkcji bez przywracania reputacji. Po prostu to robię, ponieważ myślałem, że może pomogę innym.
Seyed Morteza Kamali

Odpowiedzi:


101

Cząstka piramidy

Domyślny kształt cząsteczki Unity to quad. najpierw musisz zmienić ten kształt na piramidę, używając obiektu piramidy lub zamienia quady w piramidy za pomocą modułu cieniującego geometrię .

wizerunek

awd

Refrakcja

Aby uzyskać efekt potłuczonego szkła ( załamanie ), możesz użyć GrabPass { "TextureName" }tego, aby pobrać zawartość ekranu do tekstury.

GrabPass to specjalny typ przejścia - chwyta zawartość ekranu, na którym obiekt ma zostać narysowany w teksturę. Tę teksturę można wykorzystać w kolejnych przejściach, aby uzyskać zaawansowane efekty oparte na obrazie.

https://docs.unity3d.com/Manual/SL-GrabPass.html

record_2018_02_03_23_09_06_370

Shader "Smkgames/GlassRefraction"
{
    Properties{
        _Refraction("Refraction",Float) = 0.05
        _Alpha("Alpha",Range(0,1)) = 1
    }
    SubShader
    {
Tags {"Queue"="Transparent" "RenderType"="Transparent"}

        Blend SrcAlpha OneMinusSrcAlpha

        GrabPass
        {
            "_GrabTexture"
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            sampler2D _MainTex;
            float _Alpha,_Refraction;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.vertex);
                return o;
            }

            sampler2D _GrabTexture;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2Dproj(_GrabTexture, i.grabPos+_Refraction);
                return float4(col.rgb,_Alpha);

            }
            ENDCG
        }
    }
}

Używanie normalnych siatek

Przejdźmy do modułu cieniującego, który wyświetla normalne siatki w przestrzeni świata. Użyłem go, ponieważ chciałem wyglądać na trójwymiarowy złamany kształt.

normalne

record_2018_02_05_18_06_09_41

record_2018_02_03_23_19_06_705

    Shader "Smkgames/BrokenGlass3D"
{
    Properties{
        _MainTex("MainTex",2D) = "white"{}
        _Alpha("Alpha",Float) = 1
    }
    SubShader
    {
Tags {"Queue"="Transparent" "RenderType"="Transparent"}
 Blend SrcAlpha OneMinusSrcAlpha 


        GrabPass
        {
            "_GrabTexture"
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 grabPos : TEXCOORD0;
                float3 normal :NORMAL;
            };

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 vertex : SV_POSITION;
                half3 worldNormal :TEXCOORD1;

            };
            sampler2D _MainTex;
            float _Intensity,_Alpha;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            sampler2D _GrabTexture;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 c = 0;
                c.rgb = i.worldNormal*0.5+0.5;
                float4 distortion = tex2D(_MainTex,i.grabPos)+_Intensity;
                fixed4 col = tex2Dproj(_GrabTexture, i.grabPos+c.r);
                return float4(col.rgb,_Alpha);
            }
            ENDCG
        }
    }
}

Zniekształcenie ciepła

Aby stworzyć zniekształcenie ciepła, możesz użyć mapy przepływu

Mapa przepływu jest teksturą, która przechowuje w teksturze informacje kierunkowe 2d. Kolor piksela określa kierunek, w którym używa tekstury współrzędnych UV jako podstawy. Im więcej kolorów, tym większa proporcjonalna prędkość. Przykładowy zielony nakazuje mu iść w górę-w lewo, środek jest neutralny, a czerwony pójdzie w dół w prawo. Jest to przydatna technika dla materiałów płynnych, takich jak woda, i użyteczna alternatywa dla zwykłego węzła panoramicznego.

flow_map

zniekształcenie cieplne

    Shader "Smkgames/HeatDistortion"
{
    Properties{
        _DistortionMap("DistortionMap",2D) = "white"{}
        _Intensity("Intensity",Float) = 50
        _Mask("Mask",2D) = "white"{}
        _Alpha("Alpha",Range(0,1)) = 1
    }
    SubShader
    {
Tags {"Queue"="Transparent" "RenderType"="Transparent"}

        GrabPass
        {
            "_GrabTexture"
        }

        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            sampler2D _Mask,_DistortionMap;
            float _Alpha,_Refraction;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.vertex);
                return o;
            }

            sampler2D _GrabTexture;
            float _Intensity;

            fixed4 frag (v2f i) : SV_Target
            {
                float mask = tex2D(_Mask,i.grabPos);
                mask = step(mask,0.5);
                //mask = smoothstep(mask,0,0.4);
                float4 distortion = tex2D(_DistortionMap,i.grabPos+_Time.y)+_Intensity;
                fixed4 col = tex2Dproj(_GrabTexture, i.grabPos*distortion);
                return float4(col.rgb,mask*_Alpha);

            }
            ENDCG
        }
    }
}

inny przykład przy użyciu normalnego:

odetnij

normalmap

smoketile_normal 1

Shader "Smkgames/HeatDistortion2" {
Properties {
        _CutOut ("CutOut (A)", 2D) = "black" {}
        _BumpMap ("Normalmap", 2D) = "bump" {}
        _BumpAmt ("Distortion", Float) = 10
}

Category {

    Tags { "Queue"="Transparent"  "IgnoreProjector"="True"  "RenderType"="Opaque" }
    Blend SrcAlpha OneMinusSrcAlpha
    Cull Off 
    Lighting Off 
    ZWrite Off 
    Fog { Mode Off}

    SubShader {
        GrabPass {                          
            "_GrabTexture"
        }
        Pass {

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_particles
#include "UnityCG.cginc"

struct appdata_t {
    float4 vertex : POSITION;
    float2 texcoord: TEXCOORD0;
};

struct v2f {
    float4 vertex : POSITION;
    float4 uvgrab : TEXCOORD0;
    float2 uvbump : TEXCOORD1;
    float2 uvcutout : TEXCOORD2;
};

sampler2D _BumpMap,_CutOut,_GrabTexture;
float _BumpAmt;
float4 _GrabTexture_TexelSize;
float4 _BumpMap_ST,_CutOut_ST;

v2f vert (appdata_t v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*-1) + o.vertex.w) * 0.5;
    o.uvgrab.zw = o.vertex.zw;
    o.uvbump = TRANSFORM_TEX( v.texcoord, _BumpMap );
    o.uvcutout = TRANSFORM_TEX( v.texcoord, _CutOut );
    return o;
}



half4 frag( v2f i ) : COLOR
{
    half2 bump = UnpackNormal(tex2D( _BumpMap, i.uvbump )).rg;
    float2 offset = bump * _BumpAmt * _GrabTexture_TexelSize.xy;
    i.uvgrab.xy = offset * i.uvgrab.z + i.uvgrab.xy;

    half4 col = tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
    fixed4 cut = tex2D(_CutOut, i.uvcutout);
    fixed4 emission = col;
    emission.a = (cut.a);
    return emission;
}
ENDCG
        }
    }

  }
}

Podział RGB

Jeśli zwrócisz uwagę na swój pierwszy gif, zobaczysz niewielki podział RGB.

u_rgb_seperation_ar

Shader "Hidden/RgbSplit"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _NoiseTex1 ("Noise Texture A", 2D) = "white" {}
        _NoiseTex2 ("Noise Texture B", 2D) = "white" {}
    }
    SubShader
    {

        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;
            };

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

            sampler2D _MainTex,_NoiseTex1,_NoiseTex2;
            float3 colorSplit(float2 uv, float2 s)
{
    float3 color;
    color.r = tex2D(_MainTex, uv - s).r;
    color.g = tex2D(_MainTex, uv    ).g;
    color.b = tex2D(_MainTex, uv + s).b;
    return color;
}

float2 interlace(float2 uv, float s)
{
    uv.x += s * (4.0 * frac((uv.y) / 2.0) - 1.0);
    return uv;
}

    fixed4 frag (v2f i) : SV_Target
    {

    float t = _Time.y;

    float s = tex2D(_NoiseTex1, float2(t * 0.2, 0.5)).r;

    i.uv = interlace(i.uv, s * 0.005);
    float r = tex2D(_NoiseTex2, float2(t, 0.0)).x;

    float3 color = colorSplit(i.uv, float2(s * 0.02, 0.0));

    return float4(color, 1.0);

            }
            ENDCG
        }
    }
}

Przydatne linki

https://www.fxguide.com/featured/time-for-destruction-the-tech-of-quantum-break/

Źródło na Github


47
Ciekawe, czy zastanawiałeś się nad utworzeniem bloga programisty, aby udostępniać takie techniki? Zasubskrybowałbym taki zasób. :)
DMGregory

7
Popieram sugestię! Codziennie monitoruję Twoją witrynę pod kątem twoich odpowiedzi, ponieważ twoje podejście jest zawsze kreatywne, szczegółowe, a jednocześnie łatwe do zrozumienia. Podane przykłady również są bardzo pomocne.
altskop

4
Jeśli chodzi o efekt podziału RGB: noszę okulary i zawsze odczuwam naturalny efekt podobny do aberracji chromatycznej, zmieniający się w zależności od odległości od oka do ekranu. W ten sam sposób, w jaki okulary 3D powodują niedopasowanie między różnymi wskazówkami, jak daleko jest coś, twój efekt zakłóca szczegół, który mój mózg interpretuje, aby oszacować odległość ekranu od mojego oka. Jest to wyjątkowo nieprzyjemne, aż do mdłości. Opcjonalnie, jeśli chcesz go użyć!
Aoeuid,

1
@Aoeuid FWIW, jest bardzo nieprzyjemny nawet dla osób bez wizji korekcyjnej :)
Max

@DMGregory tak: DI nie mam witryny, dlatego dzielę się tutaj swoimi technikami. Potrzebuję twojej pomocy przy tworzeniu bloga lub witryny. Jeśli mnie wspierasz, będę pomocny https://www.patreon.com/SeyedMortezaKamaly
Seyed Morteza Kamali
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.