• 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



  • 相关阅读:
    Java学习——文件和IO流
    Java多线程——ThreadLocal类的原理和使用
    Java多线程——线程八锁案例分析
    Django 模版语法 一
    Django 命令行调用模版渲染
    Django 使用 locals() 函数
    Django 加载 app 中的urls
    Django 传递额外参数及 URL别名
    Django 无名参数与有名参数
    Django 项目中添加静态文件夹
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7234472.html
Copyright © 2020-2023  润新知