ShaderLab中的CG语言
CG语句写在哪
百度 本版采写/新京报记者曾金秋CG需要写在Pass中,在CGPROGRAM和ENDCG之间
pragma申明编译指令
定义实现 顶点/片元着色器 代码的函数名称
pragma vertex 名字(实现顶点着色器的函数名)
pragma fragment 名字(实现片元着色器的函数名)
作用:将顶点/片元着色器实现 定位到这两个函数名中
因此只要在这两个函数中书写shader逻辑
数据类型
基础数据类型
区别:half(16位浮点数)、fixed(12位浮点数)、sampler(纹理对象句柄)
复合数据类型
一维数组
申明:int a[4] = {1,2,3,4}
长度:a.length
二维数组
int b[2][3] = {{1,2,3},{4,5,6}}
行:b.length
列:b[0].length
结构体
区别:结构体申明结束后加分号,一般在函数外申明
特殊数据类型
向量
//二维向量
fixed f2 = fixed2(1.2,2.5);
//三维向量
float3 f3 = float3(2,3,4);
//四维向量
int4 i4 = int4(1,2,3,4);
矩阵
//矩阵
int2x3 mInt2x3 = int2x3(1,2,3,
4,5,6);
float3x3 mFloat3x3 = float3x3(1,2,3,
4,5,6,
7,8,9);
fixed4x4 mFloat4x4 = fixed4x4(1,2,3,4,
5,6,7,8,
9,10,11,12,
13,14,15,16);
bool类型的特殊使用
//bool的特殊使用
float3 a = float3(1,2,3);
float3 b = float3(4,5,6);
bool3 c = a > b;
//运行后的结果为bool3(false,false,false)
总结:
Swizzle操作符
用.的形式使用,后面跟着所需的分量顺序
对于四维向量,可以用:向量.xyzw / 向量.rgba
前者表示坐标,后者表示颜色通道
fixed4 f4 = fixed4(1,2,3,4);
提取分量:
//提取分量:
//xyzw,rgba
//第一个分量
fixed f = f4.x;
f = f4.r;
//第二个分量
f = f4.y;
f = f4.g;
重新排列分量:
//重新排列:
f4 = f4.yzxw;
f4 = f4.abgr;
创建新向量:
//创建新的向量
fixed3 f3 = f4.xyz;
fixed2 f2 = f4.xz;
fixed4 f4_2 = fixed4(f2,f2);//升维需要补齐
f4_2 = fixed4(f3,f);//升维需要补齐
向量和矩阵的更多用法
把矩阵当作二维数组来用
用向量申明矩阵:
fixed4x4 f4x4 = {fixed4(1,2,3,4),
fixed4(5,6,7,8),
fixed4(9,10,11,12),
fixed4(13,14,15,16)};
f4x4 = {f4,
f4,
f4,
f4};
获取矩阵中的元素:
和获取二维数组的元素一样
f = f4x4[0][0];
利用向量获取矩阵中的某一行:
f4_2 = f4x4[0];
高维转低维:
直接赋值,自动在高维矩阵(向量)中截取低维矩阵(向量)部分
fixed3 f3_2 = f4;
f2 = f4;
fixed2x2 f2x2 = f4x4;
运算符相关
三目运算符:和C#一样
逻辑运算符: || && ! ,不存在短路,所以不管逻辑运算符满不满足都会执行完所有条件
数学运算符:CG中的取余%只能对整数取余,这和C语言一样
流程控制语句
和C#一样
注意:CG需要更多的考虑性能消耗
- 尽量少使用循环语句,并减少次数和复杂度
- 利用GPU并行性来替代循环
- 尽量避免复杂的条件分支
函数
in和out可以有多个
无返回值:
参数有in,out之分
输入参数不改,输出参数必须初始化/修改,可以在外部调用
in和out关键字可以省略,但最好不要这么做
有返回值:
参数只有in
对于顶点vert / 片元着色器frag函数只会用单返回值进行处理
顶点/片元着色器的基本结构
#pragma vertex myVert
#pragma fragment myFrag
//顶点着色器 回调函数
//POSITION 和 SV_POSITION 是CG语言的语义
//POSITION 模型的顶点坐标,填充到输入参数v中
//SV_POSITION 裁剪空间中的顶点坐标,填充到输出参数SV_POSITION中
//语义是用来限定输入输出参数,让渲染器知道用户的输入输出是什么
float4 myVert(float4 v:POSITION):SV_POSITION{
//mul():矩阵/向量的相乘
//UNITY_MATRIX_MVP:Unity内置的变换矩阵,是Unity内置模型、观察、投影矩阵的集合
//v:顶点坐标
return mul(UNITY_MATRIX_MVP, v);
//新版本把这个封装成了UnityObjectToClipPos(v)
}
//片元着色器 回调函数
//SV_Target 告诉渲染器,输出参数是SV_Target,
// 渲染器会把用户输出颜色储存到一个渲染目标中,输出到默认的帧缓存中
fixed4 myFrag(): SV_Target
{
return fixed4(1, 0, 0, 1);
}
效果:
语义——特殊关键字
修饰 函数的传入参数和返回值
作用:让Shader知道从哪里读取数据,并输出到哪里去
unity只支持CG的部分语义
常用语义
应用阶段->顶点着色器
顶点着色器->片元着色器
片元着色器的输出
其他语义
HLSL语义,CG语义
顶点/片元着色器获取更多数据信息
顶点着色器获取更多数据信息
使用结构体对数据封装,通过对结构体中的成员变量+语义的方式来定义想要获取的信息
struct a2v{
//顶点坐标
float4 vertex : POSITION;
//顶点法线
float3 normal : NORMAL;
//纹理坐标
float2 uv : TEXCOORD0;
};
float4 myVert(a2v data):SV_POSITION
{
return UnityObjectToClipPos(data.vertex);
}
片元着色器获取更多数据信息
片元着色器输入的数据基本都是由顶点着色器传递的
封装的结构体还需要顶点着色器的返回类型
v2f myVert(a2v data)
{
//传给片元着色器的数据结构体
v2f v2fData;
v2fData.pos = UnityObjectToClipPos(data.vertex);
v2fData.normal = data.normal;
v2fData.uv = data.uv;
return v2fData;
}
fixed4 myFrag(v2f data): SV_Target
{
return fixed4(0,1,0,1);
}
ShaderLab属性类型和CG变量类型的匹配关系
Shader三大属性:数值、颜色和向量,纹理贴图
Properties
{
//整形
_MyInt("My Int", Int) = 10
//浮点型
_MyFloat("My Float", Range(0,1)) = 0.5
//范围型
_MyRage("My Range", Range(0,10)) = 5
//颜色
_MyColor("My Color", Color) = (1,1,1,1)
//向量
_MyVector("My Vector", Vector) = (1,1,1,1)
//2D纹理
_My2D("My2D", 2D) = "white" {}
//2D数组纹理
_My2DArray("My2DArray", 2DArray) = "white" {}
//Cube map 纹理
_MyCube("MyCube", Cube) = "white" {}
//3D纹理
_My3D("My3D", 3D) = "white" {}
}
CG中变量类型对应的ShaderLab属性类型
如何在CG语句块中使用ShaderLab中申明的属性
直接在CG语句块中申明和属性对应类型的同名变量
CGPROGRAM
#pragma vertex myVert
#pragma fragment myFrag
float _MyInt;
float _MyFloat;
float _MyRage;
fixed4 _MyColor;
float4 _MyVector;
sampler2D _My2D;
samplerCUBE _MyCube;
sampler3D _My3D;
CG内置函数
1.数学函数
三角函数
向量、矩阵
数值相关
其他
2.几何函数
3.纹理函数
二维纹理
举例: