Làm thế nào tôi có thể làm cho giọt mưa tự nhiên trên màn hình?


11

Tôi đang cố gắng để làm cho hiệu ứng đổ mưa với metaballs và đường mòn trên screen.I tìm thấy một đầu mối trong shadertoy nhưng tôi không hiểu làm thế nào thực hiện:

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

Thật không may, nó có nhiều phép tính toán và tôi không thể sử dụng nó trong sự thống nhất vì nó tạo ra độ trễ. Rõ ràng tôi nên sử dụng kết cấu nhưng làm thế nào tôi có thể có hiệu ứng đường mòn?!

nhập mô tả hình ảnh ở đây

ý tưởng của tôi là sử dụng một kết xuất và kết xuất đường mòn để thả nhưng làm thế nào tôi có thể có hiệu ứng siêu dữ liệu? nhập mô tả hình ảnh ở đây


Cập nhật

Tôi có thể triển khai Metaballs theo Điều này

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

nhưng tôi không có ý tưởng về đường mòn

Câu trả lời:


11

Tôi nghĩ bạn nên nghĩ về hiệu ứng như "tính toán bản đồ nơi nước" + "tạo ra một vectơ bình thường từ bản đồ đó và sử dụng nó để bù đắp cho việc tra cứu kết cấu nền".

Phân tích những gì shadertoy ví dụ của bạn làm, nó chỉ tính toán một "dấu vết" để chỉ ra nơi xảy ra sự cố làm mờ:

nhập mô tả hình ảnh ở đây

Tính các chỉ tiêu của những hạt mưa tròn,

nhập mô tả hình ảnh ở đây

và sử dụng bản đồ bình thường đó để bù đắp một tra cứu kết cấu cho khúc xạ giả.

Nếu bạn muốn các đường mòn được thực hiện thông qua xử lý hậu kỳ trong một shader, bạn chỉ cần tạo hình dạng "dấu vết" trong shader bằng một số đại số. Ví dụ, trong chức năng sau đây, tôi đã phủ lên một "con đường chao đảo" và một hình côn ở đầu và đuôi để có được

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

Đây là một POC thô trong shadertoy - https://www.shadertoy.com/view/XlBfz1 thể hiện việc tạo ra một tập hợp các vệt mưa. Nó trông nhiễu hạt ở độ phân giải nhỏ do độ phân giải dẫn xuất nhưng sẽ đẹp hơn nếu bạn toàn màn hình.

Chỉnh sửa: Đã thêm một ví dụ với những hạt mưa phủ

nhập mô tả hình ảnh ở đây

Còn lại như một bài tập cho người đọc:

1) Thêm các giọt tròn nhỏ. để có cảm hứng, hãy nhìn vào StaticDropschức năng trong ví dụ shadertoy ban đầu của bạn.

2) Thêm vào tính toán bình thường chất lượng cao. Như #define CHEAP_NORMALStùy chọn trong ví dụ shadertoy ban đầu của bạn ngụ ý, dFdx dựng sẵn là một xấp xỉ độ chính xác thấp và bạn có thể nhận được kết quả tốt hơn bằng cách tính toán các đạo hàm (với chi phí tính toán hàm 3 lần).

3) Chọn ngẫu nhiên khoảng cách giữa các cột. Bạn có thể mở rộng các cột và sau đó sửa đổi uv.x - 0.5 + 0.2 * wobblebit để thêm phần bù ngẫu nhiên trên trục x. Bạn cũng có thể muốn lấy một trang ra khỏi ví dụ ban đầu một lần nữa và đặt một vài lớp luồng có kích thước khác nhau lên nhau để có được cái nhìn ít đồng nhất hơn.



@DMGregory Lưu ý. xóa bình luận metaball
Jimmy

Bản thân đường mòn có thể được thực hiện thông qua bộ đệm, bằng cách làm mờ dần (trả về oldValue * .95 + newdiskposeition). Thông thường, mọi người sử dụng tiếng ồn Perlin để làm nhiễu đường thẳng.
Seyed Morteza Kamali

một cái gì đó như thế này shadertoy.com/view/4dy3zR Tôi đã cố gắng tạo ra dấu vết ồn ào nhưng tôi không thể
Seyed Morteza Kamali

7

bạn có thể tạo hiệu ứng này bằng cách làm theo các bước dưới đây:

Hạt

Hạt

Kết xuất đồ họa

