Unity 2D外描边Shader

这篇具有很好参考价值的文章主要介绍了Unity 2D外描边Shader。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

今天,我们来实现一个2D外描边的效果。外描边:即在边缘透明像素周围加上一层描边,不占用原来的像素。
思路:我们可以在片元着色器实现此效果,当一个像素本身不是透明的(alpha>0),那么让它返回自身的颜色;当一个像素本身是透明的,并且它上下左右4个像素的alpha值总和不等于0,那么我们可以判定该像素处于边缘,让它变成描边颜色就可以。

二、Shader内容

2.1 初版shader

好,我们根据思路来写代码

Shader "Custom/2DOutline"{
    
    Properties{
        _MainTex("Texture",2D) = "white" {}
        _OutlineWidth("OutlineWidth",Range(0,10)) = 0
        _OutlineColor("OutlineColor",Color) = (0,0,0,1)     
    }

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



        Pass{
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            Cull Off
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            
            struct appdata{
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            struct v2f{
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            
            sampler2D _MainTex;
            float4 _MainTex_ST; //获取_MainTex纹理的Tiling和Offset,带入xyzw
            float4 _MainTex_TexelSize;//获取_MainTex纹理的宽高,4个分量如下:Vector4(1 / width, 1 / height, width, height)
            
            float _OutlineWidth;
            float4 _OutlineColor;

            
            //顶点着色器不做额外操作
            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            
            //片元着色器
            half4 frag(v2f v) : SV_Target{
                fixed4 col = tex2D(_MainTex,v.uv);
                
                //获取自身alpha
                float pointAlpha = col.a;

                //获取周围上下左右4个点的UV
                float2 up_uv = v.uv + float2(0,_OutlineWidth * _MainTex_TexelSize.y);
                float2 down_uv = v.uv + float2(0,-_OutlineWidth * _MainTex_TexelSize.y);
                float2 left_uv = v.uv + float2(-_OutlineWidth * _MainTex_TexelSize.x,0);
                float2 right_uv = v.uv + float2(_OutlineWidth * _MainTex_TexelSize.x,0);

                //获取周围上下左右4个点的alpha总和
                float aroundAlpha = tex2D(_MainTex,up_uv).a +
                tex2D(_MainTex,down_uv).a + 
                tex2D(_MainTex,left_uv).a + 
                tex2D(_MainTex,right_uv).a;

                //自身alpha>0, 保持
                if(pointAlpha > 0){
                    return col;
                }

                //周围4个点的alpha>0,使用描边颜色
                if(aroundAlpha > 0){
                    return _OutlineColor;
                }
                return col;
                
            }
            ENDCG
        }
    }
    FallBack "Sprites/Default"
}

2.2 效果

unity外轮廓描边,Shader,unity,游戏引擎

2.3 分析

片元着色器按我们的思路来写,都加上了注释。
这里先讲一个有用的知识点:_MainTex_TexelSize是获取纹理宽高的内置变量。值为:Vector4(1 / width, 1 / height, width, height),我们使用了此变量来帮助我们获取到周围的uv

可以看到我们实现了描边的效果,但是可以看到在描边层和自身层之间好像还隔着一层透明的像素,如下图。这是因为在图片边缘的像素,他们本身的像素接近透明,alpha值比较小,但也大于0,因为我们做了if alpha>0,即保持自身像素的缘故。这一层也保持下来了。

	 //自身alpha>0, 保持
     if(pointAlpha > 0){
      	return col;
     }

unity外轮廓描边,Shader,unity,游戏引擎

2.4 优化

2.4.1 优化边缘接近透明的像素

从上面的分析中,我们可以把透明度的阈值提高一点,让边缘这层接近透明的像素也返回描边颜色;
我们可以定义一个透明度阈值变量: _AlphaThreshold(“AlphaThreshold”,Range(0,1)) = 0

 //自身alpha>_AlphaThreshold, 保持
 if(pointAlpha > _AlphaThreshold){
      return col;
  }

调整 _AlphaThreshold即可把这层接近透明的像素层也改成描边颜色
unity外轮廓描边,Shader,unity,游戏引擎

2.4.2 优化掉if

我们知道在shader里使用if会降低效率,所以我们接下来使用step和lerp函数来吧if替换掉
函数说明:
step(a,b) 当b>=a 返回1,否则返回0
lerp(a,b,progress) 在a~b之间进行插值,基于progress。我们可以传入step的值,因为step结果不是0就是1,所以返回的值不是a就是b

     			//周围的透明度step
                float arroundStep = step(0.01,aroundAlpha);
                //自身的透明度step
                float pointStep = step(_AlphaThreshold,pointAlpha);

                //先把周围和自身都改成描边颜色
                float4 result = lerp(col,_OutlineColor,arroundStep);
                //把自身原色还原
                result = lerp(result,col,pointStep);
                //返回
                return result;

效果
unity外轮廓描边,Shader,unity,游戏引擎

2.4.3 增加亮度

因为描边最好是布灵布灵bulingbuling的,所以可以调节亮度会更好一点
接下来我们简单加下变量:_Light(“Light”,Range(1,5)) =1

  				//周围的透明度step
                float arroundStep = step(0.01,aroundAlpha);
                //自身的透明度step
                float pointStep = step(_AlphaThreshold,pointAlpha);
                
                //乘上亮度值
                _OutlineColor.rgb = _OutlineColor.rgb * _Light;

                //先把周围和自身都改成描边颜色
                float4 result = lerp(col,_OutlineColor,arroundStep);
                //把自身原色还远
                result = lerp(result,col,pointStep);
                //返回
                return result;

效果
unity外轮廓描边,Shader,unity,游戏引擎

三、完整代码

到此,我们的代码就写完了。接下来附上完整的代码文章来源地址https://www.toymoban.com/news/detail-757623.html

Shader "Custom/2DOutline"{
    
    Properties{
        _MainTex("Texture",2D) = "white" {}
        _OutlineWidth("OutlineWidth",Range(0,10)) = 0
        _OutlineColor("OutlineColor",Color) = (0,0,0,1)   
        _AlphaThreshold("AlphaThreshold",Range(0,1)) = 0  
        _Light("Light",Range(1,5)) =1
    }

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



        Pass{
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            Cull Off
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            
            struct appdata{
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            struct v2f{
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            
            sampler2D _MainTex;
            float4 _MainTex_ST; //获取_MainTex纹理的Tiling和Offset,带入xyzw
            float4 _MainTex_TexelSize;//获取_MainTex纹理的宽高,4个分量如下:Vector4(1 / width, 1 / height, width, height)
            
            float _OutlineWidth;
            float4 _OutlineColor;
            float _AlphaThreshold;
            float _Light;
            
            //顶点着色器不做额外操作
            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            
            //片元着色器
            half4 frag(v2f v) : SV_Target{
                fixed4 col = tex2D(_MainTex,v.uv);
                
                //获取自身alpha
                float pointAlpha = col.a;

                //获取周围上下左右4个点的UV
                float2 up_uv = v.uv + float2(0,_OutlineWidth * _MainTex_TexelSize.y);
                float2 down_uv = v.uv + float2(0,-_OutlineWidth * _MainTex_TexelSize.y);
                float2 left_uv = v.uv + float2(-_OutlineWidth * _MainTex_TexelSize.x,0);
                float2 right_uv = v.uv + float2(_OutlineWidth * _MainTex_TexelSize.x,0);

                //获取周围上下左右4个点的alpha总和
                float aroundAlpha = tex2D(_MainTex,up_uv).a +
                tex2D(_MainTex,down_uv).a + 
                tex2D(_MainTex,left_uv).a + 
                tex2D(_MainTex,right_uv).a;
            
                //周围的透明度step
                float arroundStep = step(0.01,aroundAlpha);
                //自身的透明度step
                float pointStep = step(_AlphaThreshold,pointAlpha);
                
                //乘上亮度值
                _OutlineColor.rgb = _OutlineColor.rgb * _Light;

                //先把周围和自身都改成描边颜色
                float4 result = lerp(col,_OutlineColor,arroundStep);
                //把自身原色还远
                result = lerp(result,col,pointStep);
                //返回
                return result;
                
            }
            ENDCG
        }
    }
    FallBack "Sprites/Default"
}

到了这里,关于Unity 2D外描边Shader的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity3D Shader系列之描边

    总结下描边效果的实现方式,主要有以下几种: ①法线外拓+ZTest Always ②法线外拓+Cull Front ③法线外拓+ZWrite Off ④法线外拓+模板测试 ⑤基于屏幕后处理 法线外拓的原理如下: 基本原理还是很简单的:模型渲染两次,第一次渲染时将模型的顶点沿法线方向外拓,然后绘制描边

    2023年04月08日
    浏览(45)
  • 【实现100个unity特效】shader实现3D物品闪光和描边效果

    线状映射图片 配置,按该shader新增材质 Outline Width控制描边 Line Speed控制闪光速度 当然,还可以修改对应的颜色 效果演示 赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的 点赞评论和关注 ,以便我第一时间收到反馈,你的每一次 支持 都是我不断创作的最

    2024年01月25日
    浏览(60)
  • Unity中UI Shader遮罩RectMask2D

    Unity中UI Shader遮罩RectMask2D 当父级物体有Rect Mask 2D组件时激活. 需要先手动定义此变体#pragma multi_compile _ UNITY_UI_CLIP_RECT 同时需要声明:_ClipRect(一个四维向量,四个分量分别表示RectMask2D的左下角点的xy坐标与右上角点的xy坐标.) UnityGet2DClipping (float2 position, float4 clipRect)即可实现遮

    2024年02月07日
    浏览(48)
  • Unity游戏图形学 Shader结构

    openGL:SLG跨平台 =GLSL:openGL shaderlauguge DX:微软开发,性能很好,但是不能跨平台 =HLSL:high level shader language CG:微软和Nvidia公司联合开发,跨平台,基于c语言开发,性能很好 openGL、dx、cg都包含 CG和HLSL包括在 CGPROGRAM...ENDCG 语法快内 GLSL包括在 GLSLPROGRAM...ENDGLSL 语法快内 自己

    2024年02月01日
    浏览(40)
  • unity 2d游戏开发教程(2d战棋)

    unity 2d 游戏开发教程(2d战棋) 类似的游戏有:火焰纹章,梦幻模拟战 素材下载地址: 人物 https://brullov.itch.io/generic-char-asset 场景 https://anokolisa.itch.io/sidescroller-pixelart-sprites-asset-pack-forest-16x16 场景2:https://anokolisa.itch.io/dungeon-crawler-pixel-art-asset-pack/devlog/447513/12th-road-map-for-pi

    2024年02月13日
    浏览(51)
  • UNITY—2D游戏制作入门!

    Unity作为当今最流行的游戏引擎之一,受到各大厂商的喜爱。 像是炉石传说,以及逃离塔克夫,都是由unity引擎开发制作。 作为初学者的我们,虽然无法直接做出完成度那么高的作品,但每一个伟大的目标,都有一个微不足道的开始。让我们从一个2D小游戏入手,来学习Unit

    2024年02月04日
    浏览(52)
  • Unity——2D小游戏笔记整理

    【每日一句:清晨和夜晚都请用尽全力去生活】 目录 一、环境搭建 二、人物 三、相机跟随人物移动 四、平铺精灵 五、血条跟随敌人行走 六、脚本逻辑 【玩家行走方法】 【玩家跳跃方法】 【改变玩家血量值方法】 【创建玩家子弹方法】 【主角血量,改变血条遮罩】 【敌

    2024年02月09日
    浏览(52)
  • Unity之创建第一个2D游戏项目

    一 Unity环境配置 1.1 Untity资源官网下载:https://unity.cn/releases 1.2 Unity Hub集成环境,包含工具和项目的管理 1.3 Unity Editor编辑器 1.4 Visual Studio 2022脚本编辑器 1.5 AndroidSKD,JDK,NDK工具,用于android环境的运行 二 创建Unity项目 2.1 新建2D模板项目 2.2 新建2D物体 2.3 新建C#脚本文件 

    2024年02月04日
    浏览(47)
  • unity-2D游戏地面检测 三射线检测

        2D游戏中跳跃是不可或缺的功能,要实现跳跃功能,就必须进行地面检测!常规方法是使用一根往角色下方延伸的射线检测,但是这种方法在一些复杂不规则的地面效果通常不尽人意。通过增加射线数量,即可完善这种方法的不足,达到在复杂地面也能正确检测角色是否

    2024年02月15日
    浏览(37)
  • Unity Physics2D 2d物理引擎游戏 笔记

    2d 材质 里面可以设置 摩擦力 和 弹力 Simulated:是否在当前的物理环境中模拟,取消勾选该框类似于Disable Rigidbody,但使用这个参数更加高效,因为Disable会销毁内部产生的GameObject,而取消勾选Simulated只是禁用。 Kinematic 动力学刚体 动力学刚体不受重力和力的影响,而受用户的

    2023年04月24日
    浏览(121)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包