Unity Shader从入门到**

一、概念

Shader其实就是专门用来渲染图形的一种技术,通过shader,我们可以自定义显卡渲染画面的算法,使画面达到我们想要的效果。小到每一个像素点,大到整个屏幕

Shader分为两类 :

1.顶点Shader(3D图形都是由一个个三角面片组成的,顶点Shader就是计算每个三角面片上的顶点,并为最终像素渲染做准备)。
2.像素Shader,顾名思义,就是以像素为单位,计算光照、颜色的一系列算法。 几个不同的图形API都有各自的Shader语言,在DirectX中,顶点shader叫做 Vertex Shader ,像素Shader叫做 Pixel Shader; 在OpenGL中,顶点Shader也叫做 Vertex Shader ,但像素Shader叫做 Fragment Shader,也就是我们常说的片断Shader或者片元Shader。

Shader编程语言
既然Shader是一段代码,那必然要用一种语言来书写它,目前主流的有三种语言:

基于OpenGL的OpenGL Shading Language,简称GLSL。
基于DirectX的High Level Shading Language,简称HLSL。
还有NVIDIA公司的C for Graphic,简称Cg语言。
GLSL与HLSL分别是基于OpenGL和Direct3D的接口,两者不能混用。而Cg语言是用于图形的C语言,这其实说明了当时设计人员的一个初衷,就是让基于图形硬件的编程变得和C语言编程一样方便,自由。正如C++和 Java的语法是基于C的,Cg语言本身也是基于C语言的。如果您使用过C、C++、Java其中任意一个,那么Cg的语法也是比较容易掌握的。Cg语言极力保留了C语言的大部分语义,力图让开发人员从硬件细节中解脱出来,Cg同时拥有高级语言的好处,如代码的易重用性,可读性高等。

Cg语言是Microsoft和NVIDIA相互协作在标准硬件光照语言的语法和语义上达成了一致,所以,HLSL和Cg其实是同一种语言。

二、学习笔记

1.结构

基本的结构

Shader "MyFirstShader"
{
    
    
     Properties//属性
     {
    
         
     }
     SubShaders//子shader块(shader逻辑处理块,可以有多个)
     {
    
    
     }
     FallBack "Diffuse"//备用材质
     CutomEditor "EditorName"//自定义界面
}

1.1.属性

格式

[Attribute]_Name ("Display Name",Type) = Default Value
//[ 标记  ] 变量名("面板上的显示名",类型)=  默认值

1.1.1属性类型

①.Color颜色

_Color("我是Color",color) = (1,1,1,1)

②.Int整数

//(面板中即便可以输入小数,shader也只取其整数部分)
_Int("我是Int",Int) = 1

③.Float浮点数

_Float("我是Float",Float) = 0.5

Float相关标记

//[Range]:限制参数范围
_Float("我是Float", Range( 0 , 1)) = 0.5
//[IntRange]:向下取整
[IntRange]_Float("我是Float", Range( 0 , 1)) = 1
//[Toggle]:开关(0代表关,1代表开)
[Toggle]_Float("我是Float", Range( 0 , 1)) = 1
//[Enum]下拉列表
[Enum(UnityEngine.Rendering.CullMode)]_Float("我是Float", Float) = 1

④.Vector四维数

_Vector("我是Vector",Vector) = (0,0,0,0)

⑤.2D纹理

_MainTex("我是2D纹理",2D) = "white" {
    
    }

2D纹理相关标记

//[NoScaleOffset]:隐藏掉Tiling(贴图重复度)和Offest(贴图偏移值)参数
[NoScaleOffset]_MainTex("我是2D纹理", 2D) = "white" {
    
    }
//[Normal]:指定参数为法线贴图
[Normal]_MainTex("我是2D纹理", 2D) = "white" {
    
    }

//默认值
//white  白
//black  黑
//gray   灰
//bump   法线图

⑥.3D纹理

_MainTex("我是3D纹理"3d) = "" {
    
    }

⑦.Cube立方体纹理

