UnityShader基础

最简单的Shader

设置模型的颜色为白色

image-20241029180920202

输入结构体

image-20241029182310609

按照给定的名字进行使用,Unity会自动为结构体填充内容,texcoord使用 0 ,是大家公认的第一套UV;

对结构体名字的解释

a:application,即从渲染流中通过Unity自动添加的

2:即 to 的谐音,

v:vertex,代表顶点着色器

最后意思是从程序中输入到顶点着色器中的结构体

输出结构体

image-20241029183838169

属性控制

1
2
3
4
5
_Color("Color",Color)=(1,1,1,1) //在属性块中的属性

fixed4 _Color;//要想在SubShader中使用以上属性就需要在CGPROGRAM按照当前格式定义,名字必须相同

//对于 _Color在着色器中的访问,可以使用xyzw或者rgba,来抽取当中的色彩块

库自带输入输出结构体

在UnityCG.cginc库文件中,有官方已经实现的输入结构和部分输出结构,使用的时候使用C++的头文件导入形式

1
#include "UnityCg.cginc"
1
2
3
4
5
6
7
8
9
10
11
struct appdata full{
float4 vertex:POSITION;//顶点
float4tangknt :TANGENT;//切线
float3 normal:NORMAL;//法线
float4 texcoord :TEXCOORD0;
float4 texcoord1 :TEXCOORD1;
float4 texcoord2 :TEXCOORD2;
float4 texcoord3 :TEXCOORD3;
fixed4 color :COLOR;
UNITY_VERTEX_INPUT_INSTANCE
};

着色器语意

顶点着色器输入结构中的常见语义

语义 描述
POSITION 模型空间中的顶点位置,通常是float4类型
NORMAL 顶点法线,通常是float3类型
TANGENT 顶点切线,通常是float4类型
TEXCOORDn,如TEXCOORD0,TEXCOORD1 该顶点的纹理坐标,TEXCOORD0表示第一组坐标纹理,依次类推,通常是float2,float4类型
COLOR 顶点颜色,通常是fixed4或float4类型

简单介绍各个版本Shader中对于TEXCOORD的支持数量

Shader Model版本 TEXCOORDn中N的支持个数
Shader Model2 8
Shader Model3 8
Shader Model4 16
Shader Model5 16

顶点着色器输出结构体中常用语义

语义 描述
SV_POSITION 裁剪空间中的顶点坐标,结构体中必须包含一个用该语义修饰的变量。等同于DX9中的POSITION。
COLOR0 通常用于输出第一组顶点颜色,不是必须
COLOR1 通常用于输出第二组顶点颜色,不是必须
TEXCOORD0-TEXCOORD7 通常用于输出纹理坐标,不是必须

片元着色器输出时的常见语义

语义 描述
SV_Target 输出值将会储存到渲染目标(render target)中。等同于DX9中COLOR语义。

调试

颜色测试输出

1
2
3
4
5
6
7
8
9
v2f o;
o.pos = UnityObjectToclipPos(v.vertex);
//法线
//法线的范围在(-1,1)之间,需要规范到颜色的(0,1) 的区间内
o.color =v.normal*0.5 +fixed3(0.5,0.5,0.5);
//切线
o.color =v.tangent.xyz*0.5 + fixed3(0.5,0.5,0.5);
//UV
o.color =fixed4( v.texcoord.xy,0,1);

FrameDebug

在Unity的windows工具类中,在性能分析那一栏,选中可以使用Frame Debug对Shader的每个阶段进行排查测试

image-20241030095855290

第三方工具:Inter Gpa , Snapdragon Profiler等

平台差异

抗锯齿下的手动翻转

image-20241030100740037

开启Anti Aliasing,并且同时处理多张渲染图像是,DX平台需要翻转

image-20241030100757192

UNITY_UV_STARTS_AT_TOP判断当前平台是否是DX平台,使用_MainTex_TexelSize.y<0来判断是否开启了抗锯齿。

知识补充:开启Anti Aliasing 抗锯齿可以通过项目设置的质量进入

image-20241030102501291

不同图形接口的数据初始化

1
2
float4 v= float4(0);//OpenGL
float4 v=float4(0,0,0,0);//DX,DX的初始化更严格

表面着色器中初始化

1
UNITY_INITIALIZE_OUTPUT(Input,o);

Cg数据类型

1,基本数据类型:Cg支持7种基本的数据类型,分别是:

float, 32 位浮点数据,一个符号位。浮点数据类型被所有的 profile 支持

half,16 为浮点数据

int,32 位整形数据,有些 profile 会将 int 类型作为 float 类型使用

fixed,12 位定点数,被所有的 fragment profiles 所支持

bool,布尔数据,通常用于 if 和条件操作符( ?: ) ,布尔数据类型被所有的profiles 支持

simpler*, 纹理对象的句柄( the handle to a texture object ) ,分为 6 类:

sampler, sampler1D, sampler2D, sampler3D, samplerCUBE, 和 samplerRECT 。DirectX profiles 不支持 samplerRECT 类型, 除此之外这些类型被所有的 pixelprofiles 和 NV40 vertex program profile 所支持( CgUsersManual 30 页) 。由此可见,在不远的未来,顶点程序也将广泛支持纹理操作

string,字符类型,该类型不被当前存在的 profile 所支持,实际上也没有必要在 Cg 程序中用到字符类型,但是你可以通过 Cg runtime API 声明该类型变量,并赋值;因此,该类型变量可以保存 Cg 文件的信息。

​ 前6种类型为常用类型,string类型几乎不使用。此外,Cg还提供了内置的向量数据类型 (built-in vector data types) ,内置的向量数据类型基于基础数据类型。 例如: float4, 表示 float 类型的 4 元向量; bool4, 表示 bool类型 4 元向量。

不同类型的浮点数在pc上最终被改变为float进行计算,而移动端上的fix又是一个古老的东西,现在基本不使用,因此在编写的时候时候围绕 half 和 float 进行曹组就可以了

2.数组

数组数据类型在Cg中的作用:作为函数的形参,用于大量数据的传递,例如:顶点参数数组、光照参数数据等。

一维数组:

1
2
3
4
5
float a[10];//声明了一个数组,包含 10 个 float 类型数据

float a[4] = {1.0, 2.0, 3.0, 4.0}; //初始化一个数组

int length = a.length;//获取数组长度

多维数组:

1
2
3
4
5
float b[2] [3] = {{0.0, 0.0, 0.0},{1.0, 1.0, 1.0}};

int length1 = b.length; // length1 值为 2

int length2 = b[0].length; // length2 值为 3

3,结构体

结构体的声明以关键字 struct 开始,然后紧跟结构体的名字,接下来是一个大括号,并以分号结尾(不要忘了分号) 。大括号中是结构体的定义,分为两大类:成员变量和成员函数。

Unity支持的Shader Target

指令 描述
#pragma target 2.0 相当于D3D9上的Shader Model2.0,不支持顶点纹理采样,不支持显示的LOD纹理采样
#pragma target 3.0 相当于D3D9上的Shader Model3.0 支持顶点纹理采样
#pragma target 4.0 相当于 D3D10上的Shader Model4.0支持几何着色器
#pragma target 5.0 相当于D3D11上的Shader Model5.0

补充

尽量少用if else,分支中指令尽量少

GPU并行运行的特性,ifelse中的每个分支都会运行一次,但是最终有些没用上,浪费资源