(二)Unity Shader基础知识(上)
一、Unity Shader概述
没有Unity编辑器情况下的shader编码(伪代码):
Main.cs
1 Void InitializationI(){ 2 3 //从硬盘上加载顶点着色器代码 4 5 String vertexShaderCode =LoadShaderFromFile(VertexShader.shader); 6 7 //从硬盘上加载片元着色器代码 8 9 String fragmentShaderCode = LoadShaderFromFile(FragmentShader.shader); 10 11 //把顶点着色器加载到GPU中 12 13 LoadVertexShaderFromString(vertexShaderCode); 14 15 //把片元着色器加载到GPU 16 17 LoadFragmentShaderFromString(fragmentShaderCode); 18 19 20 21 //设置名为”VertexPosition”的属性的输入,即模型顶点坐标 22 23 SetVertexShaderProerty(“VertexPosition”,vertices); 24 25 //设置名为”MainTex”的属性的输入,someTexture是某张已加载的纹理坐标 26 27 SetVertexShaderProerty(“MainTex”,someTexture); 28 29 //设置名为”MVP”的属性的输入,MVP是之前由开发者计算好的变换矩阵 30 31 SetVertexShaderProerty(“MVP”,MVP); 32 33 34 35 //关闭混合 36 37 Disable(Blend); 38 39 //设置深度测试 40 41 Enable(ZTest); 42 43 SetZTestFunction(LessOrEqual); 44 45 //其他设置 46 47 ... 48 49 50 51 } 52 53 //每一帧进行渲染 54 55 Void OnRendering(){ 56 57 //调用渲染命令 58 59 DrawCall(); 60 61 //当涉及多种渲染设置时,我们可能还需要在这里进行改变各种渲染设置 62 63 ... 64 65 }
VertexShader.shader
1 //输入:顶点位置、纹理、MVP变换矩阵 2 3 In float3 VertexPosition; 4 5 In sampler2D MainTex; 6 7 In Matrix4x4 MVP; 8 9 //输出:顶点经过MVP变换后的位置 10 11 Out float4 position; 12 13 Void main(){ 14 15 //使用MVP对模型顶点进行坐标进行变换 16 17 Position = MVP * vertexPosition; 18 19 }
FragmentShader.shader
1 //输入VertexShader输出的Position、经过光栅化程序插值后的该片元对应的Position 2 3 In float4 position; 4 5 //输出:该片元的颜色值 6 7 Out float4 fragColor; 8 9 Void main(){ 10 11 //将片元颜色设为白色 12 13 fragColor = float4(1.0,1.0,1.0,1.0); 14 15 }
该伪代码已经简化,随着渲染的工程量变大,上述过程变得更加复杂和冗长,Unity Shader的出现为了改善上述情况。
1、材质和Unity Shader
使用Unity Shader常见流程,如下图:

2、Unity中的材质
创建材质的方法:
- 第一种,在Unity菜单栏中选择Assets->Create->Material
- 第二种,在Project视图右击->Create->Material
- 第三种,贴图拖至游戏对象会直接生成一个材质
默认情况下,新建的材质将使用Unity内置的Standard Shader,这是一种基于物理渲染的着色器。
3、Unity中的shader
创建shader的方法:
- 在Unity的菜单栏中选择Assets->Create->shader
- 在Project视图中右击->Create->shader
在Unity5.2以及以上版本中,Unity一共提供了4种Unity Shader模板来让我们选择:
- Standard Surface Shader
- Unlit Shader
- Image Effect Shader
- Compute Shader
- Standard Surface Shader
包含了一个标准光照模型的表面着色器模板。
- Unlit Shader
产生一个不会包含光照的基本的顶点/片元着色器。
- Image Effect Shader
为我们实现各种屏幕后处理效果提供了一个基本模板。
- Compute Shader
产生一种特殊的Shader文件,这类shader旨在利用GPU的并行性来进行一些与常规渲染流水线无关的计算。

以表面着色器为例:
- 红色区域:单击Show generated code生成一个新文件,该文件将显示Unity在背后为该表面着色器生成的顶点/片元着色器。可以方便我们对生成的代码进行研究。
- 紫色区域:用来查看该固定函数着色器生成的顶点/片元着色器。
- 绿色区域:Compiled and show code可以让开发者检查该Unity Shader针对不同图像编程接口(例如OpenGL、D3D9、D3D11)最总编译成shader代码。
二、Unity Shader的基础:shaderLab
一、什么是shaderLab?
Unity Shader是Unity为开发者提高的高级层的渲染抽象层。和这层抽象层打交道的途径就是通过使用Unity提供的一种专门为Unity Shader服务的语言——ShaderLab。

在Unity中,所有Unity Shader都是使用ShaderLab来编写。ShaderLab是Unity提供的编写UnityShader的一种说明性语言。它使用了一些嵌套在花括号内部的语义(syntax)来描述一个UnityShader文件的结构。这些结构包含了许多渲染所需的数据。他们都定义了要显示一个材质所需的所有东西,而不仅仅是着色器代码。
一个UnityShader的基础结构如下所示:
1 Shader”ShaderName”{ 2 Properties{ 3 //属性 4 } 5 SubShader{ 6 //显卡A使用的着色器 7 } 8 SubShader{ 9 //显卡B使用的着色器 10 } 11 Fallback “VertexLit” 12 }
Unity在背后会根据适用平台把这些结构编译成真正的代码和shader文件,而开发者只需要和ShaderLab打交道即可。
二、Unity Shader的结构
1、Unity Shader的命名
每个Unity Shader文件的第一行都需要通过Shader语义来指定Unity Shader的名字。这个名字通过字符串来定义,这个名称会显示在材质列表里。例如:
1 Shader “Custom/MyShader”{}
2、材质和Unity Shader的桥梁:Properties
Properties语义块包含了一系列属性(Property),这些属性将会出现在材质面板。格式如下:
1 Properties{ 2 3 Name(“Display Name”,PropertyType)=DefaultValue; 4 5 Name(“Display Name”,PropertyType)=DefaultValue; 6 7 //更多属性 8 9 }
属性名字Name:shader中访问的变量,在Unity中通常由一个_下划线开始。
显示名称Display name:出现在材质面板上的名字。
属性类型PropertyType:一些常见的属性的类型。
属性类型DefaultValue:属性的默认值。

Int、Float、Range这些数字类型的属性,其默认值就是一个单独的数字。
Color和Vector这类属性,其默认值是一个四维向量。
2D、Cube、3D这三种纹理型,默认值是通过一个字符串后面跟一个花括号来指定,字符串要么为空,要么是内置的纹理名称。如“white”,“black”“gray”或者“bump”。{}内原本用于指定一些纹理属性,通过TexGenCubeReflect、TexGenCubeNormal等选项,控制固定管线的纹理坐标生成。Unity5.0以后的版本{}中选项移除,需自己在顶点着色器中编写计算相应纹理坐标。
Unity允许我们重载默认的材质编辑面板,以提供更多自定义的数据类型。在Properties语义块中声明这些属性,也可以直接在Cg代码片段中定义变量。我们也通过脚本向shader中传递这些属性,Proper
3、重量级成员:SubShader
Unity加载这个UnityShader时,会扫描所有的SubShader语义块,然后选择第一个可以在目标平台上运行的SubShader。如果都不支持使用Fallback语义指定的UnityShader。
SubShader{ //可选的标签 [Tags] //可选的状态 [RenderSetup] //定义一次完整的的渲染流程,Pass过多导致渲染性能下降 Pass{ //可以在Pass内声明状态和标签 } //Other Passes }
[RenderSetup]状态设置
常见的渲染设置状态设置选项,这些指令可以设置显卡的各种状态。

当在SubShader块中设置了上述渲染状态,将会应用到所有Pass。
[Tags]标签
SubShader的标签(Tags)是一个键值对(Key/Value Pair),它的键和值都是字符串类型。这些键值对是SubShader和渲染引擎之间的沟通桥梁。它告诉Unity如何渲染。
Tags标签的结构如下:
Tags{“TagName” = “Value” “TagName2” = “Value2”}

[Pass]语义块
Pass{ [Name]//定义该Pass名称 [Tags]//除SubShader中的标签可以用在这里外,还可以使用固定管线着色器 [RenderSetup] //other code }
Pass标签中使用的标签类型:

Unity内部会把所有Pass的名称转换成大写字母表示,在使用UsePass命令时必须使用大写形式的名字。
[其他特殊的Pass]
UsePass:可以使用UsePass命令,使用其他Unity Shader中的Pass。在使用UsePass命令时必须使用大写名字,例如:MyShader/MYPASSNAME
GrabPass:该Pass负责抓取屏幕并将结果存储在一张纹理中,以用来后续的Pass处理。
4、留一条后路:Fallback
紧跟所有SubShader语义块后面,可以是Fallback指令,它用于告诉Unity如果上面所有的SubShader在显卡上都不能运行,就使用最低级的Shader。
Fallback“最低级Shader名称” //或者 Fallback Off //关闭Fallback
Fallback会影响阴影的投射,在渲染阴影纹理时,Unity会在每个UnityShader中寻找一个阴影投射的Pass。通常我们不需要自己去实现这个,内置shader包含了这个东西。

浙公网安备 33010602011771号