http://blog.csdn.net/mobanchengshuang/article/details/38731035
上篇文章中我們掌握了表面剔除和剪裁模式
這篇文章將利用這些知識實現(xiàn)一個簡單的,但是又很常用的例子:把一張圖片做成圓角矩形
例3:圓角矩形Shader
好吧我承認(rèn)在做這個例子的時候走了不少彎路,由于本人對矩陣的知識掌握已經(jīng)悉數(shù)還給老師,所以一開始用了一些笨辦法計算圓角矩形區(qū)域。
我們知道TEXTCOORD0是一個以對象為坐標(biāo)系的坐標(biāo),并且范圍在該坐標(biāo)的第一象限,取值為(0,0)到(1,1)
那么我們把每一張圖片都看做一張1X1大小的矩形
我們要在1X1大小的矩形中擦除4個角,應(yīng)該是這樣:
以左上角為例,我們做一個輔助圓內(nèi)切于這個角,半徑為0.1,那么我們將這個圓擦掉3/4,剩下的黃色弧線與這個角形成的區(qū)域就是我們要擦除的區(qū)域:
這個道理很簡單,那么我們對4個角分別擦除掉這樣的區(qū)域就能得到一個半徑為10%原圖尺寸的圓角矩形
我一開始走的彎路就在于計算這個區(qū)域,是用4個圓的方程來算呢還是用距離來計算
由于給出4個圓的方程太過于復(fù)雜,我這里直接給出計算外點距離算法的示意圖:
首先在這個大矩形的內(nèi)部以4個圓心為頂點做出一個內(nèi)矩形,心算得邊長為0.8
其次忽略內(nèi)矩形內(nèi)部的點,在這個紅色矩形內(nèi)給定任意一個藍(lán)色矩形的外點p ?,只要能夠得到p到藍(lán)色矩形的距離,距離大于0.1(半徑),那么就在圓角矩形外部,直接擦除,如圖:
我們看p1,p2,p3,3個點到藍(lán)色矩形的距離分別是p1的距離<半徑,根號2倍半徑>p2的距離>半徑,p3的距離等于半徑
所以p2在圓角矩形外,p1,p3在圓角矩形內(nèi)部或邊緣,我們將p2擦除掉
其中p3的距離恰好是 p3到4條直線的距離最小值
p1同理
而p2的距離不能再這樣計算,而應(yīng)該是計算p2到4個頂點距離的最小值
按這個算法只要算出所有外點中的點到藍(lán)色矩形區(qū)域的距離,然后與半徑判斷大小,大于則discard就能得到圓角矩形
一開始我按照這個思路得出一個極端無腦的方法:
給定任意一點p,求p到4條直線,4個頂點的距離,然后在8個距離中求最小值作為最終的距離拿來與半徑比較
興奮地寫完代碼知道我錯了,檢查了很久才明白,像p3這種點,算出來的8個距離中,最小距離并不是到頂點的距離,而是到兩條邊的延長線的距離
于是最終8距離求最小值算法以失敗告終
還是得老老實實分情況
那么有幾種情況呢
其實只有1種,但是先按正常邏輯分為2種:
我們來看綠色區(qū)域和紫色區(qū)域的外點們
1、當(dāng)外點在紫色區(qū)域時,距離應(yīng)是點到4頂點的距離最小值
2、當(dāng)外點在綠色區(qū)域時,距離應(yīng)是點到4條直線的距離最小值
按照這個思路那么我們可以對整個 坐標(biāo)系內(nèi)的任意點(x,y)進(jìn)行判斷:
1、如果點在白色區(qū)域或者綠色區(qū)域內(nèi), ?還計算個毛線距離啊,肯定是不discard啊~~~~(之前我傻乎乎的還真去算了)
2、紫色區(qū)域內(nèi)計算點到4頂點距離,然后取最小值,然后將大于0.1的部分剔除掉
最后我們需要將這個0.1作為變量提取出來,不能寫死,這樣可以在Inspector中方便調(diào)節(jié),或者在script中去設(shè)置,也就是給我們的shader定義一個float或rang型的屬性
最后代碼為:
[csharp]?view plaincopy print?
Shader?"Custom/RoundRect"?{?? ????Properties?{?? ?????????? ????????_MainTex?("Base?(RGB)",?2D)?=?"white"?{}?? ?????????? ?????????? ?????????? ????????_RoundRadius("Radius",float)?=?0.1?? ????}?? ????SubShader?{?? ?????????? ????????Pass{?? ????????????CGPROGRAM?? ? ????????????#pragma?fragment?frag?? ????????????? ????????????#include?"UnityCG.cginc"?? ?????????????? ????????????sampler2D?_MainTex;?? ????????????float?_RoundRadius;?? ????????????float4?_MainColor;?? ?????????????? ?????????????? ????????????struct?FragInput{?? ????????????????float2?texcoord:TEXCOORD0;?? ?????????????????? ????????????};?? ?? ?????????????? ????????????float4?frag(FragInput?input)?:?COLOR?? ????????????{?? ?????????????????? ?????????????????? ????????????????float4?c=tex2D(_MainTex,input.texcoord);?? ?????????????????? ?????????????????? ?????????????????? ????????????????float?x=input.texcoord.x;?? ????????????????float?y=input.texcoord.y;?? ?????????????????? ?????????????????? ????????????????float?xt=1-_RoundRadius;?? ????????????????float?xb=_RoundRadius;?? ????????????????float?yl=_RoundRadius;?? ????????????????float?yr=1-_RoundRadius;?? ?????????????????? ????????????????if(!(x<xt&&x>xb&&y>yl&&y<yr))?? ????????????????{?? ?????????????????? ?????????????????????? ????????????????????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);?? ?????????????? ?????????????????? ????????????????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));?? ?????????????????? ?????????????????? ????????????????float?dist=min(distlb,distlt);?? ????????????????dist=min(dist,distrt);?? ????????????????dist=min(dist,distrb);?? ?????????????????? ?????????????????? ????????????????if(dist>_RoundRadius)?? ????????????????????????discard;?? ?? ????????????????}?? ?????????????????? ?????????????????? ????????????????}?? ?? ????????????????return?c;?? ?? ????????????}?? ????????????ENDCG?? ????????}?? ?? ?????????? ????}??? ????FallBack?"Diffuse"?? }??
最后運(yùn)行的效果,不同Radius不同尺寸的圖片進(jìn)行圓角矩形剔除
當(dāng)radius設(shè)為0.25時我們可以得到一個圓,所以我們的RoundRadius屬性可以設(shè)置為一個0.01~0.25的rang
由于我是windows系統(tǒng),mac os下好像有點問題,不知道是不是省略了頂點著色器的問題,發(fā)現(xiàn)原因后再來補(bǔ)正
總結(jié)
以上是生活随笔為你收集整理的解读Unity中的CG编写Shader系列4——unity中的圆角矩形shader的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。