Shader又叫着色器,控制着颜色的显示。即可以让模型显示出贴图的颜色,也可以显示出金属的光泽、通过法线贴图增加模型的细节等。

先在场景中新建一个物体,然后在工程面板新建一个材质,给物体换上这个材质,然后我们就可以在属性面板为这个物体更换shader了。系统自带了很多shader,它们有不同的显示效果,可以更换着试试看。

unity color 怎么填255 unity怎么上颜色_unity color 怎么填255

我们开始创建第一个shader。在工程面板中Create-Shader-Standard Surface Shader创建一个shader文件。

unity color 怎么填255 unity怎么上颜色_unity color 怎么填255_02

和c#脚本一样,创建后可以给shader一个新文件名。

unity color 怎么填255 unity怎么上颜色_unity color 怎么填255_03

之后双击该脚本即可打开。如果你没有修改过设置,一般会默认直接用vs打开和编辑。但我改成了vs code。如果你也准备用vs code,可以安装这几个我安装了的插件:

unity color 怎么填255 unity怎么上颜色_unity_04

 

相对于c#,写shader时的辅助功能是非常不完善的。比如不会直接提示语法错误,需要运行才能知道是否有问题。用vs code等工具相对vs舒服点,但依然不能直接提示语法错误。这个只能自己适应一下了……

我们先了解一下Shader的基本结构:

首先是属性(Properties),里面填的就是需要直接在unity的面板中修改的内容。比如需要用哪张贴图、显示什么颜色。

然后是一个或多个子着色器(SubShader),但只有一个会执行。比如有的显卡可能不支持这个子着色器的内容,就会执行下一个能执行的内容。但如果是语法错误导致的不能执行,就一个也不能执行,模型会直接变成紫红色。

最后是备用方案(FallBack),填一个已经有的Shader即可。

//这里填的"本shader名称"是想在选择Shader时显示出的那个名称。名称并不要求与文件名相同。
//可以直接是shader名,也可以是 路径/shader名 的形式。
//这样可以将同类Shader放在同一个路径中(这里的路径只需要直接在这里填,不用去改文件的实际存放路径)。
Shader "本shader名称" {	

	//属性,不是必须有。里面写需要在面板中直接修改的内容,比如用哪个贴图、什么颜色。
	Properties {}

	//子着色器。有一个或多个。比如有的显卡可能不支持这个子着色器,就会选择下一个子着色器执行。
	SubShader {

		//一个子着色器一般一个Pass块,最少一个,允许多个。一个Pass块等于一个功能或一个方法。
		pass{
			CGPROGRAM
			//在CGPROGRAM与ENDCG中间用CG语言编写Shader代码。除了CG,其它写shader的语言主要有写OpenGL的GLSL,写DirectX 的HLSL。
			ENDCG
		}
	}

	//所有SubShader都不能使用时的应急方案。填一个已经有的Shader,就是面板中能看到的那些可以更换的Shader。
	FallBack "备用Shader名"
}

顶点函数与片元函数:

模型的表面是由一个个三角形组成的。三角形有3个顶点。首先由顶点函数处理模型各个三角形的顶点,确定位置等。然后将信息传递给片元函数。之后由片元函数得到每个像素的显示颜色。这两个函数就像c#脚本的start、UpDate等函数一样,是自动被系统调用的。片元函数的返回值就是显示的颜色。

语义:

通过 冒号+关键字 的形式,对某个变量进行解释。功能有将某个系统中的量赋值给这个变量、或将这个变量的内容作为系统的某个量,或解释这个变量是什么类型以便将这个变量用于存储相关类型的内容。先学2个:

变量:POSITION //将模型空间的顶点坐标赋值给该变量。

变量:SV_POSITION //将该变量作为片元函数中剪切空间下的顶点坐标。

比如以下这个函数,函数名为vert,参数为float4 类型的v,返回值也为float4类型。v:POSITION代表将模型空间的顶点坐标赋值给v。后面的这句:SV_POSITION代表将该函数的返回值作为片元函数中剪切空间下的顶点坐标。

float4 vert(float4 v:POSITION):SV_POSITION{
//函数内容
}

方向、位置的空间转换:

Shader中会用到模型空间、剪切空间、切线空间等不同的空间。经常需要将方向、位置在不同空间进行转换。好在已经有现成的方法用于将这些量在不同的空间中转换。使用一个系统提供的矩阵与这些量进行叉乘即可转换。方法为

转换后的量= mul(转换用的矩阵,转换前的量);

比如假设v是模型空间下的顶点坐标,需要转换到剪切空间下并将新值赋值给pos:

pos= mul(UNITY_MATRIX_MVP,v);//用UNITY_MATRIX_MVP即可得到此次从模型空间转换到剪切空间需要用的矩阵,先将这个记录下来,和语义一样,用多了就熟悉了。

删除shader中的原代码,改为如下代码

//路径与shader名为"Tutorial/01SolidColor"。可以填其它名称。
Shader "Tutorial/01SolidColor" {
	//这个Shader用不到属性
	SubShader{
		pass{
			CGPROGRAM

			//声明顶点函数名为vert
			#pragma vertex vert
			//声明片元函数名为frag
			#pragma fragment frag 

			//顶点函数的内容
			float4 vert(float4 v:POSITION):SV_POSITION{
				//将模型空间下的顶点坐标转换到剪切空间
				float4 pos= mul(UNITY_MATRIX_MVP,v);
				//将剪切空间下的顶点坐标返回。返回值里是必须有这个值的。
				//这个值片元函数会用到,不过是系统自动使用的,不用我们去调用。
				return pos;
			}

			//片元函数的内容
			float4 frag():SV_TARGET{
				//片元函数的返回值就是相关像素显示的颜色。这里返回了一个float4的量。
				//这个量有4维,分别代表红绿蓝和阿尔法值,阿尔法值影响透明度。数字0-1。
				//了解色彩的就知道,红绿蓝一起显示就是白色。这里我们直接返回了一个白色。
				//这里可以修改为其它颜色,如float4(1,0,0,1),红色。但这里直接修改透明度是无效的。
				return float4(1,1,1,1);
			}
			ENDCG
		}
	}
	//备用方案
	Fallback "VertexLit"
}

注意有的句子后面是没有";"的。实际上主要是CGPROGRAM和ENDCG之间的CG代码才需要加";",且声明顶点和片元函数名时也没有";"。

之后在选择shader时就能选择我们新写的这个shader了:

unity color 怎么填255 unity怎么上颜色_unity color 怎么填255_05

选择这个Shader后,物体变成了纯白色:

unity color 怎么填255 unity怎么上颜色_unity_06