操作系统:Windows8.1

显卡:Nivida GTX965M

开发工具:Unity2017.3 | Shader


最近在制作一款APP,其中需要对矩形图片资源的展现进行圆角化,看了一下网上的方案大多是基于正方形,然而在实际场景中,需要圆角化的图片往往还包括矩形,即宽高不相等,如果用技术参数来解释,便是 widthheightaspect 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] 圆角矩形效果实现的更多相关文章

  1. 不使用border-radius,实现一个可复用的高度和宽度都自适应的圆角矩形

    现在css3支持圆角矩形,但是为了兼容性问题,虽然比较麻烦,但还是有必要了解一下以下方法. 在一个div内,包含8个div,控制这个8个div的height.margin以及border属性值,以达到 ...

  2. C# vb .net实现圆角矩形特效滤镜

    在.net中,如何简单快捷地实现Photoshop滤镜组中的圆角矩形效果呢?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第 ...

  3. Android中实现圆角矩形及半透明效果。

    注:本文由Colin撰写,版权所有!转载请注明原文地址,谢谢合作! 在做Android开发时,我们为了美观,有时候需要使用圆角矩形,或半透明之类的效果,在网页设计中很容易实现.但在Android开发中 ...

  4. [BOT] 一种android中实现“圆角矩形”的方法

    内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角.思路是利用"Xfermode + Path"来进行 ...

  5. 一行实现QQ群组头像,微信群组,圆角等效果. 并支持url直接加载图片

    说点题外话. Coding中我们总是经历着这么几个过程. 学会使用: 不管是API也好, 开源库也好. 总是在最开始的学会去用. 了解实现原理: 可能会因为一些不兼容, 代码的异常状态的处理不够完美等 ...

  6. RoundedImageView,实现圆形、圆角矩形的注意事项

    RoundedImageView是gitHub上面的一个开源组件(https://github.com/vinc3m1/RoundedImageView),实现一些圆形或者圆角矩形是很方便的, < ...

  7. Android圆角矩形创建工具RoundRect类

    用于把普通图片转换为圆角图像的工具类RoundRect类(复制即可使用): import android.content.Context; import android.graphics.Bitmap ...

  8. 解读Unity中的CG编写Shader系列四(unity中的圆角矩形shader)

    转自 http://www.itnose.net/detail/6097625.html 上篇文章中我们掌握了表面剔除和剪裁模式 这篇文章将利用这些知识实现一个简单的,但是又很常用的例子:把一张图片做 ...

  9. Android利用canvas画各种图形(点、直线、弧、圆、椭圆、文字、矩形、多边形、曲线、圆角矩形) .

    1.首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, ...

随机推荐

  1. 在不同的浏览器使用不同的css样式,解决浏览器兼容问题

    区别IE6与FF:       background:orange;       *background:blue; 区别IE6与IE7:       background:green !import ...

  2. 将Gridview中的数据出到excel或word中

    在以下按钮单击事件中实现:private void btnMIME_Click(object sender, System.EventArgs e){dgShow.AllowPaging = fals ...

  3. NodeJS反序列化漏洞利用

    原文来自:http://www.4hou.com/web/13024.html node.js是一个服务器端的运行环境,封装了Google V8引擎,V8引擎执行JavaScript速度非常快,性能非 ...

  4. New Concept English Two 25 67

    $课文65  小象对警察 683. Last Christmas, the circus owner, Jimmy Gates, decided to take some presents to a ...

  5. PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/phalcon.so' - /usr/lib64/php/mod

    这个警告可能是,扩展在php.d里面加载了一遍,然后又在php.ini里写了一遍导致的

  6. Javascript中的prototype与继承

    通常来说,javascript中的对象就是一个指向prototype的指针和一个自身的属性列表.javascript创建对象时采用了写时复制的理念. 只有构造器才具有prototype属性,原型链继承 ...

  7. Ethereum以太网搭建本地开放环境简明教程

    引言: 区块链技术的风起云涌预示着一个去中心化时代的来临,ethereum技术栈是目前业界最为应用广泛的基于区块链技术的技术方案,本文将记录如何基于本地环境来搭建私有区块链的开发环境. 部署私有区块链 ...

  8. 阿里云windows时间同步服务地址

    偶然发现的, 记录一下 ntp1.aliyun.com

  9. Nodejs中npm install 命令的问题

    在使用nodejs的npm包管理工具中碰到过许多个坑,在网上查了很久才解决,现在加以总结. 两种安装方式(本地安装,全局安装) 1.全局安装(npm install -g moduleName/npm ...

  10. StringUtils的工具类isBlank与isEmply

    1. public static boolean isEmpty(String str)   判断某字符串是否为空,为空的标准是 str==null 或 str.length()==0   下面是 S ...