unity 切圓角矩形 --shader編程


先上個效果圖




制作思路



如上圖我們要渲染的就是上圖帶顏色的部分

步驟:

先獲取黃色和藍綠部分

例如以下圖



算法

|U|<(0.5-r)或|V|<(0.5-r)

注意的是模型貼圖最大值是1.


然后獲取紅色的四份之中的一個圓部分


實現過程

首先在unity里創建一個shader。


創建完畢后


然后雙擊newshader(名字是能夠隨便起)

將里面的內容所有刪掉

代碼例如以下:


Shader "Custom/NewShader" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader
    {
        pass
        {
        
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "unitycg.cginc"
        sampler2D _MainTex;
        struct v2f
        {
        float4 pos : SV_POSITION ;
        float2 ModeUV: TEXCOORD0;
        };
        v2f vert(appdata_base v)
        {
        v2f o;
        o.pos=mul(UNITY_MATRIX_MVP,v.vertex);  //將模型頂點坐標轉換到視圖坐標矩陣中
        o.ModeUV=v.texcoord;   //獲取模型的UV坐標
        return o;
        }
        fixed4 frag(v2f i):COLOR
        {
        fixed4 col;
        
        col=tex2D(_MainTex,i.ModeUV);      //依據模型UV坐標獲取貼圖相相應的顏色
        
        return col;        
        }
        ENDCG
        
        }
    }
}  


上述主要代碼以凝視。

如今實現了一個簡單的頂點像素shader。

然后建一個material材質球。將你寫的shader拖到material上面去,然后給material賦值一張圖片。

然后創建一個3D的Plane物體,將material拖到物體上面去。


效果例如以下圖:


好了如今我們來切圓角矩形。

要說明的是我們為了計算方便坐標系原點在uv的中心,可是unity模型的uv的原點在左下角例如以下圖,切vu取值范圍(0,1)。就是說貼圖的像素坐標也是(0,1)表示全部的像素坐標點


unity的uv坐標系

所以為了統一,我們將unity的uv坐標系處理成中心坐標系,用一個變量存儲處理后的坐標系

方法是

unity的uv-float(0.5,0.5)

首先我們實現下圖區域的顯示



改動上面的代碼,我們須要加入一個圓角半徑的屬性。然后我們要獲取上面所說的黃色和藍綠色部分,加入代碼以下紅色字體。

代碼改動后例如以下:


Shader "Custom/NewShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_RADIUSBUCE("_RADIUSBUCE",Range(0,0.5))=0.2
}
SubShader
{
pass
{

CGPROGRAM

#pragma exclude_renderers gles
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
float _RADIUSBUCE;
sampler2D _MainTex;


struct v2f
{
float4 pos : SV_POSITION ;
float2 ModeUV: TEXCOORD0;
float2 RadiusBuceVU : TEXCOORD1;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex); //v.vertex;
o.ModeUV=v.texcoord;
o.RadiusBuceVU=v.texcoord-float2(0.5,0.5);       //將模型UV坐標原點置為中心原點,為了方便計算


return o;
}




fixed4 frag(v2f i):COLOR
{
fixed4 col;
col=(0,1,1,0);


if(abs(i.RadiusBuceVU.x)<0.5-_RADIUSBUCE||abs(i.RadiusBuceVU.y)<0.5-_RADIUSBUCE)    //即上面說的|x|<(0.5-r)或|y|<(0.5-r)
{

col=tex2D(_MainTex,i.ModeUV);


}


return col;
}
ENDCG

}
}
}

效果例如以下圖:




好了如今我們開始獲取紅色四份之中的一個圓區域


繼續改動代碼(藍色字體)


Shader "Custom/NewShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_RADIUSBUCE("_RADIUSBUCE",Range(0,0.5))=0.2
}
SubShader
{
pass
{

CGPROGRAM

#pragma exclude_renderers gles
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
float _RADIUSBUCE;
sampler2D _MainTex;


struct v2f
{
float4 pos : SV_POSITION ;
float2 ModeUV: TEXCOORD0;
float2 RadiusBuceVU : TEXCOORD1;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex); //v.vertex;
o.ModeUV=v.texcoord;
o.RadiusBuceVU=v.texcoord-float2(0.5,0.5);       //將模型UV坐標原點置為中心原點,為了方便計算


return o;
}




fixed4 frag(v2f i):COLOR
{
fixed4 col;
col=(0,1,1,0);


if(abs(i.RadiusBuceVU.x)<0.5-_RADIUSBUCE||abs(i.RadiusBuceVU.y)<0.5-_RADIUSBUCE)    //即上面說的|x|<(0.5-r)或|y|<(0.5-r)
{

col=tex2D(_MainTex,i.ModeUV);


}

else
{
if(length( abs( i.RadiusBuceVU)-float2(0.5-_RADIUSBUCE,0.5-_RADIUSBUCE)) <_RADIUSBUCE)
{
col=tex2D(_MainTex,i.ModeUV);

}
else
{
discard;
}
}

return col;
}
ENDCG

}
}
}

