Bagaimana saya bisa membuat tetesan hujan alami di layar?

11

Saya mencoba membuat efek hujan turun dengan metaballs dan menelusuri di layar. Saya menemukan petunjuk di shadertoy tapi saya tidak mengerti bagaimana penerapannya:

https://www.shadertoy.com/view/ltffzl

sayangnya ia memiliki banyak perhitungan matematika dan saya tidak dapat menggunakannya dalam kesatuan karena menghasilkan lag. Jelas saya harus menggunakan tekstur tetapi bagaimana saya dapat memiliki efek jejak ?!

masukkan deskripsi gambar di sini

ide saya menggunakan penyaji tekstur dan jejak untuk dijatuhkan tetapi bagaimana saya dapat memiliki efek metaballs? masukkan deskripsi gambar di sini


Memperbarui

Saya bisa Menerapkan Metaballs oleh Artikel Ini

https://github.com/smkplus/RainFX/tree/master

tapi aku belum punya ide tentang jejak

Sayy Morteza Kamali
sumber

Jawaban:

11

Saya pikir Anda harus berpikir tentang efeknya sebagai "menghitung peta di mana air" + "menghasilkan vektor normal dari peta itu dan menggunakannya untuk mengimbangi pencarian tekstur latar belakang".

Memecah apa yang contoh shadertoy Anda lakukan, itu hanya menghitung "jejak" untuk menunjukkan di mana defogging terjadi:

masukkan deskripsi gambar di sini

Menghitung normal dari tetesan hujan melingkar,

masukkan deskripsi gambar di sini

dan menggunakan peta normal itu untuk mengimbangi pencarian tekstur ke pembiasan palsu.

Jika Anda ingin jalur dilakukan melalui post-processing dalam shader, Anda harus membuat bentuk "trail" di shader menggunakan beberapa aljabar. Misalnya, dalam fungsi berikut, saya telah overlay "jalur goyah" dan lancip di kepala dan ekor untuk mendapatkan

float trailDrop(vec2 uv, vec2 id, float t) { 
    // wobbly path
    float wobble = 0.5 + 0.5 
        * cos(120.0 * uv.y) 
        * sin(50.0 * uv.y);
    float v = 1.0 - 10.0 * abs(uv.x - 0.5 + 0.2 * wobble);
    // head
    v *= clamp(30.0 * uv.y, 0.0, 1.0);
    v *= clamp( uv.y + 7.0 * t - 0.6, 0.0, 1.0);
    // tail
    v *= clamp(1.0 - uv.y - pow(t, 2.0), 0.0, 1.0);
    return clamp(v * 10.0, 0.0, 1.0);
}

Berikut ini adalah POC kasar di shadertoy - https://www.shadertoy.com/view/XlBfz1 yang mendemonstrasikan pembuatan satu set jalur hujan. Itu terlihat kasar pada resolusi kecil karena resolusi turunan tetapi harus terlihat lebih baik jika Anda fullscreen

Sunting: Menambahkan contoh dengan tetesan hujan yang dihamparkan

masukkan deskripsi gambar di sini

Ditinggalkan sebagai latihan untuk pembaca:

1) Tambahkan tetes bulat kecil. untuk inspirasi, lihat StaticDropsfungsi dalam contoh shadertoy asli Anda.

2) Tambahkan dalam perhitungan normal berkualitas tinggi. Seperti yang #define CHEAP_NORMALStersirat dalam opsi contoh shadertoy asli Anda, dFdx bawaan adalah pendekatan kesetiaan yang rendah dan Anda bisa mendapatkan hasil yang lebih baik dengan secara manual menghitung turunannya (dengan biaya menghitung fungsi 3 kali).

3) Mengacak jarak antar kolom. Anda dapat memperluas kolom dan kemudian memodifikasi uv.x - 0.5 + 0.2 * wobblebit untuk menambahkan offset acak pada sumbu x. Anda mungkin juga ingin mengambil satu halaman dari contoh aslinya sekali lagi dan melapisi beberapa lapis aliran ukuran yang berbeda satu sama lain untuk mendapatkan tampilan yang kurang seragam.

Jimmy
sumber
@DMGregory Tercatat menghapus komentar metaball
Jimmy
Jejak itu sendiri dapat dilakukan melalui buffer, dengan memudar (mengembalikan oldValue * .95 + newdiskposition). Biasanya orang menggunakan suara Perlin untuk memperbaharui garis lurus.
Seyed Morteza Kamali
sesuatu seperti ini shadertoy.com/view/4dy3zR Saya mencoba membuat jejak berisik tapi saya tidak bisa
Seyed Morteza Kamali
7

Anda dapat membuat efek ini dengan mengikuti langkah-langkah di bawah ini:

Partikel

Partikel

RenderTextuer

Anda dapat menyimpan hasilnya dengan menggunakan RenderTexture. ini adalah contoh multipass di shadertoy:

https://www.shadertoy.com/view/ltccRl

