【问题标题】:Is there a way to hide a player who is in the shadow in Unity 2D Light System?有没有办法在 Unity 2D Light System 中隐藏处于阴影中的玩家?
【发布时间】:2021-01-13 05:42:14
【问题描述】:

我想在 Unity 中使用 Universal Pipeline 和 2D 照明系统重新创建游戏“我们之中”的视野效果。

但是当我使用 2D 光和影时,我仍然看到阴影中的角色,我不想让阴影完全变黑,因为我想重新创建游戏中的外观,就像在我们中间一样,背景仍然存在有一些亮点。

这就是我们中间视野的意思

如您所见,有阴影,背景是浅色的,角色的身体一半在不可见的阴影中,一半在可见的光线中。

我的意思是玩家被黑了

有几个关于它的 YouTube 视频,但视图变得清晰,并且视图边缘没有像 2D 灯光那样的辐射。这真的让它看起来很漂亮。

我需要这方面的帮助,是否可以在 Unity 中使用 2D 灯光和阴影来实现这一点?如果是这样,我该怎么做?

提前感谢您的帮助,非常感谢。

【问题讨论】:

  • 我不确定你是否可以用普通阴影实现这一点,它看起来更像是一个蒙版。
  • 但是我该怎么做呢?我能够生成一个网格,它的作用与我们中间的一样,它会隐藏和显示等等。但我无法实现 fersnal 效果,也无法像《我们之中》中那样喜欢边缘的余波。这会导致游戏中断。

标签: c# unity3d shader


【解决方案1】:

我花了一段时间才弄明白,而且我不是那个弄明白的人,我从 Unity Discord 服务器上的某个人那里得到了帮助。他进入Sprite-Lit-Default 并更改了一些占luminance 的代码,现在我对着色器编程一无所知,所以我无法解释太多。但他创建了一个.hlsl 文件,其功能与Unity 用来计算灯光的CombinedShapeLightShared.hlsl 文件can be found here 具有相同的功能,但添加了一些解释luminance 的参数。现在这里是.shader 文件和.hlsl 文件的文件内容。

但是您需要将这两个文件保存在同一个文件夹中,否则将无法正常工作。还要保持文件名相同,除非您知道自己在做什么

文件名HideInShadow.shader

