• 【Unity Shader学习笔记】(三)绘制点、直线、网格等基本图形


    前言

    今天我们学习一种简单的使用Unity Shader在屏幕上绘制几何图形的方法。其中包含了基本的点(或者说是圆形)、直线(任意方向)和网格(横纵交错)的绘制方法。本文例程使用的是Unity5.4.1。

     

    1 准备工作

    建立一个Unity工程,在摄像机前方放置一个Plane,需要填充满摄像机视野,放得正不正都没有关系,填满就行。利用Plane映射到屏幕上的像素坐标作为绘制图形的输入参数。(当然,如果我们使用camera的OnRenderImage()函数,进行RenderTexture的材质修改,也可以实现本文的效果,原理都是一致的,这里我们主要看思路哈)


    然后创建一个新的Material,名称随意,默认也可。再创建一个新的任意种类的Shader,取名为Draw。将Draw.shader文件中默认生成的shader代码全部删掉。将下面代码复制到你的Draw.shader文件中。

    Shader "Custom/Draw"
    {
    	Properties
    	{
    
    	}
    	SubShader
    	{
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    			};
    
    			struct v2f
    			{
    				float4 vertex : SV_POSITION;
    			};
    		
    			
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				return o;
    			}
    			
    			fixed4 frag (v2f i) : SV_Target
    			{
    				return fixed4(1,1,1,1);
    
    			}
    			ENDCG
    		}
    	}
    }
    


    这就完成了基本的准备工作了。

     

    2 Shader代码编写

    2.1 绘制点或圆形

    点可以认为是只有一个像素的圆形,所以我们统一认为是绘制圆形。为了在屏幕上绘制圆形,我们需要知道圆形的位置和半径。

    在Properties中添加要绘制的点位置信息,半径暂时不设置为可调的,后文在使用时用了固定值

    		_Point1("Point1",vector) = (100,100,0,0)
    		_Point2("Point2",vector) = (200,200,0,0)

    在SubShader的Pass中添加

    			float4 _Point1;
    			float4 _Point2;
    

    绘制圆形的代码:

    			    //绘制圆形,此处半径使用了固定值1000和500,当然大家也可以把他们写成可调的参数
    				if( pow((i.vertex.x- _Point1.x ),2) + pow((i.vertex.y- _Point1.y ),2) <1000   )
    				{
    					return fixed4(0,1,0,1);
    				}
    				if( pow((i.vertex.x- _Point2.x ),2) + pow((i.vertex.y- _Point2.y ),2) <500   )
    				{
    					return fixed4(1,0,0,1);
    				}


    2.2 绘制直线

    在Properties中添加要绘制的直线上两点位置及直线宽度

    		_LP1("linePoint1",vector) = (300,100,0,0)
    		_LP2("linePoint2",vector) = (600,400,0,0)
    		_LineWidth("LineWidth",range(1,20)) = 2.0


    在SubShader的Pass中添加

    			float4 _LP1;
    			float4 _LP2;
    			float _LineWidth;		


    绘制直线上两点:

    				//绘制直线上两点
    				if( pow((i.vertex.x- _LP1.x ),2) + pow((i.vertex.y- _LP1.y ),2) <100   )
    				{
    					return fixed4(0,0,1,1);
    				}
    				if( pow((i.vertex.x- _LP2.x ),2) + pow((i.vertex.y- _LP2.y ),2) <100   )
    				{
    					return fixed4(0,0,1,1);
    				}


    根据两点绘制直线。问题转化为计算哪些点在直线的线宽范围内。首先利用直线的两点式方程,过(x1,x2)和(y1,y2)的直线上任意点(x,y)满足下式


    转化为一般式为


    根据点到直线的距离公式,某一点(x0,y0)到上述直线的距离为


    所以绘制直线的代码如下:

    				//计算点到直线的距离
    				float d = abs((_LP2.y-_LP1.y)*i.vertex.x + (_LP1.x - _LP2.x)*i.vertex.y +_LP2.x*_LP1.y -_LP2.y*_LP1.x )/sqrt(pow(_LP2.y-_LP1.y,2) + pow(_LP1.x-_LP2.x,2));
    				//小于或者等于线宽的一半时,属于直线范围
    				if(d<=_LineWidth/2)
    				{
    					return fixed4(0.8,0.2,0.5,1);
    				}


    2.3 绘制横纵网格

    绘制网格直线代码:

    				//绘制网格直线
    				if( (unsigned int)i.vertex.x% (unsigned int)(0.25*_ScreenParams.x)==0 )
    				{
    					return fixed4(0,0,1,1);
    				}
    				if( (unsigned int)i.vertex.y% (unsigned int)(0.1*_ScreenParams.x)==0 )
    				{
    					return fixed4(0,0,1,1);
    				}


    2.4 绘制效果

    屏幕分辨率设置成了800*600。当然这是可以按照自己的意愿随意设置的,你可以改为自己喜欢的分辨率。

    2.5 完整的shader代码

    Shader "Custom/Draw"
    {
    	Properties
    	{
    		_Point1("Point1",vector) = (100,100,0,0)
    		_Point2("Point2",vector) = (200,200,0,0)
    		_LP1("linePoint1",vector) = (300,100,0,0)
    		_LP2("linePoint2",vector) = (600,400,0,0)
    		_LineWidth("LineWidth",range(1,20)) = 2.0
    	
    	}
    	SubShader
    	{
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    			};
    
    			struct v2f
    			{
    				float4 vertex : SV_POSITION;
    			};
    			float4 _Point1;
    			float4 _Point2;
    			float4 _LP1;
    			float4 _LP2;
    			float _LineWidth;		
    			
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				return o;
    			}
    			
    			fixed4 frag (v2f i) : SV_Target
    			{
    			    //绘制圆形,此处半径使用了固定值1000和500,当然大家也可以把他们写成可调的参数
    				if( pow((i.vertex.x- _Point1.x ),2) + pow((i.vertex.y- _Point1.y ),2) <1000   )
    				{
    					return fixed4(0,1,0,1);
    				}
    				if( pow((i.vertex.x- _Point2.x ),2) + pow((i.vertex.y- _Point2.y ),2) <500   )
    				{
    					return fixed4(1,0,0,1);
    				}
    
    				//绘制直线上两点
    				if( pow((i.vertex.x- _LP1.x ),2) + pow((i.vertex.y- _LP1.y ),2) <100   )
    				{
    					return fixed4(0,0,1,1);
    				}
    				if( pow((i.vertex.x- _LP2.x ),2) + pow((i.vertex.y- _LP2.y ),2) <100   )
    				{
    					return fixed4(0,0,1,1);
    				}
    
    				//计算点到直线的距离
    				float d = abs((_LP2.y-_LP1.y)*i.vertex.x + (_LP1.x - _LP2.x)*i.vertex.y +_LP2.x*_LP1.y -_LP2.y*_LP1.x )/sqrt(pow(_LP2.y-_LP1.y,2) + pow(_LP1.x-_LP2.x,2));
    				//小于或者等于线宽的一半时,属于直线范围
    				if(d<=_LineWidth/2)
    				{
    					return fixed4(0.8,0.2,0.5,1);
    				}
    
    				//绘制网格直线
    				if( (unsigned int)i.vertex.x% (unsigned int)(0.25*_ScreenParams.x)==0 )
    				{
    					return fixed4(0,0,1,1);
    				}
    				if( (unsigned int)i.vertex.y% (unsigned int)(0.1*_ScreenParams.x)==0 )
    				{
    					return fixed4(0,0,1,1);
    				}
    				//默认返回白色
    				return fixed4(1,1,1,1);
    
    			}
    			ENDCG
    		}
    	}
    }
    




    小结

    我们已经可以使用Shader绘制简单的几何图形,今后可以进入更加复杂的图形绘制学习阶段,做做后期场景特效等等。






  • 相关阅读:
    Which is best in Python: urllib2, PycURL or mechanize?
    Ruby开源项目介绍(1):octopress——像黑客一样写博客
    Truncated incorrect DOUBLE value解决办法
    Qt Quarterly
    Rich Client Platform教程
    iOS6 中如何获得通讯录访问权限
    省赛热身赛之Javabeans
    [置顶] [开心学php100天]第三天:不羁的PHP文件操作
    hdu2033 人见人爱A+B
    [置顶] AAM算法简介
  • 原文地址:https://www.cnblogs.com/yanhuiqingkong/p/7770075.html
Copyright © 2020-2023  润新知