"벽 뒤에서보기"효과를 만들려면 어떻게해야합니까?


103

신성 : Original Sin 2 에는 아름다운 시스루 시스템이 있습니다. 벽 뒤로 가면 스플래시 마스크가 나타나고 게임 주위를 움직이면 바뀝니다. 디졸브 셰이더와 같으며 메타 볼 효과가 있습니다.

이 효과를 어떻게 복제하여 플레이어가 벽 뒤에 갈 때 동적 스플래시 마스크를 만들 수 있습니까?

이 YouTube 비디오 를 통해 원하는 효과를 볼 수 있습니다 .

영상


3
안녕하세요, 질문 이외의 추가 항목을 요청하여 질문에 범위 크립을 추가 한 것 같습니다. 이 단계에서, 특히 추가 행동 요청에 의해 부분적으로 무효화 된 전체 답변을 얻은 후에는 요구 사항을 확장하는 대신 새로운 질문을하는 것이 좋습니다. 바운티가 세부 사항에 대한 것이면 새로운 질문을하고 문제를 설명하고 바운티에 대한 환불을 요청하기 위해 중재자에게이 질문에 플래그를 지정하여 바운티를 새 질문에 게시하면 좋습니다.
doppelgreener

2
스코프 크립으로 인해이 질문을 이전 상태로 롤백했습니다. 바운티 추가와 범위 변경이 포함 된 편집 사이의 시간을 감안할 때이 질문에 다른 답변을 원한다고 가정하면 바운티를 그대로 두겠습니다. @doppelgreener가 제안한 것처럼 새로운 요구 사항에 대해 다른 질문을하는 것이 좋습니다.
Alexandre Vaillancourt

죄송 오 @AlexandreVaillancourt 나는 수정하기위한 체인 questions.thanks을 좋아하지 않아 있기 때문에, 난 그냥 내 질문에 대한 옵션을 추가 몰랐 ...
세예드 모르테 카 말리

답변:


163

마스킹

이 효과를 얻으려면 스텐실 버퍼를 사용하여 객체를 마스크 할 수 있습니다.

스텐실 버퍼는 화면에 그려진 각 픽셀에 대해 추가 8 비트 정수 (예 : 0-255의 값)를 저장할 수있는 범용 버퍼입니다. 셰이더가 RGB 값을 계산하여 화면의 픽셀 색상을 결정하고 깊이 버퍼에 그려진 픽셀의 깊이에 대한 z 값을 지정하는 것처럼 각 픽셀에 대한 임의의 값을 스텐실 버퍼에 쓸 수도 있습니다. 그런 다음 이러한 스텐실 값을 쿼리하고 후속 셰이더 패스와 비교하여 픽셀을 화면에서 합성하는 방법을 결정할 수 있습니다.

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

효과 분석

절차 적 텍스처 를 원한다면 약간의 노이즈가 필요합니다.

영상 이 쉐이더는 ShaderToy 에서 볼 수 있습니다 .

이 효과를 만들려면 UV 좌표를 사용하는 대신 극좌표를 사용 하여 노이즈 텍스처로 설정하십시오.

Uvs는 일반적으로 픽셀 na 화면 (X = 너비, Y = 높이)과 같은 형식으로 그리드에 배치됩니다. 그러나 극좌표는 x와 ya 비트를 다르게 사용합니다. 하나는 원의 중심에서 얼마나 떨어져 있는지를 결정하고 다른 하나는 필요한 것에 따라 0-1 범위에서 각도를 결정합니다.

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

다른 해결책은 worley noise를 사용하는 것입니다.

2018-01-05_8-16-16

이 쉐이더를 ShaderToy 에서 볼 수 있습니다


메타 볼

그런 다음 이 기사 에서 metaball 효과를 추가 하십시오 . img


빌 탑승

더있다 ...

당신이 당신의 카메라에보고, 마스크를 회전하려면 사용할 수 있습니다 빌 보드 :

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

이것은 빌 탑승과 마스크입니다 :

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
이것은 플레이어 캐릭터 앞에 있다는 것을 알면 프론트 벽에서 마스킹을 수행하는 방법에 대한 좋은 설명이지만 캐릭터의 지오메트리 앞에있는 벽에만이 쉐이더를 자동으로 적용하는 방법이 있습니까?
솜털

10
@fluffy 당신은 캐릭터가 벽 뒤에있을 때를 탐지하기 위해 Raycast를 사용할 수 있으며 마스크를 활성화합니다.
Seyed Morteza Kamali
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.