一、Unity Shader基础
1、创建和使用Shader
在Unity中Shader一般由两种用途:
- 指定给材质,用于物理渲染;
- 指定给脚本,用于图像处理,比如后期处理(Post Processing);
2、Unity渲染管线Shader的编写方式
- 顶点-片段着色器(Vertex and Fragment Shader);
- 表面着色器(Surface Shader);
- 固定函数着色器(Fixed Function Shader,目前逐渐被抛弃);
二、CG语法基础
1、编译指令
CG常用的编译指令:
(1) 编译目标等级
CG代码编译到不同的Shader Models中,要适应对应的GPU平台,否则会出现一些Shader在GPU上无法运行。
声明编译目标的级别#pragma target name
也可以使用#pragma require feature
指令直接声明某个特定的功能。
#pragma target 3.5 //目标等级3.5 #pragma require geometry tessellation //需要几何体细分功能
(2) 渲染平台
Unity具有跨平台的特性,它支持很多渲染API,例如Direct3D、Opengl。默认情况下,Unity会为所有支持的平台编译一份Shader程序,但需要指定编译某些平台或不编译某些平台。
使用示例:
#pragma only_renderers d3d11 //目标只编译Direct3D 11/12 平台 #pragma exclude_renderers glcore //不编译 OpenGL 3.x/4.x
2、着色器函数
一个基本的Shader示例:
Shader "Custom/Simplest Shader" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag void vert (in float4 vertex : POSITION, out float4 position : SV_POSITION) { position = UnityObjectToClipPos(vertex); } void frag (in float4 vertex : SV_POSITION, out fixed4 color : SV_TARGET) { color = fixed4(1, 0, 0, 1); } ENDCG } } }
在Shader中,顶点-片元着色器主要通过顶点函数和片元函数来实现的。
(1) 无返回值函数
上述Shader中的顶点函数和片元函数使用的是无返回值的函数,通过out关键字将变量输出。
语法结构如下:
void name(in 参数,out 参数) { //函数体 }
void:函数以void开头,表示返回值为空;
name:定义函数名称;
in:输入参数,语法为:in+数据类型+名称,一个函数可以有多个输入,关键词 in 可省略。
out:输出参数,语法为:out+数据类型+名称,一个函数可以有多个输出。
(2) 有返回值的函数
语法结构如下:
type name(in 参数) { //函数体 return 返回值; }
3、语义
CG语言编写着色器函数时,函数的输入参数和输出参数都需要填充一个语义(Semantic)来表示它们要传递的数据信息。
语义可以执行大量繁琐的操作,使用户能够避免直接于GPU底层进行交流。
参数后被冒号隔开并且全部大写的关键词就是语义。
(1) 顶点这着色器的输入语义
顶点数据是以输入参数的方式传递给顶点函数的,每一个输入的参数都需要填充一个语义,用于表示所传递的数据。
注意:
当顶点信息包含的元素少于顶点着色器输入所需要的元素时,缺少的部分会被0填充, w分量会被1填充; 如:输入语义TEXCOOED0被声明为float4类型,那么顶点着色器最终获取到的数据为 ( x , y , 0 , 1 ) (x,y,0,1) (x,y,0,1)
(2) 顶点这着色器输出和片元着色器输入语义
在整个渲染流水线中,顶点着色器最重要的的一项人物就是需要输出顶点在裁剪空间中的坐标,这样GPU就可以知道顶点在屏幕上的栅格化位置以及深度值。在顶点函数中这个输出参数值需要使用float4类型的SV_POSITION语义填充。
顶点着色器产生的输出值将会在三角形便利阶段经过插值计算,最终作为像素值输入到片元着色器。
换句话说,顶点着色器的输出就是片元着色器的输入。
片元着色器会自动获取顶点着色器输出的裁切空间顶点坐标,所以片元函数输入的SV_POSITION可以省略。
注意:
与顶点函数的输入语义不同,TEXCOORDn不再特指模型的UV坐标,COLORn也不在特指顶点颜色。它们使用范围更广,可以用于声明任何符合要求的数据。
(3) 片元着色器输出语义
片元着色器通常只会输出一个fixed4类型的颜色信息,输出的值会存储到渲染目标(Render Target),输出参数使用SV_TARGET语义进行填充。