bạn có thể lưu trữ kết quả bằng cách sử dụng RenderTexture. đây là ví dụ về bội số trong shadertoy:

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

iñigo quilez: Shadertoy sử dụng nhiều đường chuyền, mỗi lần cho một "Bộ đệm". Như tên cho thấy, điều này vượt qua lưu trữ kết quả trong một bộ đệm. Một bộ đệm chỉ là một kết cấu. Unity sẽ cho phép bạn kết xuất với kết cấu quá.

Tôi đã tạo một máy ảnh để kết xuất các hạt thành RenderTexture:

cây rìu

Kết xuất đồ họa

GrabPassing

bạn có thể lấy pass để áp dụng Biến dạng

Tôi đã giải thích nó trong bài viết này:

Làm thế nào tôi có thể tái tạo hiệu ứng hạt biến dạng của Quantum Break?

Mơ hồ

bằng cách sử dụng màu alpha trong suốt cuộc đời, chúng ta có hiệu ứng làm mờ đơn giản

bảng chữ cái

dần dần

để có kết quả tốt hơn, tốt hơn là sử dụng hiệu ứng làm mờ đơn giản, nhưng làm thế nào để chúng ta đạt được hiệu ứng nhòe?

Ma trận kết hợp

Trong xử lý ảnh, hạt nhân, ma trận chập hoặc mặt nạ là một ma trận nhỏ. Nó được sử dụng để làm mờ, làm sắc nét, dập nổi, phát hiện cạnh, và nhiều hơn nữa. Điều này được thực hiện bằng cách thực hiện tích chập giữa kernel và hình ảnh.

để biết thêm chi tiết, xin vui lòng theo liên kết này

Hạt nhân

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

Hộp mờ

Làm mờ hộp (còn được gọi là bộ lọc tuyến tính hộp) là bộ lọc tuyến tính miền không gian trong đó mỗi pixel trong ảnh kết quả có giá trị bằng giá trị trung bình của các pixel lân cận trong ảnh đầu vào. Nó là một dạng của bộ lọc thông thấp ("làm mờ"). Một ô mờ 3 x 3 có thể được viết dưới dạng ma trận

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

1_oos3y1ztoewgieubpdnbvea

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

hộp mờ

Sự lặp lại

bạn có thể sử dụng Rendertexture để lưu trữ khung hình trước đó. Vì vậy, bạn có thể lấy khung hình trước đó sau đó làm mờ. bằng cách lặp lại điều này bạn đạt được mờ.

0fe28c6167db2132d4bb8677fc1b2050 - leandro-erlich-argentina

Bình thường

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

ghi_2019_03_03_21_35_45_417

Phần kết luận

Shader cuối cùng:

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

không sử dụng màu alpha trong suốt cuộc đời:

ghi_2019_03_03_21_48_36_273

bằng cách sử dụng màu alpha trong suốt cuộc đời:

hồ sơ_2019_03_03_21_48_19_786

Nguồn có sẵn:

https://github.com/smkplus/RainDrop

Còn nữa!

bạn cũng có thể tạo ra Ripples

bản ghi_2019_03_04_22_10_25_457

Liên kết hữu ích

https://80.lv/articles/breakdown-animated-raindrop-m vật liệu-in-kiện4 /

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


1

một câu hỏi về những năm trước đây, nhưng nó hoàn toàn không liên quan đến Unity (thật không may). Nếu bạn nhìn vào slide 57 của bản trình bày được liên kết, họ sẽ đề cập đến cách tiếp cận dựa trên lưới.

Có một câu hỏi hơi liên quan đến Vật lý SE mà bạn có thể thấy thú vị. Liên kết đến droet.pdf trong câu hỏi được liên kết bị hỏng, nhưng nó vẫn nằm trên Wayback Machine. Nó đi vào một số toán học của nước chảy ra từ một vài loại bề mặt. Ví dụ, các giọt nhỏ thích di chuyển trong các đường dẫn được sử dụng bởi các hạt mưa trước đó (xem p926).

Bạn có thể chỉ cần mô hình hóa các đầu và đuôi của mỗi "hạt mưa" và cho phép nó ngoằn ngoèo một chút. Khi hai hạt mưa kéo dài va chạm vào nhau, tôi cho rằng bạn có thể kết hợp chúng thành một hạt mưa lớn hơn và di chuyển nhanh hơn. Thể tích nước giữ nguyên. Nó chỉ được di chuyển và định hình bởi các lực hấp dẫn, bám dính vào kính và sự gắn kết.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.