Unity之Shader初识 - 一

Unity之Shader初识

本篇说一下Unity Shader编程的最基本知识,主要以一个Shader代码为例说明一下代码各个模块的作用以及注意事项

首先创建一个Shader,在Project面板中Assets文件夹下右键创建



双击打开创建的Shader脚本,代码如下

<span style="font-size:14px;">Shader "Custom/qq" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Lambert

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}</span>


可以在材质面板选择该Shader的位置



接下来解释上面的代码

<span style="font-size:14px;">//着色器
Shader "Custom/qq" {

    //着色器属性
	Properties {

	//一、 _MainTex  属性名字,即变量名
	//二、 Base (RGB) 该字符串将显示在Unity的材质编辑器中作为Shader的使用者可读的内容
	//三、 2D             属性的类型,可能的类型有以下几种: 
	//    (1)Color -    纯色(一个颜色)(RGBA-红绿蓝和透明度)四个变量 ; 以 0 - 1定义的RGBA颜色,如(.5, .5, .5, 1);
	//    (2)2D    -    一张2的阶数的贴图(64, 64)(128, 128)等贴图,这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终被显示出来
	//    (3)Rect  -    一个非2阶数大小的图片
	//    (4)Cube  -     即 Cube map texture(立体纹理),即6 张2D贴图的组合,主要用于做反射效果(天空盒)
	//    (5)Range(min, max)- 一个介于最小值和最大值之间的浮点数,一般用来调整Shader某些特性的参数(如透明度渲染的区间为 0 - 1)
	//    (9)Float -     任意一个浮点数
	//    (10)Vector -   一个思维数; 如(x, y, z, w)
	//四、 white 定义这个属性的默认值,通过一个符合格式的默认值来制定对应属性的初始值

	// 下面列举几个属性申明的例子
	// _MyColor ("My Color", Color) = (.5, .2, 1, .6)  //定义一个颜色,并且设定初始值
	//
	// _Texture ("MyTexture", 2D) = "black"{}

		_MainTex ("Base (RGB)", 2D) = "white" {}
	}

	//子着色器
	SubShader {

	    // 表面着色器可以被多个标签(Tags)修饰, 硬件则通过每个标签决定什么时候调用该着色器
		// "RenderType"="Opaque"  从字面意思即可看出, 该Tags  渲染类型为 不透明的,即系统应该在渲染非透明物体时调用
		//如 "RenderType" = "Transparent" 渲染类型为透明的,即系统在渲染透明或者半透明物体时调用
		//如 "IgnoreProjector" = "True" 即不被 Projector影响
		//如 "ForceNoShadowCasting" = "True" 即不产生阴影
		//如 "Queue" = ""  指定渲染队列,当做一些透明和不透明物体的混合,出现不透明物体无法显示在透明物体之后的情况,可能就是渲染顺序不对导致的
		// Queue 预定义的值有:
		//(1)Background - 最早被渲染,即会被后续的渲染遮挡
		//(2)Geometry - 为Queue的默认值,用来渲染不透明物体
		//(3)AlphaTest - 用来渲染经过Alpha Test的像素, 单独为 AlphaTest设定一个Queue是出于对效率的考虑
		//(4)Transparent-以从后往前的顺序渲染透明物体
		//(5)Overlay - 用来渲染叠加的效果,(如镜头光晕等特效)
		// 这些预定义的值,本质上市一组定义的整数, Background = 1000, Geometry = 2000, AlphaTest = 3000 等
		//在实际设置Queue的值时,不仅能适用上面的预定义之,也可指定Queue值,如  "Queue" = "Transparent + 200",即在Transparent之后200的Queue上进行调试
		//通过调整Queue的值,可以确定一物体一定在另一些物体之前或之后渲染
		 
		Tags { "RenderType"="Opaque" }

		//LOD 即 Level of Detail 的缩写 这里制定为 200, 这个数值决定我们能用什么样的Shader,在Unity的Quality Setting中可以设定
		//允许的最大LOD, 当设定的 LOD 小于 SubShader所指定的LOD时,这个 SubShader 将不可用,Unity内建Shader定义了一组LOD数值,
		// 在实现自己的Shader的时候可以将其作为参考来设定自己的LOD数值,在根据设备性能来调整画面质量时可以进行比较精确的控制
	    // VertexLit = 100
		// Decal, Reflective VertexLit = 150
		// Diffuse = 200
		// Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
		// Bumped, Specular = 300
		// Bumped Specular = 400
		// Parallax = 500
		// Parallax Specular = 600

		LOD 200
		
		// 表明这里开始是CG程序, Unity写的Shader是使用 CG/HLSL 语言
		CGPROGRAM

		//预编译指令, 声明为 surf Lambert 即表面 Shader,并制定了光照模型
		//标准写法为 
		//#pragma suface sufaceFunction lightModel [optionalparams]
		//surface - 声明的是一个表面着色器
		//surfaceFunction - 着色器代码的方法名
		//lightModel - 使用的光照模型

		//在这里声明一个表面着色器,实际的代码在 surf 函数中(下面没有该函数), 使用Lambert(diffuse)作为光照模型

		#pragma surface surf Lambert

		// sampler2D 是 GLSL中的贴图类型,还有 sampler1D ,sampler3D
		// 在这里声明 _MainTex 的作用,在Properties 里边已经声明过了, 在这里还要声明,原因是这个Shader
		//是由两个相对独立的块组成的,外层的属性声明,回滚等是Unity可以直接使用和编译的SasderLab; 而现在
		//是在 CGPROGRAM  ...  ENDCG 这一块代码中,这是一段CG程序, 对于这段CG程序,想要访问在Properties中
		//所定义的变量的话,必须使用和之前变量相同的名字进行声明,于是 sampler2D _MainTex; 做的事就是再次声明
		//并链接了 _MainTex, 使得接下来的CG程序能够使用这个变量
		
		sampler2D _MainTex;

		//在此定义的 Input 结构体为在下面 surf 函数中要用到的结构体,自行定义
		//下面结构体重定义了一个 float2 的变量, float 和 vec 都可以加入一个 2-4的数字,来表示被
		//被打包在一起的 2 - 4个同类型数
		// 如 定义一个 2D 的 vector
		// vec2 coo;
		// float4 color;
		// float3 mmm = color.rgb * coo.x;
		//这些访问值,既可以使用名称来获得整组值,也可以使用下标方式(如 .x, .y, .xyzw, .rgba, .r)
		//UV mapping的作用是将一个2D贴图上的点按照一定规则映射到3D模型上,是3D渲染中最常见的一种顶点
		//处理手段。在CG程序中,我们有这样的约定,在一个贴图变量(在我们例子中是_MainTex)之前加上uv
		//两个字母,就代表提取它的uv值(其实就是两个代表贴图上点的二维坐标 )。我们之后就可以在surf程
		//序中直接通过访问uv_MainTex来取得这张贴图当前需要计算的点的坐标值了。

		struct Input {
			float2 uv_MainTex;
		};

		//#pragma 段已经指出了我们的着色器代码的方法名叫 surf, 这段代码是我们的着色器的工作核心
		//着色器就是给定了输入,然后给出输出进行着色的代码,CG规定声明为表面着色方法(就是我们这里的surf)
		//的参数类型和名字,我们不能决定 surf 的输入输出参数的类型,必须按照规定写,这个规定就是第一个参数
		//是Input结构, 第二个参数是一个 inout 的 SurfaceOutput结构
		// 其中Input结构需要我们自己定义 ,可以把需要参与计算的数据都放到这个Input结构中,传入 surf函数使用
		//SurfaceOutput是已经定义好了里面类型输出结构,但是一开始的时候内容暂时是空白的,我们需要向里面填写输出
		//这样就可以完成着色了
		//作为输入的结构体必须命名为 Input, 
		// SurfaceOutput 是预定义的输出结构,surf 函数的目标就是根据输入把这个输出的结构填上
		//SurfaceOutput的结构体定义如下

		//struct SurfaceOutput {
		//     half3 Albedo;   //像素的颜色
		//	 half3 Normal;   //像素的法向值
		//	 half3 Emission; //像素的发散颜色
		//	 half  Specular; //像素的镜面高光
		//	 half  Gloss;    //像素的发光强度
		//	 half  Alpha;    //像素的透明度
		//}

		//这里的 half 和我们常见float与double类似,都表示浮点数,只是精度不一样, half指的是版精度浮点数,精度最低,运算性能相对高精度浮点数高,因此被大量使用

		//这里用到了一个tex2d函数,这是CG程序中用来在一张贴图中对一个点进行采样的方法,返回一个float4。
       //这里对_MainTex在输入点上进行了采样,并将其颜色的rbg值赋予了输出的像素颜色,将a值赋予透明度。
	   //于是,着色器就明白了应当怎样工作:即找到贴图上对应的uv点,直接使用颜色信息来进行着色

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}

		// CG 程序在此结束
		ENDCG
	} 

	// 回滚
	FallBack "Diffuse"
}
</span>

读完上面的代码估计就能读懂一些简单的Shader了,由于我对Shader也不太懂,所以哪位读者发现哪里有错请回帖谢谢














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值