_MainTex("我是Cube纹理", CUBE) = "" {
    
    }

通用属性标记

//[Header]:属性说明,使用后会在面板中参数上方出现文本
[Header(This is Header )]_Int("我是Int", Int) = 1

1.2 SubShaders 里有什么

1.2.1 Pass

Pass的意思就是:渲染一次模型
1.一个Shader中,至少有一个SubShader
2.每个SubShaders 至少有一个 Pass
在这里插入图片描述

1.2.2 Pass里有什么

1.2.2.1 .CGPROGRAM 和ENDCG

每个Pass里必须有CGPROGRAM 和ENDCG,代码就写在CGPROGRAM 和ENDCG中间

1.2.2.2 #pragma

声明的顶点着色器与片断着色器
关键词 #pragma

//定义顶点着色器为name,通常情况下会起名为vert。
#pragma vertex name

//定义片断着色器为name,通常情况下会起名为frag。
#pragma fragment name
1.2.2.3 实现声明
float4 vert ( float4 vertex : POSITION ) : SV_POSITION
{
    
    
	return UnityObjectToClipPos(vertex);
}
fixed4 frag () : SV_Target
{
    
    
	return _Color;
}

完整shader

Shader "Unlit/MyFirstShader"
{
    
    
	Properties
	{
    
    
		_Color("Color", Color) = (1,1,1,1)
	}
	
	SubShader
	{
    
    
		Pass
		{
    
    
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			fixed4 _Color;
			
			float4 vert ( float4 vertex : POSITION ) : SV_POSITION
			{
    
    
				return UnityObjectToClipPos(vertex);
			}
			
			fixed4 frag () : SV_Target
			{
    
    
				return _Color;
			}
			ENDCG
		}
	}	
}
ENDCG
1.2.2.4属性的使用

//再次声明
fixed4 _Color;
开头我们定义过一个属性_Color,但是想要在pass里使用,就需要再声明一次,名字要和上边一致
关键词用的fixed4,代表四维向量

Cg/HLSL中声明属性的常用关键词有以下几种

float
//高精度类型,32位,通常用于世界坐标下的位置,纹理UV,或涉及复杂函数的标量计算,如三角函数、幂运算等。
half
//中精度类型,16位,数值范围为[-60000,+60000],通常用于本地坐标下的位置、方向向量、HDR颜色等。
fixed
//低精度类型,11位,数值范围为[-2,+2],通常用于常规的颜色与贴图,以及低精度间的一些运算变量等。

//在PC平台不管你Shader中写的是half还是fixed,统统都会被当作float来处理。half与fixed仅在一些移动设备上有效。
//比较常用的一个规则是,除了位置和坐标用float以外,其余的全部用half。主要原因也是因为大部分的现代GPU只支持32位与16位,也就是说只支持float和half,不支持fixed。
interger
//整型类型,通常用于循环与数组的索引。

//在 Direct3D 9 和 OpenGL ES 2.0平台上整型可能会被直接用浮点数来处理,在Direct3D 11、OpenGL ES 3等现代GPU上可以正确的以整型类型来处理。
sampler2D、sampler3D与samplerCUBE
//纹理,默认情况下在移动平台纹理会被自动转换成低精度的纹理类型,如果你需要中精度的或者高精度的需要用以下方式来声明:
sampler2D_half(中精度2D纹理)
sampler2D_float(高精度2D纹理)
sampler3D_half(中精度3D纹理)
sampler3D_float(高精度3D纹理)
samplerCUBE_halft(中精度立方体纹理)
samplerCUBE_float(高精度立方体纹理)

1.2.2 struct

关键字:struct
作用:存放变量
调用:结构体名+“.”+变量名

struct appdata{
    
    
	float4 vertex:POSITION;
}
//还可以定义这些语义的变量
struct appdata
	{
    
    
		float4 vertex : POSITION;		//顶点
		float4 tangent : TANGENT;		//切线
		float3 normal : NORMAL;			//法线
		float4 texcoord : TEXCOORD0;	//UV1
		float4 texcoord1 : TEXCOORD1;	//UV2
		float4 texcoord2 : TEXCOORD2;	//UV3
		float4 texcoord3 : TEXCOORD3;	//UV4
		fixed4 color : COLOR;			//顶点色
	};

