解读Unity中的CG编写Shader系列四(unity中的圆角矩形shader)
转自 http://www.itnose.net/detail/6097625.html
上篇文章中我们掌握了表面剔除和剪裁模式
这篇文章将利用这些知识实现一个简单的,但是又很常用的例子:把一张图片做成圆角矩形
例3:圆角矩形Shader
好吧我承认在做这个例子的时候走了不少弯路,由于本人对矩阵的知识掌握已经悉数还给老师,所以一开始用了一些笨办法计算圆角矩形区域。
我们知道TEXTCOORD0是一个以对象为坐标系的坐标,并且范围在该坐标的第一象限,取值为(0,0)到(1,1)
那么我们把每一张图片都看做一张1X1大小的矩形
我们要在1X1大小的矩形中擦除4个角,应该是这样:
以左上角为例,我们做一个辅助圆内切于这个角,半径为0.1,那么我们将这个圆擦掉3/4,剩下的黄色弧线与这个角形成的区域就是我们要擦除的区域:
这个道理很简单,那么我们对4个角分别擦除掉这样的区域就能得到一个半径为10%原图尺寸的圆角矩形
我一开始走的弯路就在于计算这个区域,是用4个圆的方程来算呢还是用距离来计算
由于给出4个圆的方程太过于复杂,我这里直接给出计算外点距离算法的示意图:
首先在这个大矩形的内部以4个圆心为顶点做出一个内矩形,心算得边长为0.8
其次忽略内矩形内部的点,在这个红色矩形内给定任意一个蓝色矩形的外点p ,只要能够得到p到蓝色矩形的距离,距离大于0.1(半径),那么就在圆角矩形外部,直接擦除,如图:
我们看p1,p2,p3,3个点到蓝色矩形的距离分别是p1的距离<半径,根号2倍半径>p2的距离>半径,p3的距离等于半径
所以p2在圆角矩形外,p1,p3在圆角矩形内部或边缘,我们将p2擦除掉
其中p3的距离恰好是 p3到4条直线的距离最小值
p1同理
而p2的距离不能再这样计算,而应该是计算p2到4个顶点距离的最小值
按这个算法只要算出所有外点中的点到蓝色矩形区域的距离,然后与半径判断大小,大于则discard就能得到圆角矩形
一开始我按照这个思路得出一个极端无脑的方法:
给定任意一点p,求p到4条直线,4个顶点的距离,然后在8个距离中求最小值作为最终的距离拿来与半径比较
兴奋地写完代码知道我错了,检查了很久才明白,像p3这种点,算出来的8个距离中,最小距离并不是到顶点的距离,而是到两条边的延长线的距离
于是最终8距离求最小值算法以失败告终
还是得老老实实分情况
那么有几种情况呢
其实只有1种,但是先按正常逻辑分为2种:
我们来看绿色区域和紫色区域的外点们
1、当外点在紫色区域时,距离应是点到4顶点的距离最小值
2、当外点在绿色区域时,距离应是点到4条直线的距离最小值
按照这个思路那么我们可以对整个 坐标系内的任意点(x,y)进行判断:
1、如果点在白色区域或者绿色区域内, 还计算个毛线距离啊,肯定是不discard啊~~~~(之前我傻乎乎的还真去算了)
2、紫色区域内计算点到4顶点距离,然后取最小值,然后将大于0.1的部分剔除掉
最后我们需要将这个0.1作为变量提取出来,不能写死,这样可以在Inspector中方便调节,或者在script中去设置,也就是给我们的shader定义一个float或rang型的属性
最后代码为:
Shader "Custom/RoundRect" {
Properties {
//两种内容模式,图片模式
_MainTex ("Base (RGB)", 2D) = "white" {}
//纯色模式
//_MainColor ("Color", COLOR) = (1,1,1,1)
//圆角半径,默认为0.1
_RoundRadius("Radius",float) = 0.1
}
SubShader { Pass{
CGPROGRAM #pragma fragment frag #include "UnityCG.cginc"
//获取3个属性 并传值到CG代码段
sampler2D _MainTex;
float _RoundRadius;
float4 _MainColor; //片段着色器输入结构体(可省略)
struct FragInput{
float2 texcoord:TEXCOORD0; }; //片段着色器入口函数
float4 frag(FragInput input) : COLOR
{ float4 c=tex2D(_MainTex,input.texcoord);//将图片信息按坐标转换成颜色
//float4 c=_MainColor; //纯色 //x,y两个变元,区间均为[0,1]
float x=input.texcoord.x;
float y=input.texcoord.y; //4条直线的常数部分
float xt=1-_RoundRadius;
float xb=_RoundRadius;
float yl=_RoundRadius;
float yr=1-_RoundRadius;
//如果(x,y)不在4条直线构成的矩形中(上图的白色区域)
if(!(x<xt&&x>xb&&y>yl&&y<yr))
{ //如果(x.y)不在上图的绿色区域
if(!((x<xt&&x>xb) || (y>yl&&y<yr) ))
//数学不好,好像判断的复杂了,如果您可以直接写出紫色区域
//的不等式组那么可以简单点
{
//计算四个顶点的坐标
float2 plb=float2(_RoundRadius,_RoundRadius);
float2 plt=float2(_RoundRadius,1-_RoundRadius);
float2 prt=float2(1-_RoundRadius,1-_RoundRadius);
float2 prb=float2(1-_RoundRadius,_RoundRadius); //计算x,y分别到4个顶点的距离
float distlb=sqrt(pow((x-plb.x),2)+pow((y-plb.y),2));
float distlt=sqrt(pow((x-plt.x),2)+pow((y-plt.y),2));
float distrt=sqrt(pow((x-prt.x),2)+pow((y-prt.y),2));
float distrb=sqrt(pow((x-prb.x),2)+pow((y-prb.y),2)); //对4个距离取最小值
float dist=min(distlb,distlt);
dist=min(dist,distrt);
dist=min(dist,distrb); //将大于半径的表面剔除
if(dist>_RoundRadius)
discard; } } return c; }
ENDCG
} }
FallBack "Diffuse"
}
最后运行的效果,不同Radius不同尺寸的图片进行圆角矩形剔除
当radius设为0.25时我们可以得到一个圆,所以我们的RoundRadius属性可以设置为一个0.01~0.25的rang
由于我是windows系统,mac os下好像有点问题,不知道是不是省略了顶点着色器的问题,发现原因后再来补正
解读Unity中的CG编写Shader系列四(unity中的圆角矩形shader)的更多相关文章
- [转]解读Unity中的CG编写Shader系列7——漫反射
如果前面几个系列文章的内容过于冗长缺乏趣味着实见谅,由于时间原因前面的混合部分还没有写完,等以后再补充,现在开始关于反射的内容了.折射与反射在物理世界中,光的反射与折射往往是同时存在的,光源由真空或者 ...
- 解读Unity中的CG编写Shader系列4——unity中的圆角矩形shader
上篇文章中我们掌握了表面剔除和剪裁模式 这篇文章将利用这些知识实现一个简单的,可是又非经常常使用的样例:把一张图片做成圆角矩形 例3:圆角矩形Shader 好吧我承认在做这个样例的时候走了不少弯路,因 ...
- [转]解读Unity中的CG编写Shader系列4——unity中的圆角矩形shader
上篇文章中我们掌握了表面剔除和剪裁模式这篇文章将利用这些知识实现一个简单的,但是又很常用的例子:把一张图片做成圆角矩形 例3:圆角矩形Shader好吧我承认在做这个例子的时候走了不少弯路,由于本人对矩 ...
- 解读Unity中的CG编写Shader系列八(镜面反射)
转自http://www.itnose.net/detail/6117378.html 讨论完漫反射之后,接下来肯定就是镜面反射了 在开始镜面反射shader的coding之前,要扩充一下前面提到的知 ...
- [转]解读Unity中的CG编写Shader系列9——镜面反射
讨论完漫反射之后,接下来肯定就是镜面反射了在开始镜面反射shader的coding之前,要扩充一下前面提到的知识,加深理解镜面反射与漫反射的区别.注:这篇文章实现的镜面反射是逐顶点着色(per-ver ...
- unity 切圆角矩形 --shader编程
先上个效果图 制作思路 如上图我们要渲染的就是上图带颜色的部分 步骤: 先获取黄色和蓝绿部分 例如以下图 算法 |U|<(0.5-r)或|V|<(0.5-r) 注意的是模型贴图最大值是1. ...
- 圆角矩形shader
在游戏中,有时需要对一张矩形图片进行切割,绘制成圆角矩形. circelrect.vert attribute vec4 a_position; attribute vec4 a_normal; at ...
- 解读Unity中的CG编写Shader系列十 (光滑的镜面反射(冯氏着色))
前文完成了最基本的镜面反射着色器,单平行光源下的逐顶点着色(per-vertex lighting),又称为古罗着色(Gouraud shading).这篇文章作为后续讨论更光滑的镜面反射方式,逐像素 ...
- 解读Unity中的CG编写Shader系列七(不透明度与混合)
转自http://www.itnose.net/detail/6098539.html 1.不透明度 当我们要将两个半透的纹理贴图到一个材质球上的时候就遇到混合的问题,由于前面的知识我们已经知道了片段 ...
随机推荐
- WinSCP 连接 Ubuntu 拒绝的问题
1.打开配置文件 $ sudo vi /etc/ssh/sshd_config 2.修改操作 PermitRootLogin without-password 修改为 PermitRootLogin ...
- js中的全局变量和静态变量的使用, js 的调试?- 如果js出错, js引擎 就会停止, 这会 导致 后面的 html中 refer 该函数时, 会报错 函数为定义!!
效果里面的函数, 如show, hide,slideDown等, 这些都叫 "效果"函数, 但是里面可以包含动画, 也可以 不包含动画. 动画,是指 元素 的内容 是 逐渐 显示/ ...
- GOF业务场景的设计模式-----观察者模式
定义:定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新. 在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出 ...
- 开始使用 Markdown
(Xee:我最近感觉nyfedit打开有点慢,数据库有点大,试想着用一些其他的方式记录一下学习的过程,才想起了遗忘了很长时间的Markdown,将其分类在HTML下,也是我原本意愿的...) 本文面向 ...
- C#集合类图继承关系一览表
- 未能从程序集“System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”中加载类型“System.ServiceModel.Activation.HttpModule”。
********************************* 思路壹(也是网络上铺天盖地的通俗解决方案) 原因: 这是因为先安装了 .NET Framework , 随后启用了 .NET Fra ...
- 2013长沙 G Graph Reconstruction (Havel-Hakimi定理)
Graph Reconstruction Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge Let there ...
- ThinkPHP魔术方法
我们在使用thinkphp开发系统的时候,有时候会用到getById('1')这个方法快速的获取一条信息的内容,比用where(" id =1 ")->find();好用多了 ...
- 将json返回的日期格式转换
<script> function ChangeDateFormat(cellval) { var date = new Date(parseInt ...
- ajax状态
ajax的几个状态 Uninitialized 初始化状态.XMLHttpRequest 对象已创建或已被 abort() 方法重置. Open open() 方法已调用,但是 send() 方法未调 ...