Bagaimana saya bisa membuat efek "lihat di balik tembok"?

103

Divinity: Original Sin 2 memiliki sistem tembus pandang yang indah. Ketika saya pergi di belakang dinding, topeng splash akan muncul, dan ketika saya bergerak di sekitar permainan, itu berubah. Ini seperti shader yang larut, dan memiliki efek metaball.

Bagaimana saya bisa meniru efek ini, membuat topeng splash dinamis ketika pemain pergi di belakang dinding?

Anda dapat melihat efek yang diinginkan dalam gerakan melalui video YouTube ini .

Gambar

Sayy Morteza Kamali
sumber
3
Hai, Anda tampaknya telah menambahkan cakupan creep ke pertanyaan Anda dengan meminta hal-hal tambahan di luarnya. Pada tahap ini - terutama setelah mendapat jawaban lengkap, yang secara efektif sebagian telah dibatalkan oleh permintaan Anda untuk perilaku tambahan - Anda mungkin lebih baik mengajukan pertanyaan baru daripada memperluas persyaratan Anda. Jika bounty itu untuk perincian itu, Anda akan baik-baik saja dengan mengajukan pertanyaan baru, menjelaskan masalah Anda, menandai pertanyaan ini untuk perhatian moderator untuk meminta pengembalian uang pada bounty, dan memposting bounty pada pertanyaan baru.
doppelgreener
2
Saya memutar kembali pertanyaan ini ke keadaan sebelumnya karena cakupan creep. Mengingat waktu antara penambahan karunia dan hasil edit yang menyertakan perubahan cakupan, saya berasumsi Anda ingin mendapatkan jawaban berbeda untuk pertanyaan ini, jadi saya akan membiarkan karunia itu naik. Seperti yang disarankan oleh @doppelgreener, saya sarankan Anda mengajukan pertanyaan lain dengan persyaratan baru Anda.
Alexandre Vaillancourt
@AlexandreVaillancourt oh maaf saya tidak tahu itu, saya hanya menambahkan opsi untuk pertanyaan saya karena saya tidak suka questions.thanks rantai untuk memodifikasi ...
Seyed Morteza Kamali

Jawaban:

163

Masking

Untuk membuat efek ini, Anda dapat menutupi objek dengan menggunakan penyangga stensil.

buffer stensil adalah buffer tujuan umum yang memungkinkan Anda untuk menyimpan integer 8bit tambahan (yaitu nilai 0-255) untuk setiap piksel yang ditarik ke layar. Sama seperti shader menghitung nilai RGB untuk menentukan warna piksel pada layar, dan nilai z untuk kedalaman piksel yang ditarik ke buffer kedalaman, mereka juga dapat menulis nilai arbitrer untuk masing-masing piksel tersebut ke buffer stensil. Nilai-nilai stensil itu kemudian dapat ditanyakan dan dibandingkan dengan melewati shader berikutnya untuk menentukan bagaimana piksel harus dikomposisikan pada layar.

https://docs.unity3d.com/Manual/SL-Stencil.html

https://alastaira.wordpress.com/2014/12/27/using-the-stencil-buffer-in-unity-free/

http://www.codingwithunity.com/2016/01/stencil-buffer-shader-for-special.html

gambar

Stensil Masker:

Stencil 
{
    Ref 1 // ReferenceValue = 1
    Comp NotEqual // Only render pixels whose reference value differs from the value in the buffer.
}

Stensil dinding:

Stencil
{
    Ref 1 // ReferenceValue = 1
    Comp Always // Comparison Function - Make the stencil test always pass.
    Pass Replace // Write the reference value into the buffer.
}

Mari Melaksanakan.

gunakan ini sebagai topeng:

Shader "Custom/SimpleMask"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _CutOff("CutOff", Range(0,1)) = 0
    }
    SubShader
    {
        LOD 100
        Blend One OneMinusSrcAlpha
        Tags { "Queue" = "Geometry-1" }  // Write to the stencil buffer before drawing any geometry to the screen
        ColorMask 0 // Don't write to any colour channels
        ZWrite Off // Don't write to the Depth buffer
        // Write the value 1 to the stencil buffer
        Stencil
        {
            Ref 1
            Comp Always
            Pass Replace
        }

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _CutOff;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);

                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                float dissolve = step(col, _CutOff);
                clip(_CutOff-dissolve);
                return float4(1,1,1,1)*dissolve;
            }
            ENDCG
        }
    }
}

gunakan ini sebagai tembok:

Shader "Custom/Wall" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
        Blend SrcAlpha OneMinusSrcAlpha
        Tags { "RenderType"="Opaque" }
        LOD 200

        Stencil {
            Ref 1
            Comp NotEqual
        }

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

Analisis Efek

Jika Anda ingin memiliki tekstur prosedural , Anda perlu suara.

gambar Anda dapat melihat shader ini di ShaderToy .

Untuk membuat efek ini, alih-alih menggunakan Koordinat UV, gunakan Koordinat Polar kemudian setel ke tekstur derau.

Uv biasanya diletakkan dalam kisi-kisi seperti mode, seperti piksel layar na (X = lebar, Y = tinggi). Koordinat kutub, bagaimanapun, menggunakan bit x dan ya secara berbeda. Satu menentukan seberapa jauh dari pusat lingkaran itu dan yang lain menentukan derajat, dari rentang 0-1, tergantung pada apa yang Anda butuhkan.

1600px-sf_radialuvs

Shader "Smkgames/NoisyMask" {
    Properties {
        _MainTex ("MainTex", 2D) = "white" {}
        _Thickness ("Thickness", Range(0, 1)) = 0.25
        _NoiseRadius ("Noise Radius", Range(0, 1)) = 1
        _CircleRadius("Circle Radius", Range(0, 1)) = 0.5
        _Speed("Speed", Float) = 0.5
    }
    SubShader {
        Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"}
        ZWrite Off 
        Blend SrcAlpha OneMinusSrcAlpha 
        Cull Off

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma target 3.0
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform float _Thickness,_NoiseRadius,_CircleRadius,_Speed;

            struct VertexInput {
                float4 vertex : POSITION;
                float2 texcoord0 : TEXCOORD0;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                float4 posWorld : TEXCOORD1;

            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.uv0 = v.texcoord0;

                o.pos = UnityObjectToClipPos(v.vertex);
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }
            float4 frag(VertexOutput i, float facing : VFACE) : COLOR {

                float2 uv = (i.uv0*2.0+-1.0); // Remapping uv from [0,1] to [-1,1]
                float circleMask = step(length(uv),_NoiseRadius); // Making circle by LENGTH of the vector from the pixel to the center
                float circleMiddle = step(length(uv),_CircleRadius); // Making circle by LENGTH of the vector from the pixel to the center
                float2 polaruv = float2(length(uv),((atan2(uv.g,uv.r)/6.283185)+0.5)); // Making Polar
                polaruv += _Time.y*_Speed/10;
                float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(polaruv, _MainTex)); // BackGround Noise
                float Noise = (circleMask*step(_MainTex_var.r,_Thickness)); // Masking Background Noise
                float3 finalColor = float3(Noise,Noise,Noise);
                return fixed4(finalColor+circleMiddle,(finalColor+circleMiddle).r);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

solusi lain menggunakan worley noise:

2018-01-05_8-16-16

Anda dapat melihat shader ini di ShaderToy


Metaball

maka saya menambahkan efek metaball dari artikel ini : img


Bill boarding

masih ada lagi...

Jika Anda ingin memutar topeng Anda, untuk melihat ke kamera Anda, Anda dapat menggunakan papan Bill :

 output.pos = mul(UNITY_MATRIX_P, 
              mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
              + float4(input.vertex.x, input.vertex.y, 0.0, 0.0));

ini topeng dengan Bill naik:

Shader "Custom/Mask/SimpleMaskBillBoard"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _CutOff("CutOff", Range(0,1)) = 0
        _Radius("Radius", Range(0,1)) = 0.2
        _Speed("speed", Float) = 1
        _ScaleX ("Scale X", Float) = 1.0
        _ScaleY ("Scale Y", Float) = 1.0
    }
    SubShader
    {
        LOD 100
        Blend One OneMinusSrcAlpha
        Tags { "Queue" = "Geometry-1" }  // Write to the stencil buffer before drawing any geometry to the screen
        ColorMask 0 // Don't write to any colour channels
        ZWrite Off // Don't write to the Depth buffer

        // Write the value 1 to the stencil buffer
        Stencil
        {
            Ref 1
            Comp Always
            Pass Replace
        }

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _CutOff;
            float _Speed;
            float _Radius;
            float _ScaleX,_ScaleY;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_P, 
                    mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
                    + float4(v.vertex.x, v.vertex.y, 0.0, 0.0)
                    * float4(_ScaleX, _ScaleY, 1.0, 1.0));

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                float dissolve = step(col, _CutOff);
                clip(_CutOff-dissolve);
                return dissolve;
            }
            ENDCG
        }
    }
}

