화면에 자연적인 빗방울을 만들려면 어떻게해야합니까?


11

메타 볼 과 화면에 흔적으로 비 효과를 줄이려고하는데 셰이더 토이 에서 단서를 찾았지만 구현 방법을 이해하지 못했습니다.

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

불행히도 많은 수학 계산이 있고 지연을 생성하기 때문에 단일하게 사용할 수 없습니다. 분명히 텍스처를 사용해야하지만 어떻게 트레일 효과를 얻을 수 있습니까?!

여기에 이미지 설명을 입력하십시오

내 아이디어는 드롭에 텍스처와 트레일 렌더러를 사용하고 있지만 메타 볼 효과를 어떻게 얻을 수 있습니까? 여기에 이미지 설명을 입력하십시오


최신 정보

이 기사로 메타 볼을 구현할 수 있습니다

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

그러나 나는 흔적에 대해 생각하지 않았다

답변:


11

이 효과를 "물이있는 곳의지도 계산"+ "해당지도에서 법선 벡터를 생성하고이를 사용하여 배경 텍스처 조회를 상쇄"하는 것으로 생각해야한다고 생각합니다.

예제 셰이더 토이의 기능을 분석하면, "트레일"을 계산하여 디포 깅이 발생하는 위치를 보여줍니다.

여기에 이미지 설명을 입력하십시오

원형 빗방울의 법선을 계산합니다.

여기에 이미지 설명을 입력하십시오

그 노멀 맵을 사용하여 텍스처 조회를 가짜 굴절로 오프셋합니다.

셰이더에서 사후 처리를 통해 트레일을 수행하려면 대수를 사용하여 셰이더에 "트레일"모양을 만들어야합니다. 예를 들어, 다음 함수에서, "비틀 거리는 경로"와 머리와 꼬리에 테이퍼를 겹쳐서

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

여기 에 빗방울 흔적을 만드는 방법을 보여주는 셰이더 토이의 대략적인 POC가 있습니다. https://www.shadertoy.com/view/XlBfz1 미분 분해능으로 인해 작은 해상도에서 입자가 거칠어 보이지만 전체 화면으로 표시하면 더 좋아 보입니다.

편집 : 중첩 된 빗방울이있는 예를 추가했습니다 .

여기에 이미지 설명을 입력하십시오

독자에게 연습으로 남겨 두십시오.

1) 작은 둥근 방울을 추가하십시오. 영감을 얻으 StaticDrops려면 원래 셰이더 토이 예제에서 함수를 살펴보십시오 .

2) 고품질 정규 계산을 추가하십시오. #define CHEAP_NORMALS원래 셰이더 토이 예제 의 옵션에서 알 수 있듯이 내장 된 dFdx는 정확도가 낮으며 파생 함수를 수동으로 계산하여 (함수를 3 번 ​​계산하는 대신) 더 나은 결과를 얻을 수 있습니다.

3) 열 사이의 간격을 무작위로 지정합니다. 열을 넓힌 다음 uv.x - 0.5 + 0.2 * wobble비트를 수정 하여 x 축에 임의의 오프셋을 추가 할 수 있습니다. 또한 원래 예제에서 페이지를 다시 한 번 가져 와서 서로 다른 크기의 스트림 레이어를 서로 겹쳐서 덜 균일 한 모양으로 만들고 싶을 것입니다.



@DMGregory 참고 사항. 메타 볼 댓글 제거
Jimmy

트레일 자체는 페이딩을 통해 버퍼를 통해 수행 할 수 있습니다 (return oldValue * .95 + newdiskposition). 일반적으로 사람들은 Perlin 노이즈를 사용하여 직선에 영향을줍니다.
Seyed Morteza Kamali

shadertoy.com/view/4dy3zR 와 같은 것 나는 시끄러운 흔적을 만들려고 노력했지만 할 수 없었습니다
Seyed Morteza Kamali

7

아래 단계에 따라이 효과를 만들 수 있습니다.

입자

