Unity3D - 用于 Sprite 剪辑的着色器

标签 unity3d shader sprite 2d-games

我正在尝试创建一个可用于在游戏中剪辑 2D Sprite 的着色器,我在 another question 中找到了这个着色器。

Shader "Sprites/ClipArea"
{
Properties
{
    _MainTex ("Base (RGB), Alpha (A)", 2D) = "white" {}
    _Length ("Length", Range(0.0, 1.0)) = 1.0
    _Width ("Width", Range(0.0, 1.0)) = 0.5
 }

SubShader
{
    LOD 200

    Tags
    {
        "Queue" = "Transparent"
        "IgnoreProjector" = "True"
        "RenderType" = "Transparent"
    }

    Pass
    {
        Cull Off
        Lighting Off
        ZWrite Off
        Offset -1, -1
        Fog { Mode Off }
        ColorMask RGB
        Blend SrcAlpha OneMinusSrcAlpha

        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include "UnityCG.cginc"

        sampler2D _MainTex;
        float4 _MainTex_ST;
        float _Length;
        float _Width;

        struct appdata_t
        {
            float4 vertex : POSITION;
            float2 texcoord : TEXCOORD0;
        };

        struct v2f
        {
            float4 vertex : POSITION;
            float2 texcoord : TEXCOORD0;
        };

        v2f vert (appdata_t v)
        {
            v2f o;
            o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
            o.texcoord = v.texcoord;
            return o;
        }

        half4 frag (v2f IN) : COLOR
        {
            if ((IN.texcoord.x<0) || (IN.texcoord.x>_Width) || (IN.texcoord.y<0) || (IN.texcoord.y>_Length))

            {
                half4 colorTransparent = half4(0,0,0,0) ;
                return  colorTransparent ;
            }
            return tex2D(_MainTex, IN.texcoord);
        }
        ENDCG
    }
}
}

它在单个 Sprite 上完美运行,但我使用的是由 Unity Sprite 编辑器划分的 Sprite 表。

着色器中的 _Width 变量覆盖了整个 Sprite 表,而不是我正在处理的 Sprite 。我搜索了一种在着色器中获取当前 Sprite 矩形的方法,但找不到任何东西。

最佳答案

好吧,在拉我的头发三天后,我设法找到了解决方法。
在搜索了有关着色器如何工作以及在管道中的作用的更多信息后,我意识到由于一个简单的原因,着色器中的 Sprite 矩形信息可能不可用,几乎所有着色器(除了我的)的功能都不需要此信息,因为着色器的工作是取一个顶点,通过顶点函数修改它的位置(如果需要),然后通过片段函数决定它的像素颜色,它不关心整个 Sprite ,它只需要查找像素使用纹理坐标为纹理中的某个顶点设置颜色。
我确信这对于在着色器中工作的人来说是微不足道的信息,但我花了一些时间才意识到这一点(这是我的第一个着色器)。
因此,作为一种解决方法,我必须使用着色器属性来传递着色器在 Sprite 表中正在处理的当前 Sprite 的 MinX 和 MaxX,因此着色器现在看起来像这样:

Shader "Sprites/ClipArea"
{
    Properties
    {
        _MainTex ("Base (RGB), Alpha (A)", 2D) = "white" {}
        _Fill ("Fill", Range(0.0, 1.0)) = 1.0
        _MinX ("MinX", Float) = 0
        _MaxX ("MaxX", Float) = 1
     }

    SubShader
    {
        LOD 200

        Tags
        {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
        }

        Pass
        {
            Cull Off 
            Lighting Off
            ZWrite Off
            Offset -1, -1
            Fog { Mode Off }
            ColorMask RGB
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _MinX;
            float _MaxX;
            float _Fill;

            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0; 
            };

            struct v2f
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
            };

            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.texcoord = v.texcoord;
                return o;
            }

            half4 frag (v2f IN) : COLOR 
            {
            if ((IN.texcoord.x<_MinX)|| (IN.texcoord.x>(_MinX+_Fill*(_MaxX-_MinX))))
                {
                    half4 colorTransparent = half4(0,0,0,0) ;
                    return  colorTransparent ;
                }
                return tex2D(_MainTex, IN.texcoord);
            }
            ENDCG
        }
    }
} 

要使用此着色器,您需要创建一个使用它的 Material ,然后在 SpriteRenderer 中使用该 Material ,您可以从检查器中更改填充量、MinX 和 MaxX,或调用 spriteRenderer.material.setFloat(property, value ) 来自代码。

然后我遇到了动画 Sprite 的另一个问题,我必须在每一帧上不断更新 MinX 和 MaxX,但是当我在 Update 函数中这样做时,动画开始闪烁,那是因为在渲染 Sprite 之后调用了更新,所以我不得不使用 Main Camera OnPreRender 事件来更新 Material 属性。

也许有更好的方法来实现这一切,但这是我能想到的最好的方法,我希望这对尝试实现相同效果的人有益。

关于Unity3D - 用于 Sprite 剪辑的着色器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23165899/

相关文章:

android - unity3d中实现Android 6.0权限

c# - 停止碰撞值并重新生成对象

c++ - HLSL 着色器显示有线颜色

c# - 为什么我的角色/相机在 Unity 2d 中卡顿?

android - fragment 着色器未针对 Android 源代码末尾的随机符号进行编译

opengl - Cocoa 和 OpenGL,如何使用数组设置 GLSL 顶点属性?

java - 共享 Eclipse Java 项目

javascript - 用于动态着色路径的 SVG 系统 (Cordova)

android - 如何在 Android 上使 Sprite 的背景透明?

android - 如何使用新更新的 Google Play 游戏玩家 ID 检索 Google Play 游戏 ID?