[ShaderStaff] 圆角矩形效果实现
操作系统:Windows8.1
显卡:Nivida GTX965M
开发工具:Unity2017.3 | Shader
最近在制作一款APP,其中需要对矩形图片资源的展现进行圆角化,看了一下网上的方案大多是基于正方形,然而在实际场景中,需要圆角化的图片往往还包括矩形,即宽高不相等,如果用技术参数来解释,便是 width 和 height 的 aspect 非 1。所以本文将会简要说明如何实现矩形圆角化Shader。
首先看下效果组图。

通过图示我们观察到,常规的基于正方形体的圆角化效果基本符合我们预期,即当半径达到 0.50 最大值的时候变成了圆形。除此之外,长方形虽然围绕Y方向进行了一定程度的拉伸 (在这里高度为宽度的2倍),但算法对中心点进行了修正,最终确保了正确的圆角化效果。
Basic Conception
效果已经看完了,那么如何设计实现呢,我们在这里将圆角化分两个部分阐述原理。首先了解基于正方形的圆角化思路。如下图所示,如果选择上下左右四个角作为圆角化目标,则分别需要按照上下左右四个圆形区域进行mask渲染,最终只保留图示中绿色区域及黄色区域。如下图所示,当 半径 r = 0.25 时及 r = 0.5 时圆角化处理后的保留渲染区域,特别的当r= 0.5时可以联想四个角度区域的原型发生了重叠。

在继续深入讨论实现之前,我们温习一下UV坐标系,这是在贴图采样过程中遵循的坐标系,具体如下图所示:

UV坐标范围是收敛在 [0, 1] 之间,如果当前UV坐标是 (0.1, 0.1) 取得颜色值是绿色,如果当前UV坐标是 (0.2, 0.8) 取得颜色值就是粉色,如果当前UV值是 (0.7, 0.2) 取得颜色值就是蓝色,如果当前UV值是 (0.9, 0.9) 取得颜色值就是黄色。如果要索取更多的信息可以进入 WIKI咨询。
搞清概念后,我们只需要简单的在Shader中针对四个方向分别定义圆点,并根据圆点坐标及半径来判断当前UV是否在圆半径范围内,如果在圆半径范围内应用采样,反之填充透明色或者丢弃当前片元。几个主要代码片段如下:
在shader中定义新的变量用于保存自定义半径信息,在这里默认为0.25:
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Radius ("_Radius", Range(0, 0.5)) = 0.25
}
同时片段着色器编写主要判定逻辑,如下:
fixed4 frag (v2f i) : SV_Target
{
// UV采样数据
fixed4 col = tex2D(_MainTex, i.uv);
// 用于保存像素与圆心距离
half dist = 0;
// 默认圆心坐标
half2 center = half2(0, 0);
// 默认右上角圆心坐标
half2 TRC = half2(1, 1);
// 默认右下角圆心坐标
half2 BRC = half2(1, 0);
// 默认左下角圆心坐标
half2 BLC = half2(0, 0);
// 默认左上角圆心坐标
half2 TLC = half2(0, 1); // 根据输入半径修正右上角圆心坐标
center = half2(TRC.x - _Radius, TRC.y - _Radius);
if (true)
{
// 判定当前UV是否在圆外侧
if (center.x < i.uv.x && center.y < i.uv.y)
{
// 计算当前UV点与圆心距离
dist = sqrt(
pow(center.x - i.uv.x, 2)
+
pow(center.y - i.uv.y, 2)
); // 将距离与圆半径比较,如果不在范围内,丢弃该片段
if (dist > _Radius)
{
discard;
}
}
} return col;
}
该代码已经在注释中描述的比较清晰了,没有说清楚的是一个 if (true) 语句,该语句用于通过外部传递的信息决定是否对当前角进行圆角化处理。主要更新代码如下:
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Radius ("_Radius", Range(0, 0.5)) = 0.25 [MaterialToggle] _TR ("_TopRightCorner", Float) = 1
[MaterialToggle] _BR ("_BottomRightCorner", Float) = 1
[MaterialToggle] _BL ("_BottomLeftCorner", Float) = 1
[MaterialToggle] _TL ("_TopLeftCorner", FLoat) = 1
}
将开关变量分别替换掉 if(true) 后运行程序,如果一切顺利,运行效果如下图所示。

通过图示我们看到已经可以通过编辑材质来控制图片资源的圆角显示规则了。
Rectangle implementation
矩形的圆角化功能是基于上文正方形圆角化功能扩展的,所谓扩展的点就在于利用非 1 : 1 的宽高比进行已有算法实现的修正,看起来有点难以理解,没有关系,我们看代码说话。
// 修正圆心X坐标位置
half sfx0 = 1;
// 修正UV点与圆心距离
half sfx1 = 1;
// 修正圆心Y轴坐标位置
half sfy0 = 1;
// 修正UV点与圆心距离
half sfy1 = 1; // 当矩形的width > height 时计算圆心、UV修正系数
if (_scale.x > _scale.y)
{
// 计算UV坐标空间下,圆心X坐标对应缩放系数
sfx0 = _scale.y/_scale.x;
sfx1 = (_scale.y/ pow(_scale.x,2));
}
else
{
// 计算UV坐标空间下,圆心Y坐标对应缩放系数
sfy0 = _scale.x/_scale.y;
sfy1 = (_scale.x/ pow(_scale.y,2));
}
同时圆角化用于计算圆心到UV采样点的距离需要根据缩放的比例进行调整,具体代码如下。
center = half2((_TRC.x - (_Radius * sfx0)),(_TRC.y - (_Radius * sfy0) ));
if (_TR == 1 )
{
if (center.x < IN.texcoord.x && center.y < IN.texcoord.y)
{
dist = sqrt( pow( center.x - IN.texcoord.x , 2 ) / sfx1 + pow( center.y - IN.texcoord.y , 2 ) / sfy1); if (dist > _Radius)
{
discard;
}
}
}
如果一些顺利,将该部分修改更新到四个圆角计算部分,最后通过外部传递参数控制即可,在这里以Unity3D材质编辑属性为例,输入图片资源的缩放比例即可。