iñigo quilez: Shadertoy menggunakan beberapa operan, satu per "Buffer". Seperti namanya, ini melewati menyimpan hasil dalam buffer. Buffer hanyalah tekstur. Persatuan akan membiarkan Anda membuat tekstur juga.

Saya membuat kamera untuk Rendering partikel ke RenderTexture:

kapak

Tekstur Render

GrabPassing

Anda dapat memperoleh pass untuk menerapkan Distortion

Saya jelaskan di posting ini:

Bagaimana saya bisa meniru efek partikel distorsi Quantum Break?

Mengaburkan

dengan menggunakan alpha dalam warna lebih dari Lifetime kami memiliki blur sederhana

waktu lembur

gradien

untuk mendapatkan hasil yang lebih baik lebih baik menggunakan blur sederhana, tetapi bagaimana kita mencapai blur?

Matriks konvolusi

Dalam pemrosesan gambar, kernel, matriks konvolusi, atau mask adalah matriks kecil. Ini digunakan untuk pengaburan, penajaman, embossing, deteksi tepi, dan banyak lagi. Ini dilakukan dengan melakukan konvolusi antara kernel dan gambar.

untuk lebih jelasnya, silakan ikuti tautan ini

Inti

 Shader "Smkgames/Convolution"
    {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
            [Enum(kerEdgeDetectionA,1,kerEdgeDetectionB,2,kerEdgeDetectionC,3,kerSharpen,4,kerBoxBlur,5)]
            _Kernel("Kernel", Float) = 1
        }
        SubShader
        {
            // No culling or depth
            Cull Off ZWrite Off ZTest Always

            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;
                float4 _MainTex_TexelSize;

                float3x3 GetData(int channel, sampler2D tex, float2 uv, float4 size)
                {
                    float3x3 mat;
                    for (int y=-1; y<2; y++)
                    {  
                        for(int x=-1; x<2; x++)
                        {      
                            mat[x+1][y+1]=tex2D(tex, uv + float2(x*size.x, y*size.y))[channel];
                        }              
                    }
                    return mat;
                }
                float3x3 GetMean(float3x3 matr, float3x3 matg, float3x3 matb)
                {
                    float3x3 mat;
                    for (int y=0; y<3; y++)
                    {  
                        for(int x=0; x<3; x++)
                        {
                            mat[x][y] = (matr[x][y] + matg[x][y] + matb[x][y]) / 3.0;
                        }
                    }
                    return mat;
                }

                float Convolve(float3x3 kernel, float3x3 pixels, float denom, float offset)
                {
                    float res = 0.0;
                    for (int y=0; y<3; y++)
                    {  
                        for(int x=0; x<3; x++)
                        {
                            res += kernel[2-x][2-y]*pixels[x][y];
                        }
                    }

                    return  res;
                }

                float _Kernel;

                fixed4 frag (v2f i) : SV_Target
                {


                    float3x3 kerEdgeDetectionA = float3x3 (    0.0,  0,  -1.0,
                                                        1.0,  0,  -1.0,
                                                        0.0,  1.0,  0.0);

                   float3x3 kerEdgeDetectionB = float3x3 (0.0,  1.0,  0.0,
                                                 1.0, -4.0,  1.0,
                                                 0.0,  1.0, 0.0);

                   float3x3 kerEdgeDetectionC = float3x3 (-1.0, -1.0, -1.0,
                                                    -1.0,  8.0, -1.0,
                                                    -1.0, -1.0, -1.0);

                   float3x3 kerSharpen = float3x3 (0.0, -1.0, 0.0,
                                                    -1.0, 5.0, -1.0,
                                                    0.0, -1.0, 0.0);



                    float3x3 kerBoxBlur = (1.0/9.0)*float3x3 (    1.0,  1.0,  1.0,
                                                        1.0,  1.0,  1.0,
                                                        1.0,  1.0,  1.0);




                    float3x3 kernelSelection;
                if(_Kernel == 1){
                kernelSelection = kerEdgeDetectionA;
                }else if(_Kernel == 2){
                kernelSelection = kerEdgeDetectionB;    
                }else if(_Kernel == 3){
                kernelSelection = kerEdgeDetectionC;
                }else if(_Kernel == 4){
                kernelSelection = kerSharpen;   
                }else if(_Kernel == 5){
                kernelSelection = kerBoxBlur;
                }

                float3x3 matr = GetData(0, _MainTex, i.uv, _MainTex_TexelSize);
                float3x3 matg = GetData(1, _MainTex, i.uv, _MainTex_TexelSize);
                float3x3 matb = GetData(2, _MainTex, i.uv, _MainTex_TexelSize);
                float3x3 mata = GetMean(matr, matg, matb);


                // kernel
               float4 gl_FragColor = float4(Convolve(kernelSelection,matr,1.0,0.0),
                                            Convolve(kernelSelection,matg,1.0,0.0),
                                            Convolve(kernelSelection,matb,1.0,0.0),
                                            1.0);

                return gl_FragColor;
            }
            ENDCG
        }
    }
}

