• 【UnityShader】图片圆角


    1.需求

            我们在开发的时候,有时候一些按钮或者菜单栏的边角是直角的需要改成圆角,但是让美术重新绘制耽误时间不说也确实没必要,这个时候我们不妨使用一个简单的shader去解决这个问题,下面我们就讲讲这个shader要如何实现。

    需求1:可以将图片四角任意一角从直角变为圆角,可控制圆角大小

    需求2:在需求一的基础上可以选择是否给图片加上边框,颜色可变

    附加小需求:可更改图片透明度

    2.实现

    2.1. 准备

            在实现之前,除此了解shader的同学可以去了解一下unity内置的一些shader变量和函数,熟悉了这些变量和函数的含义,对我们实现一个shader有很大的帮助。

    【UnityShader预备知识】内置变量和函数

    2.1.1.Tags

    我们先了解一些需要使用的Tags:

    1. Tags
    2. {
    3. "Queue" = "Transparent"
    4. "IgnoreProjector" = "True"
    5. "RenderType" = "Transparent"
    6. "PreviewType" = "Plane"
    7. "CanUseSpriteAtlas" = "True"
    8. }

    这些是Unity Shader标签,用于指定渲染顺序、忽略投影、渲染类型以及预览方式。其中,“Transparent”表示该Shader将被渲染在所有不透明物体之后,因此适合用作UI元素或半透明物体的材质。如果你想让这个Shader按照标准的渲染顺序进行渲染,可以去掉“Transparent”标签并将“Queue”改为“Geometry”。

    另外,“CanUseSpriteAtlas”允许该Shader使用精灵图集,这对于使用多个精灵制作复杂的图形很有用。如果你想让Shader支持精灵图集,请确保你的项目中已经启用了相应的功能。

    2.1.2.Stencil

    接下来我们再看一下模板缓冲区Stencil Buffer如何设置:

    1. Stencil
    2. {
    3. Ref[_Stencil]
    4. Comp[_StencilComp]
    5. Pass[_StencilOp]
    6. ReadMask[_StencilReadMask]
    7. WriteMask[_StencilWriteMask]
    8. }
    • Stencil Buffer(模板缓冲区)是一个与颜色缓冲区和深度缓冲区类似的额外缓冲区,可用于记录每个像素是否被绘制过。当启用模板测试时,只有满足特定条件的像素才会被绘制。
    • Ref[_Stencil]指定了模板缓冲区的参考值,即只有当模板值等于该值时才绘制。
    • Comp[_StencilComp]指定了模板比较函数,例如等于、不等于、小于等等。
    • Pass[_StencilOp]指定了当模板测试失败时的操作,例如替换为Ref[_Stencil]或其他值。
    • ReadMask[_StencilReadMask]和WriteMask[_StencilWriteMask]分别指定了读取和写入模板缓冲区的掩码。

    2.1.3.基础设置

    shader中需要对光照、深度等进行一些设置,比如:

    1. Cull Off //关闭了背面剔除,使得物体的正面和背面都可以被渲染。
    2. Lighting Off //关闭了光照计算,这意味着不会对物体表面产生光照影响。
    3. ZWrite Off //关闭了深度写入,使得物体不会影响场景的深度信息。
    4. ZTest[unity_GUIZTestMode] //指定了深度测试模式,对于GUI元素通常使用LessGreater模式。
    5. Blend SrcAlpha OneMinusSrcAlpha //启用了混合模式,用于控制透明度。
    6. ColorMask[_ColorMask] //控制哪些颜色通道会被写入,通常用于控制透明度。

    这些设置关闭了背面剔除、光照计算、深度写入,并开启了混合模式,同时还设置了颜色掩码。这通常是用于渲染UI元素的标准设置。其中,Cull Off表示不剔除任何面,Lighting Off表示不进行光照计算,ZWrite Off表示不写入深度缓冲区,ZTest[unity_GUIZTestMode]表示使用Unity GUI的特殊深度测试模式,Blend SrcAlpha OneMinusSrcAlpha表示开启混合模式,使得透明度能够正确显示,ColorMask[_ColorMask]则控制哪些颜色通道会被写入。如果你希望对这些设置进行自定义,可以在Shader中添加相应的标签。

    2.2.功能实现思路

    2.2.1.直角变圆角

    如果要将一个直角变成圆角,那么首先我们得要确定这个圆角的中心点O和半径r,然后将图片超出半径范围的像素进行剔除舍弃即使其alpha=0。以左下角为例:

    1. //左下角
    2. if (x < r && y < r)//x和y分别是当前像素的UV坐标
    3. {
    4. anc_size = (x - r) * (x - r) + (y - r) * (y - r);
    5. if (anc_size > r * r)
    6. {
    7. color.a = 0;
    8. }
    9. }

    首先,我们检查当前像素是否在圆角范围内,如果是,则计算其离中心点的距离(anc_size)。

    如果anc_size大于半径的平方(r*r),则说明该像素超出了圆角范围,应被舍弃。其他几个角依次类推,大家可以自己手动画一张图这样更明了一些。需要注意的是UV坐标系,左下角为(0,0),右上角为(1,1)。相信图应该都能画出来,这边我也会在下面贴出来草图以供参考。

    其他三角:

    1. //左上角
    2. if (x < r && y > (height - r))
    3. {
    4. anc_size = (x - r) * (x - r) + (y - (height - r)) * (y - (height - r));
    5. if (anc_size > r * r)
    6. {
    7. color.a = 0;
    8. }
    9. else if (edge_width > 0 && anc_size > (r - edge_width) * (r - edge_width))
    10. {
    11. color = edge_color;
    12. }
    13. }
    14. r = _EdgeCore.z;
    15. //右下角
    16. if (x > (width - r) && y < r)
    17. {
    18. anc_size = (x - (width - r)) * (x - (width - r)) + (y - r) * (y - r);
    19. if (anc_size > r * r)
    20. {
    21. color.a = 0;
    22. }
    23. else if (edge_width > 0 && anc_size > (r - edge_width) * (r - edge_width))
    24. {
    25. color = edge_color;
    26. }
    27. }
    28. r = _EdgeCore.y;
    29. //右上角
    30. if (x > (width - r) && y > (height - r))
    31. {
    32. anc_size = (x - (width - r)) * (x - (width - r)) + (y - (height - r)) * (y - (height - r));
    33. if (anc_size > r * r)
    34. {
    35. color.a = 0;
    36. }
    37. else if (edge_width > 0 && anc_size > (r - edge_width) * (r - edge_width))
    38. {
    39. color = edge_color;
    40. }
    41. }

    2.2.2.添加边框

    添加边框是什么意思,简单点说就是把图片边上一部分的颜色进行转换,有了上面进行圆角的转换,我们只要根据边框的宽度算出对应的区域范围,将此区域范围内的颜色进行更改即可,依旧以左下角为例:

    1. if (x < r && y < r)
    2. {
    3. arc_size = (x - r) * (x - r) + (y - r) * (y - r);
    4. if (arc_size > r * r)
    5. {
    6. color.a = 0;
    7. }
    8. else if (b_width > 0 && arc_size > (r - b_width) * (r - b_width))
    9. {
    10. color = b_color;
    11. }
    12. }

    在上面我们已经计算出了arc_size,如果它介于半径和半径减去边框宽度之间(即边框区域),则应用边框颜色。这里的r代表圆角半径,x和y分别是当前像素的UV坐标。你可以根据需要修改r和b_width这两个变量来改变圆角大小和边框宽度。同时,你也需要在Shader的Properties块中声明对应的属性。

    做到这里,你可能会发现你的效果是这样的:

    哎,没错,这个效果说不定也有人有需要也是一个有意思的形状,当然,这还不是完整的边框,刚刚我们只考虑了边角,没有考虑其他地方,所以我们还要对其他地方的边框进行处理:

    1. if (b_width > 0)
    2. {
    3. //下边
    4. if (x > _RCorner.w && x < (width - _RCorner.z) && y < b_width)
    5. {
    6. color = border_color;
    7. }
    8. //上边
    9. if (x > _RCorner.x && x < (width - _RCorner.y) && (height - y) < b_width)
    10. {
    11. color = border_color;
    12. }
    13. //左边
    14. if (y > _RCorner.w && y < (height - _RCorner.x) && x < b_width)
    15. {
    16. color = border_color;
    17. }
    18. //右边
    19. if (y > _RCorner.z && y < (height - _RCorner.y) && x > (width - b_width))
    20. {
    21. color = border_color;
    22. }
    23. }

    2.2.3.修改图片透明度

    修改透明度的方式很简单,就是对颜色的alpha进行修改:

    1. if (_MainTex_TexelSize.z > 0)
    2. {
    3. color = (tex2D(_MainTex, IN.texcoord)) * IN.color;
    4. }
    5. color.a= _Alpha;

    需要注意的是alpha通道要在最后进行设置,以免后面再对颜色进行修改影响其值。

    比如你只想改改边框的透明度,你就可以把这段修改放在修改边框那边。

    2.3.最终效果

    3.下载链接

    https://download.csdn.net/download/qq_35064654/89194087

  • 相关阅读:
    mysql binlog同步数据
    Spring Cloud Consul 从入门到精通
    计算机原理-寻址方式
    一图看懂Spring事务传播的本质
    关于信息安全软考的记录3
    springboot+小区公共停车位管理 毕业设计-附源码201517
    Kafka-Java四:Spring配置Kafka消费者提交Offset的策略
    驱动开发 DAY1 外部传参Makefile编写
    SD_DATA_SEND_SHIFT_REGISTER
    Netty源码剖析之线程模型
  • 原文地址:https://blog.csdn.net/qq_35064654/article/details/138001609