Summary
整体的实现思路还是比较清晰的,在实际使用中如果结合UGUI的ScrollView子元素,可能出现遮罩的问题,只要将模版缓冲区相关的Shader设置代码补全即可。
[ShaderStaff] 圆角矩形效果实现的更多相关文章
- 不使用border-radius,实现一个可复用的高度和宽度都自适应的圆角矩形
现在css3支持圆角矩形,但是为了兼容性问题,虽然比较麻烦,但还是有必要了解一下以下方法. 在一个div内,包含8个div,控制这个8个div的height.margin以及border属性值,以达到 ...
- C# vb .net实现圆角矩形特效滤镜
在.net中,如何简单快捷地实现Photoshop滤镜组中的圆角矩形效果呢?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第 ...
- Android中实现圆角矩形及半透明效果。
注:本文由Colin撰写,版权所有!转载请注明原文地址,谢谢合作! 在做Android开发时,我们为了美观,有时候需要使用圆角矩形,或半透明之类的效果,在网页设计中很容易实现.但在Android开发中 ...
- [BOT] 一种android中实现“圆角矩形”的方法
内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角.思路是利用"Xfermode + Path"来进行 ...
- 一行实现QQ群组头像,微信群组,圆角等效果. 并支持url直接加载图片
说点题外话. Coding中我们总是经历着这么几个过程. 学会使用: 不管是API也好, 开源库也好. 总是在最开始的学会去用. 了解实现原理: 可能会因为一些不兼容, 代码的异常状态的处理不够完美等 ...
- RoundedImageView,实现圆形、圆角矩形的注意事项
RoundedImageView是gitHub上面的一个开源组件(https://github.com/vinc3m1/RoundedImageView),实现一些圆形或者圆角矩形是很方便的, < ...
- Android圆角矩形创建工具RoundRect类
用于把普通图片转换为圆角图像的工具类RoundRect类(复制即可使用): import android.content.Context; import android.graphics.Bitmap ...
- 解读Unity中的CG编写Shader系列四(unity中的圆角矩形shader)
转自 http://www.itnose.net/detail/6097625.html 上篇文章中我们掌握了表面剔除和剪裁模式 这篇文章将利用这些知识实现一个简单的,但是又很常用的例子:把一张图片做 ...
- Android利用canvas画各种图形(点、直线、弧、圆、椭圆、文字、矩形、多边形、曲线、圆角矩形) .
1.首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, ...
随机推荐
- iOS笔记之AutoresizingMask
在 UIView 中有一个autoresizingMask的属性,它对应的是一个枚举的值(如下),属性的意思就是自动调整子控件与父控件中间的位置,宽高. enum { UIViewAutoresi ...
- 活字格企业Web应用生成器荣获"2017年度优秀软件产品"
日前,中国软件行业协会权威发布"2017年度优秀软件产品"名单,活字格企业 Web 应用生成器凭借产品的独特优势,和近年来在企业Web应用方面的杰出贡献,位列其中,受到用户和行业专 ...
- .net常用正则表达式小结
好久没有些博客了,今天就随便写点工作当中遇到的一些问题.正则表达式估计大家在开发的过程中都会遇到,下面是我平时用到的以及自己整理的一些常用的正则表达式,供大家学习和参考. "^\d+$&qu ...
- PyalgoTrade 交易(五)
我们继续采取简单的策略,这次模拟实际交易.这个想法很简单: 如果调整后的收盘价高于SMA(15),我们将进入多头仓位(我们下单买入市价). 如果调整后的收盘价低于SMA(15),我们退出多头头寸(我们 ...
- vue中assets和static的区别
Vue中assets和static的区别 再一次框架定型中,与同事在静态资源的存放上有了一些分歧,后来经过查阅总结如下: 相同点: assets和static两个都是存放静态资源文件.项目中所需要 ...
- 【Beanstalkd】Beanstalkd消息队列的安装与使用
一.Beanstalkd是什么? Beanstalkd是一个高性能,轻量级的分布式内存队列 二.Beanstalkd特性 1.支持优先级(支持任务插队)2.延迟(实现定时任务)3.持久化(定时把内存中 ...
- mysql having,group by查询去除重复记录
http://m.jb51.net/article/39302.htm 可以这样去理解group by和聚合函数 http://www.cnblogs.com/wuguanglei/p/4229938 ...
- bzoj 1002 [FJOI2007]轮状病毒——打表找规律
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1002 看 Zinn 的博客:https://www.cnblogs.com/Zinn/p/9 ...
- "WannaCry"勒索病毒用户处置指南
"WannaCry"勒索病毒用户处置指南 原文: http://mp.weixin.qq.com/s/ExsribKum9-AN1ToT10Zog 卡巴斯基,下载官网:h ...
- Oracle SYS_CONTEXT用法
1. USERENV(OPTION) 返回当前的会话信息. OPTION='ISDBA'若当前是DBA角色,则为TRUE,否则FALSE. OPTION='LANGUAGE'返回数据库的字符集. OP ...