没有Unity这类编辑器的情况下,原生Shader的设置可能是这样的(伪代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void Initialization(){
//从硬盘上加载顶点着色器代码
string vertexShaderCode = LoadShaderFromFile(VertexShader.shader);
//从硬盘上加载片元着色器代码
string fragmentShaderCode = LoadShaderFromFile(FragmentShader.shader);
//把顶点着色器加载到GPU中
LoadVertexShaderFromString(vertexShaderCode);
//把片元着色器加载到GPU中
LoadFragmentShaderFromString(fragmentShaderCode);

//设置顶点着色器中定义的“vertexPosition”属性,vertices即模型顶点坐标
SetVertexShaderProperty("vertexPosition",vertices);
//设置顶点着色器中定义的“MainTex”属性,someTexture是某张已加载的纹理
SetVertexShaderProperty("MainTex",someTexture);
//设置顶点着色器中定义的“MVP”属性,MVP是之前由开发者计算好的变换矩阵
SetVertexShaderProperty("MVP",MVP);

Disable(Blend);//关闭混合
Enable(ZTest);//打开深度测试
SetZTestFunction(LessOrEqual);//设置深度测试
//其他设置…
}
//每一帧进行渲染
void OnRendering(){
//调用渲染命令
DrawCall();
//当涉及多种渲染设置时,我们可能还需要在这里改变各种渲染设置
}

VertexShader.shader文件:

1
2
3
4
5
6
7
8
9
10
11
12
//输入:顶点位置、纹理、MVP变换矩阵
in float3 vertexPosition;
in sampler2D MainTex;
in Matrix4x4 MVP;

//输出:顶点经过MVP变换后的位置
out float4 position;

void main(){
//使用MVP对模型顶点坐标进行变换
position = MVP * vertexPosition;
}

FragmentShader.shader文件:

1
2
3
4
5
6
7
8
//输入:VertexShader输出的position、经过光栅化程序插值后的该片元对应的position
in float4 position;
//输出:该片元的颜色值
out float4 fragColor;
void main(){
//将片元颜色设为白色
fragColor = float4(1.0,1.0,1.0,1.0);
}

当渲染模型的数目、需要调整的着色器属性不断增多时,代码会更加复杂冗长。而且当涉及透明物体等多物体渲染时,如果没有编辑器的帮助,我们要非常小心渲染顺序等问题。

UnityShader概述

材质和Unity Shader

UnityShader需要配合材质使用:

  1. 创建一个材质
  2. 创建一个UnityShader,并把它赋给上一步种创建的材质
  3. 把材质赋给要渲染的对象
  4. 材质面板中调整Unity Shader属性,以得到满意的效果。

material_shader

UnityShader集成了顶点着色器、片元着色器、属性(如纹理)和指令(渲染和标签设置等),通过材质来存储调节这些数据。

Unity中的材质

默认情况下,一个新建的材质使用Unity内置的Standard Shader,这是一种基于物理渲染的着色器。在材质面板最上方的下拉菜单中选择需要使用的Unity Shader

Unity中的Shader

  1. StandardSurface Shader:一个包含了标准光照模型(Unity基于物理的渲染方法)的表面着色器模板。
  2. Unlit Shader:不包含光照(但包含雾效)的基本顶点/片元着色器。
  3. Image Effect Shader:一个为了实现各种屏幕后处理效果的基本模板。
  4. Compute Shader:利用GPU的并行性来进行一些与渲染无关的计算。Unity - Manual: Compute shaders
  5. Ray-Tracing Shader:基于光线追踪的着色器。

点击一个Shader,就会显示Import Settings面板。下面是一个默认SurfaceShader的面板

shader_import_settings

Default Maps指定该Shader使用的默认纹理,任何材质使用此Shader就会自动赋予此纹理。

在新版Unity,会多出一个Override preprocessor选项,这个选项用来单独重载Shader预处理方式,默认是Use Project Settings(在Project Settings——Editor——Shader Compilation下)的设置,还可以单独设为“强制平台预处理”和“强制缓存预处理”。预处理阶段是Shader编译的第一步,不同的平台有不同的处理方式。

Surface shader:是否是一个表面着色器,是的话显示“Show generated code”按钮,否则显示“no”。

Fixed function:是否是一个固定函数着色器,是的话显示“Show generated code”按钮,否则显示“no”。

Preprocess Only(新版Unity):开启后显示预处理器的输出而不是编译后的Shader代码。?

Compiled code:点击Compile and show code,会有一个下拉列表查看该Unity Shader的图像接口,再点击show会看到底层的汇编指令。可以利用这些代码分析和优化着色器。

shader_compile_code

投射阴影、渲染队列、LOD值和Unity Shader中的“Tags”、“LOD”设置有关。

Properties:Shader的属性列表

ShaderLab

ShaderLab是Unity专门为Unity Shader服务的语言。而Unity Shader是为Unity开发者提供的高层级的渲染抽象层。

shaderlab_abstract

ShaderLab使用一些嵌套在花括号内部的语义(syntax)来描述一个UnityShader文件的结构。ShaderLab类似CgFX和Direct3D Effects(.FX)语言,它们都定义了要显示一个材质所需的所有东西,而不仅仅是着色器代码