zoukankan      html  css  js  c++  java
  • 解读Unity中的CG编写Shader系列4——unity中的圆角矩形shader

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

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


    例3:圆角矩形Shader

    好吧我承认在做这个样例的时候走了不少弯路,因为本人对矩阵的知识掌握已经悉数还给老师,所以一開始用了一些笨办法计算圆角矩形区域。

    我们知道TEXTCOORD0是一个以对象为坐标系的坐标,而且范围在该坐标的第一象限,取值为(0,0)到(1,1)

    那么我们把每一张图片都看做一张1X1大小的矩形

    我们要在1X1大小的矩形中擦除4个角,应该是这样:


    以左上角为例,我们做一个辅助圆内切于这个角,半径为0.1,那么我们将这个圆擦掉3/4,剩下的黄色弧线与这个角形成的区域就是我们要擦除的区域:


    这个道理非常easy,那么我们对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下好像有点问题,不知道是不是省略了顶点着色器的问题,发现原因后再来补正



    假设我的博客对您有帮助或者您有不论什么疑问,欢迎增加重庆u3d交流QQ群我会给您解答:68994667,也能够加群与我们一同交流技术

  • 相关阅读:
    【深度学习】吴恩达网易公开课练习(class1 week2)
    【深度学习】吴恩达网易公开课练习(class1 week3)
    【python】内存调试
    【python】threadpool的内存占用问题
    Druid: A Real-time Analytical Data Store
    Mesa: GeoReplicated, Near RealTime, Scalable Data Warehousing
    Presto: SQL on Everything
    The Snowflake Elastic Data Warehouse
    Guava 库
    Java Annotation
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4006005.html
Copyright © 2011-2022 走看看