¿Cómo puedo replicar el efecto de partícula de distorsión de Quantum Break?

68

Quantum Break tiene este fantástico efecto de partículas, es un efecto de distorsión como el cristal roto. ¿Quiero saber cómo puedo replicar este efecto? Puede verlo a continuación, y un video completo está disponible en YouTube :

record_2018_02_05_16_34_26_307

record_2018_02_01_22_27_44_971

Seyed Morteza Kamali
fuente
44
"Esta pregunta no ha recibido suficiente atención." ?
Vaillancourt
@AlexandreVaillancourt Acabo de anclar esta pregunta para obtener más puntos de vista y llamar la atención porque creo que es útil. No podría encontrar una mejor razón por razones de recompensa. Si hay un problema, cambiaré mi razón
Seyed Morteza Kamali
2
Sin embargo, el propósito de las recompensas no es solo "fijar" preguntas; su justificación declarada es algo falsa. El objetivo de las recompensas es llamar la atención sobre las preguntas que necesitan respuestas o recompensar las respuestas existentes, lo que el suyo no está haciendo. Ya existen mecanismos (el HNQ, que muchas de sus publicaciones golpean) para recompensar los temas que la comunidad considera útiles e interesantes.
Josh
2
No seas codicioso. Ya tienes suficientes vistas y votos
Casanova
@JoshPetrie tienes razón Lo siento, no repito este estado. Me da vergüenza que puedas eliminar mi pregunta de las características sin devolver la reputación. Solo hago esto porque pensé que tal vez ayudaría a otros.
Seyed Morteza Kamali

Respuestas:

101

Partícula Pirámide

La forma de la partícula predeterminada de la unidad es quad. primero debe cambiar esta forma a pirámide usando un objeto piramidal o convierte los quads en pirámides con un sombreador de geometría .

imagen

awd

Refracción

Para crear un efecto de cristal roto ( Refracción ), puede usarlo GrabPass { "TextureName" }para capturar el contenido de la pantalla en una textura.

GrabPass es un tipo de pase especial: toma el contenido de la pantalla donde el objeto está a punto de dibujarse en una textura. Esta textura se puede utilizar en pasadas posteriores para realizar efectos avanzados basados ​​en imágenes.

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

Usar mallas normales

Pasemos a un sombreador que muestre las mallas normales en el espacio mundial. Lo usé porque quería ver la forma rota tridimensional.

normales

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

Distorsión de calor

Para crear distorsión térmica puede usar el mapa de flujo

Un mapa de flujo es una textura que almacena información direccional 2D en una textura. El color del píxel determina en qué dirección está usando la textura de coordenadas uv como base. Cuanto más color haya, más rápida será la velocidad proporcional. El ejemplo verde le dice que vaya arriba a la izquierda, el centro es neutral y el rojo bajará a la derecha. Es una técnica útil para materiales líquidos como el agua, y una alternativa útil a solo un nodo panorámico.

mapa_flujo

distorsión térmica

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

otro ejemplo usando normal:

separar

mapa normal

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

  }
}

División RGB

Si prestas atención a tu primer gif, puedes ver una pequeña división 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
        }
    }
}

Enlaces útiles

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

Fuente en Github

Seyed Morteza Kamali
fuente
47
Tengo curiosidad, ¿has considerado crear un blog de desarrollador para compartir técnicas como estas? Me suscribiría a un recurso como ese. :)
DMGregory
77
¡Secundo la sugerencia! Superviso el sitio web todos los días en busca de sus respuestas, ya que su enfoque siempre es creativo, detallado y sencillo de entender. Los ejemplos que proporciona también son de gran ayuda.
altskop
44
Con respecto a su efecto dividido RGB: uso lentes y siempre experimento un efecto similar natural causado por la aberración cromática, que varía con la distancia del ojo a la pantalla. De la misma manera que las gafas 3D causan un desajuste entre varias señales de cuán lejos está algo, su efecto interfiere con un detalle que mi cerebro interpreta para estimar qué tan lejos está la pantalla de mi ojo. Es extremadamente desagradable, hasta el punto de causar náuseas. ¡Hágalo opcional si elige usarlo!
Aoeuid
1
@Aoeuid FWIW, es intensamente desagradable incluso para personas sin visión correctiva :)
Max
@DMGregory sí: DI no tiene un sitio, así que comparto mis técnicas aquí. Necesito su apoyo para desarrollar un blog o sitio. Si me apoya, seré útil https://www.patreon.com/SeyedMortezaKamaly
Seyed Morteza Kamali