一、ShaderLab总大纲
ShaderLab意义
3、控制渲染引擎的工作方式
这个功能是最主要功能,他可以控制渲染引擎的工作方式,也可以和引擎的其他功能产生沟通,比如我可以使用脚本代码控制其数据,或者通过编辑器控制着色器代码的数据;4、解析显卡编程代码
对于 OpenGL 3D API他自动调用 GLSL解析程序;
对于DirectX 3D API他自动调用HLSL解析程序;
如果发现你写的是Cg代码,他使用Cg version 3.0来实现代码解析;
语法框架结构
框架层级
1、外框:用来标注他是什么代码
Shader " 着色器代码名称 "
{
}
注意:着色器代码名称可以实现层级方式,例如:"MyShader/FixedShader",表示这个着色器代码数据 "MyShader"这个总目录之下的一个子对象;
2、属性框:用来和外界程序沟通的通道
Properties
{
// 属性:公共级别变量;
}
注意:属性框必需存在于Shader "着色器名称" { } 这样外框之内。而且一定要在外框的最上面;
属性:
写法:变量名 ("在检视体面板上提供的名称 ", 变量的类型)=初始化值
写法注意:属性必须初始化,变量名必须是英文的,"在检视体面板上提供的名称 ":这个东西可以是中文,一定要记住,最后不能添加 ";"进行结尾。这个属性变量一行只能定义一个,绝对不容许出现多个变量定义;
属性变量类型:
Vector : 向量类型,对应一个四位的向量: (x, y, z, w);
Color : 颜色类型(float),对应一个 RGBA颜色设定: (R, G,B,A)
Float : 单精度浮点,没有范围,对于初始化值据对不容许加入 "f"强转符号,例如 1.0
Range(min, max): 区间取值,范围是你定义的min到 max之间的数包含min和 max的数。这个数必须是单精度浮点;
2D: 表示一个2D的纹理贴图对象,必须是外界传递的 Texture2D资源。
Cube : 立方体贴图,多用于天空盒,支持六面体贴图;
Rect : 矩形贴图,用户鱼眼相机;
属性定义例如:
Properties
{
// 表示我们定义了一个颜色变量,并且初始化为白色
_Color("颜色", Color) = (1,1,1,1)
// 表示我们定义了一个坐标,初始化为 Zero
_Position("坐标", Vector) =(0,0,0,0)
// 表示我们定义了一个浮点化的数值
_Value("浮点数值", Float)=1.0
// 表示我们定义了一个区间值,并且给了一个值
_Range ( "区间值", Range(0.0, 1.0) ) = 0.5
// 表示我们定义了一个白色的底图,但是没有数据存在,需要外界程序给我们指定一个 2D纹理贴图;
_MainTex("纹理贴图", 2D) = "white"{}
}
3、子外框:用来给着色框架提供着色代码
SubShader
{
}
注意: SubShader这个子外框主要是用来提供着色代码的, SubShader可以实现好几个,多个 SubShader是为了让渲染引擎根据当时的渲染条件来选择可以执行的渲染代码。这个选择过程主要是渲染引擎自己抉择的,当渲染引擎选择了一个可以执行的 SubShader代码,其他的代码就全部失效;
SubShader 的执行代码分类:
1、Unity引擎自带的一种功能渲染模式:表面体着色,他只能实现上色的功能,不能控制网格对象中的顶点坐标。对于的他上色一定是具有实时光照效果的;
2、固定着色器代码,他是通过一系列的命令,控制渲染引擎工作;
3、着色器代码:GLSL, HLSL, Cg这些就是显卡元语言代码,他可以干预网格定义定位和颜色的上色过程;
注意:"表面体着色"代码可以直接在 SubShader下写。固定着色和着色器代码必须套个壳才能工作。这个壳主要用来区分执行的方式;
4、执行过程框:用来给子外框提供实际的演算过程
Pass
{
}
注意:用来提供最终的运算过程,和线程中的执行方法类似,只是Pass是你自己启动线程,而SubShader是表示Main函数,Pass只能执行固定着色和着色器代码。Pass可以出现多个,每个Pass都会执行;
注意:Pass出现的次数决定了你的绘制效率,如果太多Pass会导致你的绘制效果急剧下降;
层级说明
外框用来决定当前的脚本代码是着色器代码,并且给他取了名字;
属性框:必须在整个着色器代码的最上层,不得随意调改他的位置,属性框不一定存在,当我们不需要和外界沟通的时候我们可以不写属性框,属性框的存在是为了和外界沟通;
子外框必须存在于外框内,如果有属性框他一定在属性框之下,一个着色器中可以存在多个子外框,根据不同的渲染硬件或操作系统提供不同的渲染代码。这个监视过程由引擎自动完成,当前状态下有且只有一个子外框可以运行,其他子外框都被忽略。子外框主要是为了给着色器提供代码支持;
执行过程框存在于子外框中,他不能单独存在,执行过程框只能执行固定着色代码和着色代码。对于表面体着色器他不能执行。执行过程框可以存在多个,在一个子外框中。他的存在必须会被执行,越多的执行过程框就会造成更多绘制调用,从而增加了绘制代码的负荷,万不得已不要写多个执行过程框;
例如1:
Shader "MyShader/Fixed" //外框
{
Properties//属性框对外沟通可以存在,如果没有对外数据可以不写
{
_Color("颜色", Color) = (1,1,1,1)
}
SubShader //子外框可以执行的代码框
{
//我们可以直接写 “表面着色代码”
Pass //对于固定着色或可编程着色我们必须加Pass框
{
Color [_Color]
}
}
}
例如2:
Shader "MyShader/FixedShader"
{
Properties{ //参数可在检视面板自己调节
_Color("MyColor", Color) = (1,1,1,1)
_DiffuseColor("DiffuseColor", Color) =(1,1,1,1)
_SpecularColor("SpecularColor", Color) = (1,1,1,1)
_Shininess("SpecularRadius", Range(0,1)) = 1
_AmbientColor("AmbientColor", Color) = (1,1,1,1)
_EmissionColor("EmissionColor", Color) = (1,1,1,1)
}
SubShader
{
Pass
{
Color[_Color]
Lighting on//打开灯光才有效果
Material{
Diffuse[_DiffuseColor]//漫反射
Specular[_SpecularColor]//高光
Shininess[_Shininess]//高光半径
Ambient[_AmbientColor]//环境光
Emission[_EmissionColor]//自发光
}
}
}
}
ShaderLab固定命令集合
命令赋值方式
所有的 SahderLab固定命令都可以进行赋值操作,他们根据不同的方式接受数值内容,可以接受三种: 1、常量赋值; 2、属性变量; 3、逻辑运算数据;
常量赋值:赋值时对于向量级别的需要用 " ( ) "将向量的实际内容填入进去。对于普通的的数字直接给定值就好了;
属性变量:命令使用属性变量必须在变量名外加 " [ ] "属性变量必须有 Properties {}属性框提供,不能自己随意定义;
逻辑运算数据:提供了 on, off这样的开关效果,也可以是比较运算或者一些脚本规定的特殊关键字;
颜色控制
颜色融合和叠加
融合:也可以说是混合,表示将新颜色和已有的颜色进行混合,让已有颜色发生色彩改变;
叠加:用新颜色覆盖已有颜色,达到展示新颜色的效果;
融合/混合:数学计算中使用乘号 " * ";
叠加:数据计算中使用加号 " + ";
纯色:Color
纯色主要是关闭灯光后的自发光形式,他不受灯光影响;
例如:
Color (1,0,0,1) //表示我们需要当前物体直接显示红色
Color [_Color] //表示我们调用了Properties属性中的一个属性对象
具有灯光效果的颜色:Material
使用 Material材质块这个命令集合时必须配合灯光系统的工作,如果没有灯光的存在 Material是一定会失效的,当灯光系统被开启,那么 Material会生效,但是 Color纯色一定会失效;
语法:
Material
{
Diffuse (1,1,1,1) //漫反射灯光颜色
Specular(1,1,1,1) //冯式着色颜色 (高光色彩 )
Shininess 0.5 //高光的光斑半径范围 ( 0 -1: 0表示无穷大, 1表示最小 )
Ambient(1,1,1,1) //环境光色彩
Emission(1,1,1,1) //自发光色彩 (他是保持物体自身色彩的曝光度 )
}
对于 Material中的所有设置属性都可以使用Properties中的属性变量;
Material 中 Block Color的说明:
Diffuse 表示基础颜色(物体的实际色彩),必须存在只有他存在其他颜色才有意义。Specular是在Diffuse的基础上叠加的一种颜色,Ambient是对Diffuse颜色的一种融合。Emission级别最高,他可以随时覆盖其他所有颜色,我们一般用它做曝光饱和度调整;
以上说明可以总结成一个颜色公式:
Ambient * 引擎自带环境光颜色 +( LightColor * Diffuse + LightColor * Specular ) + Emission;
灯光控制:Lighting
灯光控制需要两个值: on或 off。
on 表示开启灯光,影响Material材质块,Color纯色失效;
off 表示关闭灯光,Material材质块失效,Color纯色生效;
例如:
Lighting on //表示开启灯光
Lighting off //表示关闭灯光
引擎控制命令
控制Mesh的正反面裁剪问题:Cull
通过控制 Cull命令通知引擎进行顺时针方面不同的顶点裁剪效果,可以将顺时针顶点保留,也可以将逆时针顶点保留,或者连个方向的都保留;
front : 表示裁剪掉(不显示)顺时针方向的顶点,显示逆时针方向的顶点;
back:表示裁剪掉逆时针方向的顶点,显示顺时针方向(这是默认模式);
off :关闭裁剪,两个防线的都不裁剪;
深度控制命令
概念
什么是深度:表示该像素点在3D世界中与摄像机的距离,深度值(就是你的Z轴)。
深度缓冲:缓冲是用来记录一些数据的内存区域,深度缓冲中记录了每个像素点的深度值(Z轴),如果我们启动深度缓冲,在绘制每个像素点之前,3D引擎都会把它们的深度值纪录下来和已经存在的深度值进行比较;
深度测试:将已经存在的像素的深度值和将要绘制的像素点的深度值进行比较的过程我们称为深度测试。如果新像素点的深度值小于( < )以存在像素点的深度值新像素点替换旧像素点。如果新像素点的深度值大于( > )以存在像素点的深度值放弃新像素点绘制;
深度缓冲控制命令:ZWrite
深度缓冲只有两种状态:on / off
注意:如果深度缓冲被关闭了,那么深度测试就会失效;
深度测试命令:ZTest
测试命令必须在缓冲开启状态下有用,但是我们也可以单独关闭测试;
off: 表示关闭深度测试;
comparsion:通过比较运算符和一个浮点数告知引擎我关心多少米范围内的深度问题;
comparsion: Greatar( > ), Less( < ) , GEqual( >=), LEqual( <= ), Equal (==)
纹理控制命令:SetTexture
SetTexture表示可以对已经存在的 Mesh 设定相应的纹理贴图。
SetTexture不支持常量数据,只支持属性变量;
格式: SetTexture [2D纹理属性变量 ] { [ 命令集合 ] }
命令集合:
combine :将两种颜色进行混合的命令,第一种: previous 表示以前存在的颜色。第二种 : texture 当前纹理的颜色。附加颜色: primary (顶点自带颜色 ), constant (常量颜色) ;
constantColor :用来设定一个常量颜色,这个颜色是可以和我们的纹理颜色进行混合的颜色;
matrix :表示接受外界传入的矩阵数据,让纹理根据矩阵发生变化;
总结常用方法:
1、直接使用纹理: SetTexture[_MainTex] { combine texture }
2、调整纹理颜色: SetTexture[_MainTex] { constantColor[_Color] combine texture * constant}
3、与顶点颜色混合: SetTexture[_MainTex] { combine texture * primary}
注意:对于这样的模式纹理可以支持光照或者不支持光照了,纹理颜色和 Color、 Material产生了混合,光照色彩比较低,所以在后面加入 DOUBLE提升亮度例如:SetTexture[_MainTex]{combinetexture* primary DOUBLE}
Alpha通道控制命令:AlphaTest
什么是 Alpha通道:
Alpha就是一个对于当前像素点的 RGB 颜色的还原率的百分比。 1表示 100% 还原,( 0 - 1)表示保留有半透明效果,如是 0 表示颜色不还原了;
利用 Alpha通道的作为:
1、制作半透明效果;
2、为了镂空图像表述特殊形状的图像;
格式: AlphaTest comparsion Alphavaule
AlphaTest off 关闭Alpha通道测试
comparsion:
Greater:大于指定 Alphavaule 就显示;
Less:小于指定的 Alphavaule 就显示;
Equal:等于 Alphavaule 就显示;
GEqual: .. ..
LEqual: .. ...
off:关闭 Alpha 通道测试。
Alphavaule:一个浮点数;
例如:
Shader"MyShader/FixedTexture"
{
Properties
{
_MainTex("Base Tex" ,2D ) = "White" {}
_TexColor("TexColor" ,Color ) = (1 ,1 ,1 ,1 )// 常量色
_AlphaChannel("Alpha" ,Range (0 ,1 )) = 0
}
SubShader
{
Pass
{
Lighting off
AlphaTest Greater[_AlphaChannel]
SetTexture [_MainTex]{constantColor [_TexColor]combine texture* constant}
}
Pass
{
Cullfront
Lighting off
AlphaTest Greater[_AlphaChannel]
Color( 0.18, 0.18, 0.18, 1)
}
}
}
颜色混合命令:Blend
融合命令是执行在即将绘制到屏幕上的时候,它是最后一道效果设置;
将新元素的颜色与意境存在的颜色进行混合后显示在屏幕上,主要用来显示半透明效果;
Blend计算公式:新颜色 * SrcFactor +以存在的颜色 * DestFactor;
SrcFactor和DestFactor的取值:
One :表示 数字 1和颜色(RGB)相乘;
Zero:表示 数字 0和颜色(RGB)相乘;
SrcColor:取新元素的颜色作为乘数与颜色相乘;
DestColor:取以存在元素的颜色作为乘数与颜色相乘;
SrcAlpha:取新元素的Alpha值作为乘数与颜色相乘;
DestAlpha:取以存在的元素的Alpha值作为乘数与颜色相乘;
OneMinusSrcColor:表示一个公式 ( 1 - source color )取他的反色;
OneMinusDestColor:表示一个公式 ( 1 - dest color )取他的反色;
OneMinusSrcAlpha:表示一个公式 ( 1 - source alpha )取他的反色;
OneMinusDestAlpha:表示一个公式 ( 1 - dest alpha )取他的反色;
雾控制命令:Fog
Fog是用来表示雾效的,这个雾效是为了弱化物体细节的,随着物体深度值的增大而逐渐弱化细节问题,最终只剩下轮廓;雾化是一种节省绘制的手段。
对于Fog命令我们可以通过Unity引擎开启全局雾化,也可以通过通过着色器代码单独开启或关闭雾化效果;
格式:Fog {命令集合 }
Mode :雾的现实模式 : off / Liner / Exponential / Exp2;
注意:如果选择off表示关闭雾效果,不受到雾效果的影响;
Color:用来设定雾的颜色;
Density:雾的浓度,1表示太浓了,0表示没有雾;
Range :指定雾浓度变化的范围;