입자

RenderTextuer

RenderTexture를 사용하여 결과를 저장할 수 있습니다. 이것은 shadertoy의 멀티 패스 예제입니다 :

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

iñigo quilez : Shadertoy는 "버퍼"당 하나씩 여러 패스를 사용합니다. 이름에서 알 수 있듯이이 패스는 결과를 버퍼에 저장합니다. 버퍼는 텍스처 일뿐입니다. 유니티는 텍스처로도 렌더링 할 수있게 해줍니다.

파티클을 RenderTexture로 렌더링하는 카메라를 만들었습니다.

도끼

렌더 텍스처

움켜 쥐기

왜곡을 적용하기 위해 패스를 잡을 수 있습니다

이 게시물에서 설명했습니다.

Quantum Break의 왜곡 입자 효과를 어떻게 복제 할 수 있습니까?

흐림

평생 동안 알파를 컬러로 사용하면 간단한 흐림 효과가 있습니다.

알파 오버 타임

gradiant

더 나은 결과를 얻으려면 간단한 블러를 사용하는 것이 좋지만 어떻게 블러를 달성합니까?

컨벌루션 매트릭스

이미지 처리에서 커널, 컨벌루션 매트릭스 또는 마스크는 작은 매트릭스입니다. 블러 링, 샤프닝, 엠보싱, 에지 감지 등에 사용됩니다. 이것은 커널과 이미지 사이의 컨볼 루션을 수행함으로써 달성됩니다.

자세한 내용은이 링크를 참조하십시오

핵심

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

박스 블러

박스 블러 (박스 선형 필터라고도 함)는 결과 이미지의 각 픽셀이 입력 이미지의 인접 픽셀의 평균값과 동일한 값을 갖는 공간 도메인 선형 필터입니다. 저역 통과 ( "블러 링") 필터의 형태입니다. 3x3 상자 흐림은 행렬로 쓸 수 있습니다

https://ko.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
        }
    }
}

블러 박스

되풀이

Rendertexture를 사용하여 이전 프레임을 저장할 수 있으므로 이전 프레임을 잡고 흐리게 처리 할 수 ​​있습니다. 이것을 반복함으로써 흐림 효과를 얻을 수 있습니다.

0fe28c6167db2132d4bb8677fc1b2050--leandro-erlich-argentina

표준

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

record_2019_03_03_21_35_45_417

결론

최종 셰이더 :

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

평생 동안 알파를 사용하지 않고

record_2019_03_03_21_48_36_273

평생 동안 알파 색상을 사용하여 :

record_2019_03_03_21_48_19_786

출처는 다음과 같습니다.

https://github.com/smkplus/RainDrop

더있다!

또한 당신은 잔물결을 만들 수 있습니다

record_2019_03_04_22_10_25_457

유용한 링크

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/


1

실제로 몇 년 전에 실제로 질문 이 있었지만, 불행히도 Unity와 전혀 관련이 없습니다. 링크 된 프레젠테이션의 슬라이드 57 을 보면 그리드 기반 방식이 언급됩니다.

있어 다소 관련된 흥미로운 찾을 수 있다는 물리학 SE에 대한 질문. 링크 된 질문에서 droplet.pdf 에 대한 링크가 끊어졌지만 여전히 Wayback Machine에 있습니다. 그것은 몇 가지 유형의 표면에서 흘러 나오는 물의 수학에 들어갑니다. 물방울은 예를 들어 이전 빗방울에서 사용했던 경로를 따라 이동하는 것을 선호합니다 (p926 참조).

각 "빗방울"의 머리와 꼬리를 모델링하여 지그재그로 지그재그로 만들 수 있습니다. 길쭉한 빗방울 두 개가 충돌하면 더 크고 빠르게 움직이는 빗방울로 결합 할 수 있다고 생각합니다. 물의 양은 동일하게 유지됩니다. 그것은 단지 중력, 유리에 대한 접착력 및 응집력에 의해 움직여지고 형성됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.