Hasil akhir:

2018-01-04_20-18-39

Sumber tersedia: https://github.com/smkplus/Divinity-Origin-Sin-2


Tautan yang Berguna

Saya menemukan tutorial yang bagus yang menerapkan efek ini dengan Melarutkan dunia:

Gambar1

Melarutkan dunia Bagian 1

Melarutkan dunia Bagian 2

Gambar

Shader "Custom/DissolveBasedOnViewDistance" {
    Properties{
        _MainTex("Albedo (RGB)", 2D) = "white" {}
        _Center("Dissolve Center", Vector) = (0,0,0,0)
        _Interpolation("Dissolve Interpolation", Range(0,5)) = 0.8
        _DissTexture("Dissolve Texture", 2D) = "white" {}
    }

        SubShader{
        Tags { "RenderType" = "Opaque" }
        LOD 200


            CGPROGRAM

        #pragma surface surf Standard vertex:vert addshadow

        #pragma target 3.0

        struct Input {
            float2 uv_MainTex;
            float2 uv_DissTexture;
            float3 worldPos;
            float viewDist;
        };



        sampler2D _MainTex;
        sampler2D _DissTexture;
        half _Interpolation;
        float4 _Center;


        // Computes world space view direction
        // inline float3 WorldSpaceViewDir( in float4 v )
        // {
        //     return _WorldSpaceCameraPos.xyz - mul(_Object2World, v).xyz;
        // }


        void vert(inout appdata_full v,out Input o){
            UNITY_INITIALIZE_OUTPUT(Input,o);

         half3 viewDirW = WorldSpaceViewDir(v.vertex);
         o.viewDist = length(viewDirW);

        }

        void surf(Input IN, inout SurfaceOutputStandard o) {


            float l = length(_Center - IN.worldPos.xyz);

            clip(saturate(IN.viewDist - l + (tex2D(_DissTexture, IN.uv_DissTexture) * _Interpolation * saturate(IN.viewDist))) - 0.5);

         o.Albedo = tex2D(_MainTex,IN.uv_MainTex);
        }
        ENDCG
        }
        Fallback "Diffuse"
}

Tutorial stensil lainnya:

Left4Dead

Tutorial Stensil

Sayy Morteza Kamali
sumber
10
Ini adalah penjelasan yang baik tentang bagaimana melakukan masking dari dinding depan mengingat pengetahuannya berada di depan karakter pemain, tetapi apakah ada cara untuk secara otomatis menerapkan shader ini hanya pada dinding yang ada di depan geometri karakter?
Fluffy
10
@fluffy Anda dapat menggunakan Raycast untuk mendeteksi ketika karakter berada di balik dinding lalu aktifkan Mask.
Seyed Morteza Kamali