這是在曾經的代碼的基礎上加入了else分支推斷。

邏輯順序是這種 if推斷的是下圖區域的,else就是非下圖區域的其它區域


if推斷的區域


else區域(藍色框的區域)

然后我們在else下再推斷像素點是否在四份之中的一個圓呢即可了

if(length( abs( i.RadiusBuceVU)-float2(0.5-_RADIUSBUCE,0.5-_RADIUSBUCE)) <_RADIUSBUCE)

上面這句推斷有點亂

首先我們先獲取UV坐標u和v都是正半軸的四份之中的一個圓:以下藍色框區域。


首先我們獲取下圖p點坐標


即:p=float2(0.5-_RADIUSBUCE,0.5-_RADIUSBUCE) //_RADIUSBUCE是上圖的r

然后將每次獲取的模型uv坐標減去p坐標,相當於將坐標系平移p后獲取的新的uv坐標。如上圖綠色坐標系。

例如以下代碼

i.RadiusBuceVU-float2(0.5-_RADIUSBUCE,0.5-_RADIUSBUCE)

然后我們就能夠通過綠色坐標系進行計算是否在圓內了。

僅僅要在新的坐標系中vu到原點的長度小於半徑r就能夠渲染顏色,否則就不渲染(cg函數為:discard--------跳出渲染管線不渲染)

if(length(i.RadiusBuceVU-float2(0.5-_RADIUSBUCE,0.5-_RADIUSBUCE))<_RADIUSBUCE)

{
col=tex2D(_MainTex,i.ModeUV);

}
else
{
discard;
}

能夠將上面的代碼替換(綠色字體)測試一下

Shader "Custom/NewShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_RADIUSBUCE("_RADIUSBUCE",Range(0,0.5))=0.2
}
SubShader
{
pass
{

CGPROGRAM

#pragma exclude_renderers gles
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
float _RADIUSBUCE;
sampler2D _MainTex;


struct v2f
{
float4 pos : SV_POSITION ;
float2 ModeUV: TEXCOORD0;
float2 RadiusBuceVU : TEXCOORD1;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex); //v.vertex;
o.ModeUV=v.texcoord;
o.RadiusBuceVU=v.texcoord-float2(0.5,0.5);       //將模型UV坐標原點置為中心原點,為了方便計算


return o;
}




fixed4 frag(v2f i):COLOR
{
fixed4 col;
col=(0,1,1,0);


if(abs(i.RadiusBuceVU.x)<0.5-_RADIUSBUCE||abs(i.RadiusBuceVU.y)<0.5-_RADIUSBUCE)    //即上面說的|x|<(0.5-r)或|y|<(0.5-r)
{

col=tex2D(_MainTex,i.ModeUV);


}

else
{
if(length( i.RadiusBuceVU-float2(0.5-_RADIUSBUCE,0.5-_RADIUSBUCE)) <_RADIUSBUCE)
{
col=tex2D(_MainTex,i.ModeUV);

}
else
{
discard;
}
}

return col;
}
ENDCG

}
}
}

效果例如以下圖


發現如今已經完畢了一個角的計算。其它角僅僅要在獲得的新uv坐標加個絕對值。將全部坐標轉換到正坐標系下就能夠了


終於代碼例如以下

Shader "Custom/NewShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_RADIUSBUCE("_RADIUSBUCE",Range(0,0.5))=0.2
}
SubShader
{
pass
{

CGPROGRAM

#pragma exclude_renderers gles
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
float _RADIUSBUCE;
sampler2D _MainTex;


struct v2f
{
float4 pos : SV_POSITION ;
float2 ModeUV: TEXCOORD0;
float2 RadiusBuceVU : TEXCOORD1;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos=mul(UNITY_MATRIX_MVP,v.vertex); //v.vertex;
o.ModeUV=v.texcoord;
o.RadiusBuceVU=v.texcoord-float2(0.5,0.5);       //將模型UV坐標原點置為中心原點,為了方便計算


return o;
}




fixed4 frag(v2f i):COLOR
{
fixed4 col;
col=(0,1,1,0);


if(abs(i.RadiusBuceVU.x)<0.5-_RADIUSBUCE||abs(i.RadiusBuceVU.y)<0.5-_RADIUSBUCE)    //即上面說的|x|<(0.5-r)或|y|<(0.5-r)
{

col=tex2D(_MainTex,i.ModeUV);


}

else
{
if(length( abs( i.RadiusBuceVU)-float2(0.5-_RADIUSBUCE,0.5-_RADIUSBUCE)) <_RADIUSBUCE)
{
col=tex2D(_MainTex,i.ModeUV);

}
else
{
discard;
}
}

return col;
}
ENDCG

}
}
}

終於效果



項目下載鏈接

http://download.csdn.net/detail/fengya1/9449577




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM