http://blog.csdn.net/mobanchengshuang/article/details/38731035

上篇文章中我们掌握了表面剔除和剪裁模式

这篇文章将利用这些知识实现一个简单的,但是又很常用的例子:把一张图片做成圆角矩形

例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型的属性

最后代码为:

[csharp] view plaincopy print?
  1. Shader "Custom/RoundRect" {
  2. Properties {
  3. //两种内容模式,图片模式
  4. _MainTex ("Base (RGB)", 2D) = "white" {}
  5. //纯色模式
  6. //_MainColor ("Color", COLOR) = (1,1,1,1)
  7. //圆角半径,默认为0.1
  8. _RoundRadius("Radius",float) = 0.1
  9. }
  10. SubShader {
  11. Pass{
  12. CGPROGRAM
  13. #pragma fragment frag
  14. #include "UnityCG.cginc"
  15. //获取3个属性 并传值到CG代码段
  16. sampler2D _MainTex;
  17. float _RoundRadius;
  18. float4 _MainColor;
  19. //片段着色器输入结构体(可省略)
  20. struct FragInput{
  21. float2 texcoord:TEXCOORD0;
  22. };
  23. //片段着色器入口函数
  24. float4 frag(FragInput input) : COLOR
  25. {
  26. float4 c=tex2D(_MainTex,input.texcoord);//将图片信息按坐标转换成颜色
  27. //float4 c=_MainColor;  //纯色
  28. //x,y两个变元,区间均为[0,1]
  29. float x=input.texcoord.x;
  30. float y=input.texcoord.y;
  31. //4条直线的常数部分
  32. float xt=1-_RoundRadius;
  33. float xb=_RoundRadius;
  34. float yl=_RoundRadius;
  35. float yr=1-_RoundRadius;
  36. //如果(x,y)不在4条直线构成的矩形中(上图的白色区域)
  37. if(!(x<xt&&x>xb&&y>yl&&y<yr))
  38. {
  39. //如果(x.y)不在上图的绿色区域
  40. if(!((x<xt&&x>xb) || (y>yl&&y<yr) ))
  41. //数学不好,好像判断的复杂了,如果您可以直接写出紫色区域
  42. //的不等式组那么可以简单点
  43. {
  44. //计算四个顶点的坐标
  45. float2 plb=float2(_RoundRadius,_RoundRadius);
  46. float2 plt=float2(_RoundRadius,1-_RoundRadius);
  47. float2 prt=float2(1-_RoundRadius,1-_RoundRadius);
  48. float2 prb=float2(1-_RoundRadius,_RoundRadius);
  49. //计算x,y分别到4个顶点的距离
  50. float distlb=sqrt(pow((x-plb.x),2)+pow((y-plb.y),2));
  51. float distlt=sqrt(pow((x-plt.x),2)+pow((y-plt.y),2));
  52. float distrt=sqrt(pow((x-prt.x),2)+pow((y-prt.y),2));
  53. float distrb=sqrt(pow((x-prb.x),2)+pow((y-prb.y),2));
  54. //对4个距离取最小值
  55. float dist=min(distlb,distlt);
  56. dist=min(dist,distrt);
  57. dist=min(dist,distrb);
  58. //将大于半径的表面剔除
  59. if(dist>_RoundRadius)
  60. discard;
  61. }
  62. }
  63. return c;
  64. }
  65. ENDCG
  66. }
  67. }
  68. FallBack "Diffuse"
  69. }

最后运行的效果,不同Radius不同尺寸的图片进行圆角矩形剔除

当radius设为0.25时我们可以得到一个圆,所以我们的RoundRadius属性可以设置为一个0.01~0.25的rang

由于我是windows系统,mac os下好像有点问题,不知道是不是省略了顶点着色器的问题,发现原因后再来补正

