Como replicar o efeito de partícula de distorção do Quantum Break?


68

O Quantum Break tem esse fantástico efeito de partícula, é um efeito de distorção como vidro quebrado. Quero saber como posso replicar esse efeito? Você pode vê-lo abaixo e um vídeo completo está disponível no YouTube :

record_2018_02_05_16_34_26_307

record_2018_02_01_22_27_44_971


4
"Esta questão não recebeu atenção suficiente." ?
Vaillancourt

@AlexandreVaillancourt Eu só fixar esta questão para mais vistas e chamar a atenção porque eu acho que é useful.I não poderia encontrar melhor razão em razões de recompensas Se há um problema eu vou mudar meus reason.thanks
Seyed Morteza Kamali

2
O objetivo das recompensas não é realmente apenas "fixar" perguntas; seu raciocínio declarado é um tanto falso. O objetivo das recompensas é chamar a atenção para perguntas que precisam de respostas ou recompensar as respostas existentes, que a sua não está fazendo. Já existem mecanismos (o HNQ, que muitas de suas postagens acessam) para recompensar tópicos que a comunidade considera úteis e interessantes.
Josh

2
Não seja ganancioso. Você já tem visualizações e votos suficientes
Casanova

@JoshPetrie você está certo Me desculpe, eu não repito esse estado.Eu tenho vergonha de remover minha pergunta dos recursos sem retornar a reputação.Eu faço isso porque pensei que talvez eu ajude outras pessoas.
Seyed Morteza Kamali

Respostas:


101

Partícula da pirâmide

O formato da partícula padrão da unidade é quad. primeiro, você precisa alterar essa forma para pirâmide usando o objeto pirâmide ou transformar quads em pirâmides com um sombreador de geometria .

imagem

awd

Refração

Para criar um efeito de vidro quebrado ( Refração ), você pode usar o GrabPass { "TextureName" }que captura o conteúdo da tela em uma textura.

O GrabPass é um tipo de passe especial - captura o conteúdo da tela onde o objeto está prestes a ser desenhado em uma textura. Essa textura pode ser usada em passagens subsequentes para criar efeitos avançados baseados em imagem.

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 normais de malha

Vamos prosseguir com um sombreador que exibe normais de malha no espaço do mundo. Eu usei porque queria parecer tridimensional.

normais

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

Distorção de calor

Para criar distorção de calor, você pode usar o mapa de fluxo

Um fluxograma é uma textura que armazena 2d informações direcionais em uma textura. A cor do pixel determina em que direção está usando a textura das coordenadas uv como base. Quanto mais cores houver, mais rápida será a velocidade proporcional. O exemplo verde indica que ele vai para a esquerda, o centro é neutro e o vermelho vai para a direita. É uma técnica útil para materiais líquidos, como a água, e uma alternativa útil para apenas um nó panner.

flow_map

calor

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

outro exemplo usando normal:

Cortar fora

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

  }
}

Divisão RGB

Se você prestar atenção ao seu primeiro gif, poderá ver uma pequena divisão 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
        }
    }
}

Links Úteis

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

Fonte no Github


47
Estou curioso, você já pensou em criar um blog de desenvolvedor para compartilhar técnicas como essas? Eu assinaria um recurso como esse. :)
DMGregory

7
Eu segundo a sugestão! Monitoro o site todos os dias em busca de respostas, pois sua abordagem é sempre criativa, detalhada e, no entanto, simples de entender. Os exemplos que você fornece também são de grande ajuda.
Altskop

4
Em relação ao seu efeito de divisão RGB: uso óculos e sempre experimento um efeito semelhante de ocorrência natural causado por aberração cromática, variando com a distância entre os olhos e a tela. Da mesma forma que os óculos 3D causam uma incompatibilidade entre várias pistas de como algo está distante, seu efeito interfere em um detalhe que meu cérebro interpreta para estimar a distância da tela do meu olho. É extremamente desagradável, a ponto de nauseante. Por favor, faça-o opcional se você optar por usá-lo!
Aoeuid 06/02

11
@Aoeuid FWIW, é intensamente desagradável, mesmo por pessoas sem visão corretiva :)
Max

@DMGregory: Sim, eu não tenho um site, então eu compartilho minhas técnicas aqui. Preciso de seu apoio para o desenvolvimento de blog ou site. Se você me apoiar, serei útil https://www.patreon.com/SeyedMortezaKamaly
Seyed Morteza Kamali
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.