Come posso replicare l'effetto particella di distorsione di Quantum Break?


68

Quantum Break ha questo fantastico effetto particellare, è un effetto di distorsione come il vetro rotto. Voglio sapere come posso replicare questo effetto? Puoi vederlo qui sotto e un video completo è disponibile su YouTube :

record_2018_02_05_16_34_26_307

record_2018_02_01_22_27_44_971


4
"Questa domanda non ha ricevuto abbastanza attenzione." ?
Vaillancourt

@AlexandreVaillancourt Ho appena aggiunto questa domanda per più punti di vista e attirando l'attenzione perché penso che sia utile.Non posso trovare un motivo migliore per motivi di generosità Se c'è un problema cambierò il mio reason.thanks
Seyed Morteza Kamali

2
Lo scopo dei doni non è in realtà solo quello di "appuntare" le domande; la tua logica dichiarata è alquanto disonesta. Lo scopo dei doni è di attirare l'attenzione su domande che richiedono risposte o di premiare le risposte esistenti, cosa che la tua non sta facendo. Esistono già meccanismi (l'HNQ, che molti dei tuoi post colpiscono) per premiare gli argomenti che la community ritiene utili e interessanti.
Josh

2
Non essere avido. Hai già abbastanza punti di vista e voti
Casanova,

@JoshPetrie hai ragione, mi dispiace, non ripeto questo stato. Mi vergogno, quindi puoi rimuovere la mia domanda dalle funzionalità senza restituire reputazione. Lo faccio solo perché pensavo che forse avrei aiutato gli altri.
Seyed Morteza Kamali

Risposte:


101

Particella piramidale

La forma della particella predefinita di Unity è quadrupla. per prima cosa devi cambiare questa forma in piramide usando l'oggetto piramide o trasforma i quad in piramidi con uno shader di geometria .

Immagine

awd

Rifrazione

Per creare un effetto vetro rotto ( Rifrazione ) puoi usare GrabPass { "TextureName" }ciò per catturare i contenuti dello schermo in una trama.

GrabPass è un tipo di passaggio speciale: prende il contenuto dello schermo in cui l'oggetto sta per essere disegnato in una trama. Questa trama può essere utilizzata nei passaggi successivi per eseguire effetti avanzati basati sull'immagine.

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

Usando normali a maglie

Procediamo con uno shader che visualizza le normali delle mesh nello spazio mondiale. L'ho usato perché volevo apparire tratteggiata tridimensionale.

normali

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

Distorsione di calore

Per creare la distorsione del calore è possibile utilizzare la mappa del flusso

Una mappa di flusso è una trama che memorizza le informazioni direzionali 2D in una trama. Il colore del pixel determina la direzione in cui sta usando la trama delle coordinate uv come base. Maggiore è il colore, maggiore è la velocità proporzionale. Esempio verde indica che va su-sinistra, il centro è neutro e il rosso scenderà a destra. È una tecnica utile per materiali liquidi come l'acqua e un'alternativa utile solo a un nodo panner.

flow_map

heatdistortion

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

un altro esempio usando normale:

ritagliare

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

  }
}

Divisione RGB

Se presti attenzione al tuo primo GIF puoi vedere una piccola divisione 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
        }
    }
}

link utili

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

Fonte su Github


47
Sono curioso, hai pensato di creare un blog per sviluppatori per condividere tecniche come queste? Mi abbonerei a una risorsa del genere. :)
DMGregory

7
Secondo il suggerimento! Controllo quotidianamente il sito Web per le tue risposte, in quanto il tuo approccio è sempre creativo, dettagliato e tuttavia semplice da capire. Anche gli esempi che fornisci sono di grande aiuto.
altskop,

4
Per quanto riguarda il tuo effetto split RGB: indosso gli occhiali e provo sempre un effetto simile naturale causato dall'aberrazione cromatica, che varia a seconda della distanza da occhio a schermo. Allo stesso modo in cui gli occhiali 3D causano una discrepanza tra i vari segnali di quanto sia lontano qualcosa, il tuo effetto interferisce con un dettaglio che il mio cervello interpreta per stimare quanto lo schermo è lontano dal mio occhio. È estremamente spiacevole, fino al punto di nausea. Si prega di renderlo facoltativo se si sceglie di usarlo!
Aoeuid,

1
@Aoeuid FWIW, è intensamente spiacevole anche per le persone senza visione correttiva :)
Max

@DMGregory sì: DI non ha un sito quindi condivido le mie tecniche qui Ho bisogno del tuo supporto per lo sviluppo di blog o siti.Se mi supporti, sarò utile https://www.patreon.com/SeyedMortezaKamaly
Seyed Morteza Kamali
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.