ฉันจะสร้างเอฟเฟกต์ "ดูด้านหลังกำแพง" ได้อย่างไร


103

เทพ: บาปดั้งเดิม 2มีระบบการไหลผ่านที่สวยงาม เมื่อฉันไปด้านหลังกำแพงหน้ากากสาดจะปรากฏขึ้นและเมื่อฉันย้ายไปรอบ ๆ เกมมันเปลี่ยนไป มันเหมือน shader ที่ละลายและมีเอฟเฟกต์เมทัลล์

ฉันจะทำซ้ำเอฟเฟกต์นี้ได้อย่างไรโดยสร้างหน้ากากสาดแบบไดนามิกเมื่อผู้เล่นอยู่หลังกำแพง?

คุณสามารถดูเอฟเฟกต์ที่ต้องการผ่านวิดีโอ YouTubeนี้

ภาพ


3
สวัสดีคุณดูเหมือนจะเพิ่มขอบเขตการคืบคำถามของคุณโดยการขอสิ่งเพิ่มเติมนอกเหนือจากนั้น ในขั้นตอนนี้ - โดยเฉพาะอย่างยิ่งหลังจากได้รับคำตอบเต็มรูปแบบซึ่งได้รับการทำให้เป็นโมฆะบางส่วนโดยคำขอของคุณสำหรับพฤติกรรมเพิ่มเติม - คุณอาจดีกว่าที่จะถามคำถามใหม่แทนที่จะขยายความต้องการของคุณ หากเงินรางวัลมีไว้สำหรับรายละเอียดเหล่านั้นคุณจะทำได้ดีโดยถามคำถามใหม่อธิบายปัญหาของคุณตั้งค่าสถานะคำถามนี้เพื่อให้ผู้ดูแลสนใจขอเงินคืนจากเงินรางวัลและโพสต์เงินรางวัลในคำถามใหม่
doppelgreener

2
ฉันย้อนกลับคำถามนี้กลับสู่สถานะก่อนหน้าเนื่องจากขอบเขตการคืบ เมื่อกำหนดเวลาระหว่างการเพิ่มค่าหัวและการแก้ไขที่รวมการเปลี่ยนแปลงขอบเขตไว้ฉันคิดว่าคุณต้องการได้คำตอบที่แตกต่างกันสำหรับคำถามนี้ดังนั้นฉันจะปล่อยให้ค่าหัว ตามที่ @doppelgreener แนะนำฉันขอให้คุณตั้งคำถามใหม่เกี่ยวกับข้อกำหนดใหม่ของคุณ
Alexandre Vaillancourt

@AlexandreVaillancourt โอ้ขอโทษผมไม่ทราบว่ามันฉันเพียงแค่เพิ่มตัวเลือกให้กับคำถามของฉันเพราะฉันไม่ชอบ questions.thanks ห่วงโซ่สำหรับการปรับเปลี่ยน ...
Seyed Morteza Kamali

คำตอบ:


163

การกำบัง

ในการสร้างเอฟเฟกต์นี้คุณสามารถปิดบังวัตถุโดยใช้ stencil Buffer

stencil buffer เป็นบัฟเฟอร์เอนกประสงค์ที่อนุญาตให้คุณเก็บจำนวนเต็ม 8 บิตเพิ่มเติม (เช่นค่าจาก 0-255) สำหรับแต่ละพิกเซลที่วาดลงบนหน้าจอ เช่นเดียวกับเฉดสีที่คำนวณค่า RGB เพื่อกำหนดสีของพิกเซลบนหน้าจอและค่า z สำหรับความลึกของพิกเซลเหล่านั้นที่ลากไปยังบัฟเฟอร์ความลึกพวกเขายังสามารถเขียนค่าตามอำเภอใจสำหรับแต่ละพิกเซลเหล่านั้นไปยังบัฟเฟอร์ stencil ค่าลายฉลุเหล่านั้นสามารถสอบถามและเปรียบเทียบโดย shader ที่ตามมาผ่านเพื่อกำหนดวิธีพิกเซลควรจะแต่งบนหน้าจอ

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

ภาพ

หน้ากากลายฉลุ:

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

ผนังลายฉลุ:

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

มาใช้กัน

ใช้สิ่งนี้เป็นหน้ากาก:

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

ใช้สิ่งนี้เป็นกำแพง:

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

การวิเคราะห์ผลกระทบ

หากคุณต้องการมีพื้นผิวขั้นตอนคุณต้องมีเสียงบางอย่าง

ภาพ คุณสามารถดู Shader นี้ในShaderToy

ในการทำให้เอฟเฟกต์นี้แทนที่จะใช้ UV Coordinates ให้ใช้พิกัดโพลาร์แล้วจึงตั้งเป็นพื้นผิวของจุดรบกวน

โดยทั่วไปแล้วยูวีจะถูกจัดวางในตารางเช่นเดียวกับแฟชั่นเช่นหน้าจอพิกเซล na (X = ความกว้าง, Y = ความสูง) อย่างไรก็ตามพิกัดเชิงขั้วใช้ x และ ya bit ต่างกัน หนึ่งกำหนดว่าอยู่ห่างจากจุดศูนย์กลางของวงกลมมากแค่ไหนและอีกอันหนึ่งกำหนดองศาจากช่วง 0-1 ขึ้นอยู่กับสิ่งที่คุณต้องการ

1600 พิกเซล-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"
}

อีกวิธีใช้เสียง worley:

2018-01-05_8-16-16

คุณสามารถเห็นส่วนนี้ในShaderToy


Metaball

แล้วฉันจะเพิ่มผล metaball จากบทความนี้ : img


บิลบอร์ดดิ้ง

มีอีก ...

หากคุณต้องการหมุนหน้ากากเพื่อมองไปที่กล้องของคุณคุณสามารถใช้Bill board :

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

นี่คือหน้ากากที่มีการขึ้น Bill:

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

ผลสุดท้าย:

2018-01-04_20-18-39

แหล่งที่มามีอยู่: https://github.com/smkplus/Divinity-Origin-Sin-2


ลิงค์ที่มีประโยชน์

ฉันพบบทช่วยสอนที่ดีที่ใช้เอฟเฟกต์นี้โดยการละลายโลก:

ภาพที่ 1

ละลายโลกตอนที่ 1

ละลายโลกตอนที่ 2

ภาพ

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

กวดวิชาลายฉลุอีก:

Left4Dead

ลายฉลุสอน


10
นี่เป็นคำอธิบายที่ดีเกี่ยวกับวิธีการปิดบังด้านหน้าของกำแพงโดยให้ความรู้ว่ามันอยู่ด้านหน้าตัวละครของผู้เล่น แต่มีวิธีที่จะใช้ shader นี้กับผนังที่อยู่ด้านหน้าของเรขาคณิตของตัวละครโดยอัตโนมัติหรือไม่?
ปุย

10
@fluffy คุณสามารถใช้ Raycast เพื่อตรวจจับเมื่อตัวละครอยู่ด้านหลังกำแพงแล้วเปิดใช้งาน Mask
Seyed Morteza Kamali
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.