Shader "Universal Render Pipeline/2D/HideInShadow"
{
    Properties
    {
        _MainTex("Diffuse", 2D) = "white" {}
        _MaskTex("Mask", 2D) = "white" {}
        _NormalMap("Normal Map", 2D) = "bump" {}

        // Legacy properties. They're here so that materials using this shader can gracefully fallback to the legacy sprite shader.
        [HideInInspector] _Color("Tint", Color) = (1,1,1,1)
        [HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1)
        [HideInInspector] _Flip("Flip", Vector) = (1,1,1,1)
        [HideInInspector] _AlphaTex("External Alpha", 2D) = "white" {}
        [HideInInspector] _EnableExternalAlpha("Enable External Alpha", Float) = 0
    }

    HLSLINCLUDE
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    ENDHLSL

    SubShader
    {
        Tags {"Queue" = "Transparent" "RenderType" = "Transparent" "RenderPipeline" = "UniversalPipeline" }

        Blend SrcAlpha OneMinusSrcAlpha
        Cull Off
        ZWrite Off

        Pass
        {
            Tags { "LightMode" = "Universal2D" }
            HLSLPROGRAM
            #pragma vertex CombinedShapeLightVertex
            #pragma fragment CombinedShapeLightFragment
            #pragma multi_compile USE_SHAPE_LIGHT_TYPE_0 __
            #pragma multi_compile USE_SHAPE_LIGHT_TYPE_1 __
            #pragma multi_compile USE_SHAPE_LIGHT_TYPE_2 __
            #pragma multi_compile USE_SHAPE_LIGHT_TYPE_3 __

            struct Attributes
            {
                float3 positionOS   : POSITION;
                float4 color        : COLOR;
                float2  uv           : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct Varyings
            {
                float4  positionCS  : SV_POSITION;
                half4   color       : COLOR;
                float2  uv          : TEXCOORD0;
                half2   lightingUV  : TEXCOORD1;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            #include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/LightingUtility.hlsl"

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);
            TEXTURE2D(_MaskTex);
            SAMPLER(sampler_MaskTex);
            half4 _MainTex_ST;

            #if USE_SHAPE_LIGHT_TYPE_0
            SHAPE_LIGHT(0)
            #endif

            #if USE_SHAPE_LIGHT_TYPE_1
            SHAPE_LIGHT(1)
            #endif

            #if USE_SHAPE_LIGHT_TYPE_2
            SHAPE_LIGHT(2)
            #endif

            #if USE_SHAPE_LIGHT_TYPE_3
            SHAPE_LIGHT(3)
            #endif

            Varyings CombinedShapeLightVertex(Attributes v)
            {
                Varyings o = (Varyings)0;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

                o.positionCS = TransformObjectToHClip(v.positionOS);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.lightingUV = ComputeNormalizedDeviceCoordinates(o.positionCS);
                o.color = v.color;
                return o;
            }

            #include "CombinedShapeLightSharedHidden.hlsl"

            half4 CombinedShapeLightFragment(Varyings i) : SV_Target
            {
                half4 main = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                half4 mask = SAMPLE_TEXTURE2D(_MaskTex, sampler_MaskTex, i.uv);

                return CombinedShapeLightShared(main, mask, i.lightingUV);
            }
            ENDHLSL
        }

        Pass
        {
            Tags { "LightMode" = "NormalsRendering"}
            HLSLPROGRAM
            #pragma vertex NormalsRenderingVertex
            #pragma fragment NormalsRenderingFragment

            struct Attributes
            {
                float3 positionOS   : POSITION;
                float4 color        : COLOR;
                float2 uv           : TEXCOORD0;
                float4 tangent      : TANGENT;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct Varyings
            {
                float4  positionCS      : SV_POSITION;
                half4   color           : COLOR;
                float2  uv              : TEXCOORD0;
                half3   normalWS        : TEXCOORD1;
                half3   tangentWS       : TEXCOORD2;
                half3   bitangentWS     : TEXCOORD3;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);
            TEXTURE2D(_NormalMap);
            SAMPLER(sampler_NormalMap);
            half4 _NormalMap_ST;  // Is this the right way to do this?

            Varyings NormalsRenderingVertex(Attributes attributes)
            {
                Varyings o = (Varyings)0;
                UNITY_SETUP_INSTANCE_ID(attributes);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

                o.positionCS = TransformObjectToHClip(attributes.positionOS);
                o.uv = TRANSFORM_TEX(attributes.uv, _NormalMap);
                o.color = attributes.color;
                o.normalWS = TransformObjectToWorldDir(float3(0, 0, -1));
                o.tangentWS = TransformObjectToWorldDir(attributes.tangent.xyz);
                o.bitangentWS = cross(o.normalWS, o.tangentWS) * attributes.tangent.w;
                return o;
            }

            #include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/NormalsRenderingShared.hlsl"

            half4 NormalsRenderingFragment(Varyings i) : SV_Target
            {
                half4 mainTex = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                half3 normalTS = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, i.uv));
                return NormalsRenderingShared(mainTex, normalTS, i.tangentWS.xyz, i.bitangentWS.xyz, i.normalWS.xyz);
            }
            ENDHLSL
        }
        Pass
        {
            Tags { "LightMode" = "UniversalForward" "Queue"="Transparent" "RenderType"="Transparent"}

            HLSLPROGRAM
            #pragma vertex UnlitVertex
            #pragma fragment UnlitFragment

            struct Attributes
            {
                float3 positionOS   : POSITION;
                float4 color        : COLOR;
                float2 uv           : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct Varyings
            {
                float4  positionCS      : SV_POSITION;
                float4  color           : COLOR;
                float2  uv              : TEXCOORD0;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);
            float4 _MainTex_ST;

            Varyings UnlitVertex(Attributes attributes)
            {
                Varyings o = (Varyings)0;
                UNITY_SETUP_INSTANCE_ID(attributes);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

                o.positionCS = TransformObjectToHClip(attributes.positionOS);
                o.uv = TRANSFORM_TEX(attributes.uv, _MainTex);
                o.color = attributes.color;
                return o;
            }

            float4 UnlitFragment(Varyings i) : SV_Target
            {
                float4 mainTex = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                return mainTex;
            }
            ENDHLSL
        }
    }

    Fallback "Sprites/Default"
}

文件名CombinedShapeLightSharedHidden.hlsl

#if !defined(COMBINED_SHAPE_LIGHT_PASS)
#define COMBINED_SHAPE_LIGHT_PASS

half _HDREmulationScale;
half _UseSceneLighting;
half4 _RendererColor;

half4 CombinedShapeLightShared(half4 color, half4 mask, half2 lightingUV)
{
    if (color.a == 0.0)
        discard;

    color = color * _RendererColor; // This is needed for sprite shape

#if USE_SHAPE_LIGHT_TYPE_0
    half4 shapeLight0 = SAMPLE_TEXTURE2D(_ShapeLightTexture0, sampler_ShapeLightTexture0, lightingUV);

    if (any(_ShapeLightMaskFilter0))
    {
        half4 processedMask = (1 - _ShapeLightInvertedFilter0) * mask + _ShapeLightInvertedFilter0 * (1 - mask);
        shapeLight0 *= dot(processedMask, _ShapeLightMaskFilter0);
    }

    half4 shapeLight0Modulate = shapeLight0 * _ShapeLightBlendFactors0.x;
    half4 shapeLight0Additive = shapeLight0 * _ShapeLightBlendFactors0.y;
#else
    half4 shapeLight0Modulate = 0;
    half4 shapeLight0Additive = 0;
#endif

#if USE_SHAPE_LIGHT_TYPE_1
    half4 shapeLight1 = SAMPLE_TEXTURE2D(_ShapeLightTexture1, sampler_ShapeLightTexture1, lightingUV);

    if (any(_ShapeLightMaskFilter1))
    {
        half4 processedMask = (1 - _ShapeLightInvertedFilter1) * mask + _ShapeLightInvertedFilter1 * (1 - mask);
        shapeLight1 *= dot(processedMask, _ShapeLightMaskFilter1);
    }

    half4 shapeLight1Modulate = shapeLight1 * _ShapeLightBlendFactors1.x;
    half4 shapeLight1Additive = shapeLight1 * _ShapeLightBlendFactors1.y;
#else
    half4 shapeLight1Modulate = 0;
    half4 shapeLight1Additive = 0;
#endif

#if USE_SHAPE_LIGHT_TYPE_2
    half4 shapeLight2 = SAMPLE_TEXTURE2D(_ShapeLightTexture2, sampler_ShapeLightTexture2, lightingUV);

    if (any(_ShapeLightMaskFilter2))
    {
        half4 processedMask = (1 - _ShapeLightInvertedFilter2) * mask + _ShapeLightInvertedFilter2 * (1 - mask);
        shapeLight2 *= dot(processedMask, _ShapeLightMaskFilter2);
    }

    half4 shapeLight2Modulate = shapeLight2 * _ShapeLightBlendFactors2.x;
    half4 shapeLight2Additive = shapeLight2 * _ShapeLightBlendFactors2.y;
#else
    half4 shapeLight2Modulate = 0;
    half4 shapeLight2Additive = 0;
#endif

#if USE_SHAPE_LIGHT_TYPE_3
    half4 shapeLight3 = SAMPLE_TEXTURE2D(_ShapeLightTexture3, sampler_ShapeLightTexture3, lightingUV);

    if (any(_ShapeLightMaskFilter3))
    {
        half4 processedMask = (1 - _ShapeLightInvertedFilter3) * mask + _ShapeLightInvertedFilter3 * (1 - mask);
        shapeLight3 *= dot(processedMask, _ShapeLightMaskFilter3);
    }

    half4 shapeLight3Modulate = shapeLight3 * _ShapeLightBlendFactors3.x;
    half4 shapeLight3Additive = shapeLight3 * _ShapeLightBlendFactors3.y;
#else
    half4 shapeLight3Modulate = 0;
    half4 shapeLight3Additive = 0;
#endif

    half4 finalOutput;
#if !USE_SHAPE_LIGHT_TYPE_0 && !USE_SHAPE_LIGHT_TYPE_1 && !USE_SHAPE_LIGHT_TYPE_2 && ! USE_SHAPE_LIGHT_TYPE_3
    finalOutput = color;
#else
    half4 finalModulate = shapeLight0Modulate + shapeLight1Modulate + shapeLight2Modulate + shapeLight3Modulate;
    half4 finalAdditve = shapeLight0Additive + shapeLight1Additive + shapeLight2Additive + shapeLight3Additive;
    finalOutput = _HDREmulationScale * (color * finalModulate + finalAdditve);

    half luminance = max(finalModulate.r, max(finalModulate.g, finalModulate.b));
    finalOutput.a = min(luminance * 2, color.a);
#endif

    finalOutput = finalOutput *_UseSceneLighting + (1 - _UseSceneLighting)*color;
    return max(0, finalOutput);
}
#endif

他添加的部分是从half luminance....开始的最后一部分

将它们复制到您自己的文件后,您可以使用.shader 文件将其添加到材质中,然后将其应用到您想要在阴影中消失的对象。因此,如果光线照射到物体上,它会出现,但随着光源越来越接近该物体,它会逐渐出现,唯一的缺点是游戏中必须有一个光源,以便它可以用来计算亮度,否则对象将默认恢复为 1 的亮度,这意味着完全可见。但是,我认为如果你想让一个物体消失在阴影中,那么你很可能会使用光源。看起来是这样的:

当然,您可以使用光源和强度来获得您想要的结果。

如果您有任何问题,我想您可以发表评论或其他内容,我会在看到评论后提供帮助。

【讨论】:

  • 此解决方案是否适合移动设备?
  • @Doh09 tbh 我从未尝试过,但它应该适用于高端手机,因为这只适用于启用通用管道的情况。因此,无法支持 2D 光渲染的旧手机将无法支持此功能。但是,嘿,试用永远不会受到伤害,所以像测试项目一样尝试它并将其部署到手机上并试用。
  • 我在手机上使用它。未检测到 fps 下降。
  • 哦,很高兴听到@amira
【解决方案2】:

您可以尝试使用目标排序层和 alpha 混合找到解决方案。

我的意思是确保手电筒将部分显示的对象不重叠,除非该特定光源正在显示它。有点像下面的示例图片。

Click here to read more.

我认为否则必须使用遮罩或着色器来完成。我曾经在 3D 环境中做过类似的事情,但从未在 2D 环境中做过,请参阅此解决方案以获得可能的灵感:unity3d trouble with ship floating on water

我的建议是更多地研究 2D 着色器,看看您是否可以通过这种方式找到解决方案。

【讨论】:

  • 谢谢你,我确实尝试了排序层,它只是创建了一个黑色的角色版本。但我没有尝试使用 Alpha Blending,所以我现在会尝试一下,我会回复你。
  • 我查看了您分享的内容,但它仍然没有任何作用。至于“漂浮在水面上的船”的帖子,我真的不太了解,我对着色器不太了解。我一直在研究 2D 着色器,但仍然一无所获。你知道是否可以在 2D 着色器中检测阴影吗?我试图调查,但找不到任何东西。 @Doh09
  • 据我所知,着色器可以使用纹理信息来更改显示的内容。我在着色器编程方面没有做太多的事情,因为这与游戏逻辑的制作方式有点不同,但我确实看到它用于类似于您的需求的目的。 Unity 有一个名为 Shadergraph 的工具,旨在简化着色器的制作。例如查看这个视频:m.youtube.com/watch?v=5dzGj9k8Qy8 我还可以补充一点,我曾经实现了一个 3d 着色器,它可以根据世界坐标部分隐藏一个角色。
  • 在船的例子中,有一个“镜头”透过水面,见底部截图。我相信有可能制作一个类似的 2d 镜头,手电筒就是镜头。这样玩家可以被隐藏,但如果镜头在他上方,他就会被显示出来。船舶示例所做的是影响为镜头所在屏幕的特定部分渲染像素的顺序。这可能也是您需要的。请注意 2d 有图层,也许您也可以使用这些图层。
  • 我看了你发来的视频,谢谢你。与 Brackeys 所做的一样,是否可以获取有关材质/播放器的光线信息并使用它,以便如果他身上有一定量的光线,则增加该部分的 alpha。但是,其他部分只是相应地减少了 alpha。所以我想我想说的是有没有办法在播放器上获得光信息或亮度? @Doh09
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
  • 2016-05-29
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多