前言
开始着手写Unity Shader之前,有必要了解一下用什么语言来写,Unity支持自家的Surface Shaders,GLSL,Cg/HLSL这几种方式来写,经过比较决定使用Cg/HLSL来写,今天就来初步学习一下Cg/HLSL语言,为接下来的使用做准备。
为什么Cg/HLSL是最佳选择
- GLSL:Unity支持GLSL,这是OpenGL的Shader语言,在GLSLPROGRAM … ENDGLSL块中编写,Unity会将这部分代码编译到任何平台,但对Windows或游戏机支持的不好,如果只是做手游的Android和IOS平台,用Mac做开发可以选择GLSL.
- Surface Shaders:可以用Unity shader库做很酷的东西。但在移动设备上不一定有效果。Shader库封装了许多功能,简化了开发,但同时也失去了对手游需要的控制和性能选项。Surface Shader只是自动帮你完成那些需要手写的、重复的通用代码。你仍然是要用CG/HLSL语言来编写Surface Shader。
- Cg/HLSL:为什么要把Cg/HLSL放到一块呢。因为Cg和HLSL就是同一个语言只是由NVIDIA和Microsoft两家公司分别维护,现在NIVIDIA已经停止维护Cg了,Microsoft在维护HLSL.Cg/HLSL可以被编译到需要的任何设备,而且Unity和微软已经亲密的像兄弟一样,在Unity中新建shader,默认也是CG语言也就是HLSL语言,所以HLSL是Unity shader的首选。
先来看一段Unity中的CG程序
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
fixed4 color : COLOR;
};
struct v2f
{
float4 vertex : SV_POSITION;
half2 texcoord : TEXCOORD0;
fixed4 color : COLOR;
};
v2f o;
v2f vert (appdata_t v)
{
o.vertex = UnityObjectToClipPos(v.vertex);
o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
o.color = v.color;
return o;
}
fixed4 frag (v2f IN) : COLOR
{
return tex2D(_MainTex, IN.texcoord) * IN.color;
}
ENDCG
CG程序被放到CGPROGRAM…ENDCG的声明块中,指明这里是写CG语言。CG语言非常像C语言的语法,有C,C++,Java等基础的非常好掌握。
编译指令#pragma
告诉编译器需要用到的函数和一些编译项的设置
- #pragma vertex name–指定vertex顶点shader的函数,name是函数名
- #pragma fragment–指定fragment片段shader的函数
- #pragma geometry name–指定geometry几何shader的函数(DX10以上)
- #pragma hull name–指定hull外壳着色器 Shader(细分着色的部分,主要负责定义细分等级(LOD)和相关控制点在细分中的“形变”趋势,DX11)
- #pragma domain name–指定domain域着色器Shader(负责的最重要的功能就是通过贴图控制的方式,实现模型的形变,DX11)
- #pragma target name–指定编译目标版本以适应不同的GPU
- #pragma require feature-细粒度控制shader需要GPU的哪个特性
- #pragma only_renderers space separated names–只编译指定的渲染器,默认编译所有的渲染器
- #pragma exlude_renderers space separated names –不编译指定的渲染器
- #pragma multi_compile … -指定 multiple shader variants
- #pragma enable_d3d11_debug_symbols-为
- #pragma hardware_tier_variants renderer name–为每一个编译的shader生成 multiple shader hardware variants
-其中#pragma vertex 和 #pragma fragment必须有,其它视情况选择使用。
编译指令#include
这个和C,C++一样,表示包含外部的脚本文件。这里指包含Unity预先定义好的公共UnityCG.cginc库。
数据类型
- 基本数据类型:float,half两种浮点类型,int整形,fixed定点数,bool布尔值,sampler*纹理对象句柄(sampler2D,sampler3D,samplerCUBE),string字符类型
- 内置向量数据类型:float4,表示float类型的4元向量;bool4,表示bool类型4元向量,fixed4表示整型4元向量,可以声明float1,float2,float3,float4类型的数组变量,初始化方式为:float4 array=float4(1.0,2.0,3.0,4.0),其它一样;
- 内置矩阵数据类型:最大的维数不能超过4X4阶。float4x4 matrix4;表示4X4阶矩阵,初始化方式为float2x2 matrix4 = {1.0,2.0,3.0,4.0},其它一样。
- 数组:和C\C++声明方法一样:float4 b[10];向量和矩阵是内置数据类型,数组则是一种数据结构。
- 结构体:Cg中的结构体的声明、使用和C++相似,一般用于传递数据类型较多的情况,参照上面例子的用法。
- 类型转换和C一样,使用强制转换
- 类型定义可在常量后跟后缀,有f,h,x(fixed),如2.0f,1.0h,3x
语义
通过语义绑定机制,指定数据存放的位置,即将输入\输出数据和寄存器做一个映射关系。
- POSITION:用于vertex shader 输入,输出,fragment shader的输入,代表位置信息
- NORMAL:用于vertex shader 输入,代表顶点法线
- BINORMAL:用于vertex shader输入,代表顶点次法线
- BLENDINDICES:用于vertex shader输入,代表四个影响顶点的骨骼的索引
- BLENDWEIGHT:用于vertex shader输入,代表四个骨骼影响顶点的加权百分比
- TANGENT:用于vertex shader输入,代表顶点切线空间
- PSIZE:用于vertex shader输入,输出,fragment shader的输入,代表点的大小Point size
- TEXCOORD0~TEXCOORD7:用于vertex shader输入,输出,fragment shader的输入,代表贴图
- FOG:vertex shader 输出,fragment shader 输入,代表雾
- COLOR0~COLOR1:vertex shader 输出,fragment shader 输入,代表颜色
- COLOR:fragment shader 输出,代表颜色
- SV_POSITION:SV_前缀的变量代表system value,DX10之后推荐使用SV_POSITION作为vertex shader的输出和fragment shader的输入,注意vertex shader的输入还是使用POSITION
语义绑定的几种形式
- [const][in|out|inout][:][=]
- struct {
[:];
}; - ()[:
函数
函数的定义和声明,同C语法类似
内置函数库
- reflect 求发射向量
- refract 求折射向量
- mul 矩阵相乘
- normalize 归一化
- 五大类: 数学函数、几何函数、纹理映射函数、调试函数
Swizzle操作符:
- 可以使用Cg语言中的swizzle操作符(.)将一个向量的成员取出组成一个新的向量。
- swizzle操作符后接x、y、z、w,分别表示原始向量的第一个、第二个、第三个、第四个元素
- swizzle操作符后接r、g、b和a的含义与前者等同。不过为了程序的易读性,建议对于表示颜色值的向量,使用swizzle操作符后接r、g、b和a的方式。
- 举例来说:float4(a, b, c, d).xyz 等价于float3(a, b, c)
swizzle操作符只能对结构体和向量使用,不能对数组使用
特定关键字,修饰函数的参数
- in:输入
- out :输出
- inout:输入输出
- uniform (被修饰的变量从外部传入)
- const: 常量
总结
以上就是CG的主要语法,比较好掌握,内置的函数,vertex shader,fragment shader的具体执行和调用方式,在真正写Shader后再慢慢学习,这篇主要是为之后的编写Shader做准备。
本文介绍了Unity Shader中Cg/HLSL语言的基础知识,包括为何选择Cg/HLSL、编译指令如#pragma和#include的用法、数据类型、语义、函数以及内置函数库。通过实例解析,帮助读者理解Shader编程的关键概念。

877

被折叠的 条评论
为什么被折叠?