Boxblur

Blur kotak (juga dikenal sebagai filter linear kotak) adalah filter linear domain spasial di mana setiap piksel dalam gambar yang dihasilkan memiliki nilai yang sama dengan nilai rata-rata piksel tetangganya dalam gambar input. Ini adalah bentuk filter low-pass ("blurring"). Kotak 3 dengan 3 blur dapat ditulis sebagai matriks

https://en.wikipedia.org/wiki/Box_blur

1_oos3y1ztoewgsubpdnbvea

Shader "Smkgames/Simple Box Blur"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Blend SrcAlpha OneMinusSrcAlpha


        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;
            float4 _MainTex_TexelSize;

            float4 box(sampler2D tex, float2 uv, float4 size)
            {
                float4 c = tex2D(tex, uv + float2(-size.x, size.y)) + tex2D(tex, uv + float2(0, size.y)) + tex2D(tex, uv + float2(size.x, size.y)) +
                            tex2D(tex, uv + float2(-size.x, 0)) + tex2D(tex, uv + float2(0, 0)) + tex2D(tex, uv + float2(size.x, 0)) +
                            tex2D(tex, uv + float2(-size.x, -size.y)) + tex2D(tex, uv + float2(0, -size.y)) + tex2D(tex, uv + float2(size.x, -size.y));

                return c / 9;
            }

            float4 frag (v2f i) : SV_Target
            {
                float4 col = box(_MainTex, i.uv, _MainTex_TexelSize);
                return col;
            }
            ENDCG
        }
    }
}

blurbox

Pengulangan

Anda dapat menggunakan Rendertexture untuk menyimpan frame sebelumnya. dengan mengulangi ini Anda mencapai blur.

0fe28c6167db2132d4bb8677fc1b2050 - leandro-erlich-argentina

Normal

float4 distortion = tex2D(_MainTex,i.uv);
float3 distortionNormal = UnpackNormal(distortion);

record_2019_03_03_21_35_45_417

Kesimpulan

Shader terakhir:

Shader "Smkgames/BrokenGlass3D"
{
    Properties{
        _MainTex("MainTex",2D) = "white"{}
        _NormalIntensity("NormalIntensity",Float) = 1
        _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 uv : TEXCOORD0;
                float2 grabPos : TEXCOORD1;
                float3 normal :NORMAL;
            };

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

            };
            sampler2D _MainTex;
            float _Intensity,_Alpha;

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

            sampler2D _GrabTexture;
            float _NormalIntensity;

            fixed4 frag (v2f i) : SV_Target
            {
                float4 distortion = tex2D(_MainTex,i.uv);
                float3 distortionNormal = UnpackNormal(distortion);
                distortionNormal.xy *= _NormalIntensity;
                normalize(distortionNormal);
                fixed4 col = tex2Dproj(_GrabTexture, i.grabPos+float4(distortionNormal.rgb,0));
                return col;
            }
            ENDCG
        }
    }
}

tanpa menggunakan warna alfa selama Lifetime:

record_2019_03_03_21_48_36_273

dengan menggunakan alpha dalam warna sepanjang Lifetime:

record_2019_03_03_21_48_19_786

Sumber tersedia:

https://github.com/smkplus/RainDrop

Masih ada lagi!

Anda juga bisa membuat Riak

record_2019_03_04_22_10_25_457

Tautan yang Berguna

https://80.lv/articles/breakdown-animated-raindrop-material-in-ue4/

https://seblagarde.wordpress.com/2013/01/03/water-drop-2b-dynamic-rain-and-its-effects/

Sayy Morteza Kamali
sumber
1

Sebenarnya ada pertanyaan tentang ini tahun lalu, tetapi itu tidak berkaitan dengan Unity sama sekali (sayangnya). Jika Anda melihat slide 57 dari presentasi yang ditautkan, mereka menyebutkan pendekatan berbasis grid.

Ada pertanyaan yang agak terkait pada Fisika SE yang mungkin menarik bagi Anda. Tautan ke droplet.pdf dalam pertanyaan yang ditautkan rusak, tetapi masih ada di Wayback Machine. Ini masuk ke beberapa matematika air yang mengalir dari beberapa jenis permukaan. Tetesan lebih suka melakukan perjalanan di jalur yang sebelumnya digunakan oleh hujan sebelumnya, misalnya (lihat hal926).

Anda mungkin bisa hanya memodelkan kepala dan ekor dari setiap "tetesan air hujan" dan membiarkannya zig dan zag sedikit. Ketika dua tetes hujan yang memanjang bertabrakan, saya kira Anda bisa membuatnya menjadi hujan yang lebih besar dan bergerak lebih cepat. Volume air tetap sama. Itu hanya digerakkan dan dibentuk oleh kekuatan gravitasi, adhesi pada kaca, dan kohesi.

David A
sumber