解读Unity中的CG编写Shader系列4——unity中的圆角矩形shader相关推荐

  1. Unity 圆角矩形Shader实现(支持长方形)(只写两行)

    一. 效果与引言 相信很多小伙伴都会遇到做圆角矩形的需求,网上的shader还不明白是怎么实现的,甚至还有一部分是错误的,本文讲从原理到代码讲解圆角矩形shader的实现 二. 原理分析 想要实现一个 ...

  2. rgb立方体用html语言,解读Unity中的CG编写Shader系列一

    CG=C for Graphics  用于计算机图形编程的C语言超集 前提知识点: 1.CG代码必须用 CGPROGRAM ... ENDCG括起来 2.顶点着色器与片段着色器的主函数名称可随意,但需 ...

  3. [转]解读Unity中的CG编写Shader系列3——表面剔除与剪裁模式

    在上一个例子中,我们得到了由mesh组件传递的信息经过数学转换至合适的颜色区间以颜色的形式着色到物体上.这篇文章将要在此基础上研究片段的擦除(discarding fragments)和前面剪裁.后面 ...

  4. 解读Unity中的CG编写Shader系列二

    转自 http://www.itnose.net/detail/6095974.html 上一篇文章的例子中我们可以看到顶点着色器的输出参数可以说是直接作为了片段着色器的形参传递过来,那么不由得一个问 ...

  5. java中acquire()_Java高并发系列之AQS中acquire源码解析

    我们知道,AQS中最重要的两个方法就是acquire和release方法.我们本文来走读走读acquire的源码. 首先,tryAcquire是需要子类具体去实现,其作用就是设置state的值,如果设 ...

  6. 圆角矩形 shader

    转载自:  http://glslsandbox.com/e#43292.1 // rectangle shader // http://glslsandbox.com/e#43268.6 #ifde ...

  7. swift之Mac中NSView视图里的截图【ScrollView中的内容截图】

    import Foundation import Cocoa 在视图中的方法 extension NSView { /****1. 在drawRect方法中绘制 使用Quartz2D绘图函数在视图上绘 ...

  8. unity Shader Lab(cg hlsl glsl)着色器入门教程 以及 vs2019 支持unity shader语法(更新中2019.9.5)

    前言: 如果你对cg glsl hlsl 顶点着色器 片段着色器 表面着色器 固定渲染管线 等等有所疑惑,或是想学会unity的渲染,看这一篇就足够了.另外我博客的shader分类中还有很多shade ...

  9. 将ShaderToy中的Shader搬运到Unity

    一.ShaderToy作品 如果你对 Shader 有一定的了解,那么你或多或少听说过 shaderToy 这个网站,这个网站上有很多令人振奋的 shader 效果,而这些效果有可能只用了几行代码来实 ...

最新文章

  1. 懂外语、会创作,机器高质量学习挑战均在这里实现
  2. 真正能解决 Windows 7下安装Office 2007—2010出现1402和1406类错误的方法
  3. pytorch多维筛选
  4. python软件有多大-Python程序有多大?
  5. 代码混淆工具Dotfuscator 在VS2008中的使用步骤
  6. python 配置文件中密码不能是明文_配置文件中明文密码改为密文密码的方法
  7. 强悍的 Vim —— .vimrc(vim 配置文件)
  8. 2016年不容错过的十五大智能家居产品
  9. C++ string字符串修改和替换方法
  10. uniapp开发h5应用进行微信网页授权登录获取code失败
  11. H∞鲁棒控制问题的一般性描述
  12. win10磁盘管理教程
  13. 碰撞检测 :Separating Axis Theorem
  14. 柔性制造物料抓取及加工系统设计
  15. Node.js 包管理器 ied
  16. CVPR 2022|上海交大腾讯优图提出IFRNet:视频插帧新范式新SOTA
  17. ubuntu自动安装显卡驱动
  18. Mind+敌我双方发射炮弹小游戏
  19. 抖音创作规范_抖音创作内容调整提示怎么办?应该怎么解决
  20. 微信小程序与公众号区别PHP,微信小程序和微信公众号的区别是什么?

热门文章

  1. idea 离线安装translation 谷歌翻译
  2. (一)双S型速度规划 原理
  3. 美团商家的数据指标体系是怎么做的?
  4. centos1-修改ip地址、更换密码
  5. web开发一定时间没操作_Web开发—明智地投资您的时间
  6. 基于部分卷积Pconv的图片修复
  7. 用JS解决那些有趣的数学题!
  8. 运维工程师的宿命(困兽之斗)
  9. 俄罗斯方块 UWP 版
  10. r语言 tunerf函数_R语言 | 一网打尽高质量统计分析与机器学习包