1.2.3 自定义函数

fixed checker(float2 uv)
{
    
    
	float2 repeatUV = uv*10;
	float2 c = fliir(repeatUV)/2;
	float checker = frac(c.x+c.y)*2;
	return checker;
}

自定义函数在代码中的调用

Shader "Unlit/MyFirstShader"
{
    
    
	Properties
	{
    
    
		_Color("Color", Color) = (1,1,1,1)
	}	
	SubShader
	{
    
    
		Pass
		{
    
    
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			fixed4 _Color;			
			struct appdata
			{
    
    
				float4 vertex:POSITION;
				float2 uv:TEXCOORO;
			};
			struct v2f
			{
    
    
				float4 pos:SV_POSITION;
				float2 uv:TEXCOORO;
			};
			
			float4 vert ( float4 vertex : POSITION ) : SV_POSITION
			{
    
    
				v2f o;
				o.pos = UnityObjectToClipPos(vertex);
				o.uv = v.uv;
				return o;
			}

			foxed checker(float2 uv)
			{
    
    
				float2 repeatUV = uv*10;
				float2 c = floor(repeatUV)/2;
				float checker = frac(c.x+c.y)*2;
				return checker;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
    
    
				fixed col = checker(i.uv);
				return col;
			}
			ENDCG
		}
	}	
}
ENDCG

//关于片段着色器的语义

Shader "Unlit/MyFirstShader"
{
    
    
	Properties
	{
    
    
		_FrontTex("FrontTex", 2d) = "white"{
    
    }
		_BackTex("BackTex", 2d) = "white"{
    
    }
	}
	
	SubShader
	{
    
    
		cull off
		Pass
		{
    
    
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0

			sampler2D _FrontTex;
			sampler2D _BackTex;

			struct appdata
			{
    
    
				float4 vertex : POSITION;
				float2 texcoord : TEXCOORD0;
			};


			struct v2f
			{
    
    
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};
			
			v2f vert (appdata v)
			{
    
    
				v2f o;
				o.pos=UnityObjectToClipPos(v.vertex);
				o.uv=v.texcoord;
				return o;
			}
			
			fixed4 frag (v2f i,float face:VFACE) : SV_Target
			{
    
    
				fixed4 col=1;
				col = face > 0 ? tex2D(_FrontTex,i.uv) : tex2D(_BackTex,i.uv);
				return col;
			}
			ENDCG
		}
	}	
}

1.2.2 SubShader Tags

SubShader中的Tags必须放置于SubShader中的Tags内,具体参数有以下这些:

1.Queue
//渲染队列,指定对象什么时候渲染,每个队列其实都是利用一个整数进行索引的。
有以下取值:

Background
//值为1000,此队列的对象最先进行渲染。
Geometry
//Queue的默认值,值为2000,通常用于不透明对象,比如场景中的物件与角色等。
AlphaTest
//值为2450,要么完全透明要么完全不透明,多用于利用贴图来实现边缘透明的效果,也就是美术常说的透贴。
Transparent
//值为3000,常用于半透明对象,渲染时从后往前进行渲染,建议需要混合的对象放入此队列。
Overlay
//值为4000,此渲染队列用于叠加效果。最后渲染的东西应该放在这里(例如镜头光晕等)。

Tags{
    
     "Queue" = "Geometry" }
//↓自定义渲染队列:
Tags{
    
     "Queue" = "Geometry+1" }

2.RenderType
自带的值有以下这些:
Opaque
Transparent
TransparentCutout
Background
Overlay
TreeOpaque
TreeTransparentCutout
TreeBillboard
Grass
GrassBillboard

原文链接:https://zhuanlan.zhihu.com/p/46745694

猜你喜欢

转载自blog.csdn.net/weixin_45023328/article/details/119735028