今天的Shader课程我们来学习Unity中的Properties(变量)。我们学任何一门语言,首先是从变量开始学的,UnityShader也不例外。之前有学生问过我,Shader网上的例子教程好少啊,怎么学的好?其实Shader难学是大家普遍认可的,但是其实最好的学习方法就在我们身边,官方的Document里面有非常详细的Shader教程.
如果英文好的话,看官网就能差不多入门了,英语不好的同学,照着本课程学习下来,也能收获颇丰。
那么我们就开始进入正题。
首先来看看官方文档对Properties的定义:
Shaders can define a list of parameters to be set by artists in Unity’s material inspector,The Properties block in the shader file defines them.
这句话的意思就是Properties作为属性可以显示在Unity的材质球里面,他是Unity通向Shader的窗口。
怎么理解这句话呢?其实就是Unity用来和Shader进行交互的媒介,我们在外面定义Shader的值,在内部可以根据这值做相应变化,从而改变显示效果。我们来举个例子,在Unity2017里面新建一个Shader,选择Unlit,然后把上面的Properties删掉,换成下面的代码:
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_MainTex3D("Texture3D",3D)="white"{}
_Color("Color",color)=(1,0,0,1)
_Float("Float",float)=0.0
_Int("Int",int)=1
_Range("Range",range(0,1))=0
_Vector("Vector",vector)=(1,0,0,1)
CubeMap("CubeMap",cube)="white"{}
}
接着我们把他赋予到随机一个材质球上,出来看看效果.
可以看到我们外面的材质球也做出了相应的变化。我们一行行来看看他们的意思。
-
第一行,这里定义了一个变量_MainTex,_MainTex是变量的“真名”,“真名”在shader里面有很重要的作用,不单止可以和Unity进行交互,而且可以和下面CG语言里面的变量进行交互。而括号里面双引号括起来的是变量的“小名”,“小名”除了能在编辑器里面显示,就没有任何作用了,比如这里的Texture在编辑器的材质球左边就是Texture,注意:这里小名是可以支持中文的,也就是说如果你代码里面用了中文,材质球编辑器也会显示中文.
_MainTex ("美术大大这里放上你画的贴图", 2D) = "white" {}
我们接着来看,后面的2D是变量的类型,这里这个2D是2D贴图的意思,也就是一般美术画的贴图,然后最后是默认值,white就是什么贴图都不给的时候他是什么颜色,可选的还有black,red,gray,同学们可以自行去尝试一下。
第二行和上面的一样,不一样的是这里是3D类型的贴图,这种贴图一般出现在次世代里面,比较高级的贴图,Unity手游上面不做考虑,详细的同学可以自行去查阅相关资料
第三行是Color,编辑器显示出来的是调色板,一般用来做颜色处理,可以用来给物体混合颜色。他的默认值这里给的是1,0,0,1,红色,对应的是颜色里面的RGBA,Red,Green,Blue和Alpha。
第四行的是Float,一般用来处理一些数学计算,比如算高光强度,颜色强度等待,他和C#的float都是算4个字节,同时都支持小数。
第五行的是Int,相对来说没那么大的作用,因为他不能计算小数部分,而在Shader里面,小数的计算是很普遍的,注意这里还有一个Bug,就是在编辑器里面,虽然他能用小数去赋值,但是他获取到的还是一个整数,感兴趣的同学可以自己试试。
第六行的是Range,他其实就是Float,但是会比Float好用很多,因为他可以限制范围,通常用来调试一些比较复杂的计算,而不至于超出。他默认值我给的是0,注意这里默认值如果溢出,他将会取到最靠近的有效值。
第七行是Vector,他其实是4个Float,如果有时候我们想传比较多的float值进来,我们可以尝试传4个Float,相对来说会比较方便,他的默认值我给的是(1,0,0,1),相对于的是X,Y,Z,W
第八个是CubeMap,它是用来处理空间反射效果的变量,这里面只能丢CubeMap类型的贴图,在Project窗口按鼠标右键可以创建一个。而他是不能识别普通的2D贴图的。
那么问题来了?
我们C#怎么和Shader进行交互呢?
很简单,首先我们要知道我们的Shader是在Material(材质球)上面的,我们的Material(材质球)又是在MeshRenderer(网格渲染器)上面的.
我们在挂了该Shader的材质球上面写上这个代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour {
private void Start()
{
this.GetComponent<MeshRenderer>().material.SetColor("_Color", Color.red);
}
}
注意,这里如果我们要改颜色就SetColor,如果要改Float,就SetFloat,如果要改Texture,就SetTexture。
以此类推,那后面的变量填什么呢?你要改什么变量,就去Shader里面找他的“真名”(PS:现在知道“真名”的用处了吧)注意这里如果用“小名”是会不通过的,最后一个参数填上要改成的值就行了。
随着金光一闪,我们的Shader的变量成功被我们改掉了。但是还有一个问题,为啥我们的盒子还是白色呢?
哈哈,因为这里他们没有任何关系,盒子是根据贴图的方式去采样的,我们在输出颜色的片段着色器里面,需要把他改成根据_Color的颜色输出的才行。所以接下来改代码:
Shader "Unlit/MyShader"
{
Properties
{
_MainTex ("美术大大这里放上你画的贴图", 2D) = "white" {}
_MainTex3D("Texture3D",3D)="white"{}
_Color("Color",color)=(1,0,0,1)
_Float("Float",float)=0.0
_Int("Int",int)=1
_Range("Range",range(0,1))=0
_Vector("Vector",vector)=(1,0,0,1)
CubeMap("CubeMap",cube)="white"{}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
fixed4 _Color;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return _Color;
}
ENDCG
}
}
}
注意我们中间有段代码Fixed4 _Color;
这里如果不写上的话SHADER不能用,原来上面没有分号的是SHADERLAB语法,下面有分号的是CG语法,两者属于不同的语法空间,所以上面定义的变量不能直接拿来用,要在下面写一个FIXED4 _COLOR映射过来(注意名字不能写错!!),FIXED是CG里面一个很重要的类型,是FLOAT的最小精度,他的取值范围是-2~2,刚好匹配颜色的范围。这里为啥用FIXED不用FLOAT,因为显卡的显存空间是很珍贵的,自行体会= =。其他变量要做映射的话也要注意,2D在CG里面要用SAMPLER2D,VECTOR在CG里面要用FLOAT4.
全套操作做完之后,我们应该能看到物体的颜色被我们改变了。
其实主要就是改动FragmentShader里面的代码,这个着色器是主要决定物体的颜色的。
那么下一章节,我们主要来研究一下FragmentShader,他是怎么改变物体的颜色的,同时我们还要基于片段着色器,做一个UV动画,让广告牌动起来。
(程序是个永无止境的东西,必须每天保持学习)
版权所有,违责必究
菜鸟在线 林老师 2017.9.17