1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| CGPROGRAM #pragma vertex vert #pragma fragment frag
//POSITION SV_POSITION 语义,不可省略,
//此处vert的frag名字必须与前面#pragma中定义的名字一样,否则会报错。 float4 vert(float4 v:POSITION):SV_POSITION { return UnityObjectToClipPos(v); } // float4 v:POSITION代表顶点信息(输入),float4代表4维向量。 // SV_POSITION 输出之后的在裁剪空间的顶点信息。
//片元着色器,最后返回到屏幕上,返回fixed4(1,1,1,1) fixed4 frag():SV_TARGET { return fixed4(1,1,1,1); }
ENDCG
|
结构体
输入结构体
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct a2v { //用模型顶点填充v变量 float4 v:POSITION; //用模型的发现填充n变量 float3 n:NORMAL; //NORMAL代表法线 //用模型的第一套uv填充texcoord float4 texcoord:TEXCOORD0; }; float4 vert(a2V v):SV_POSITION { return UnityObjectToClipPos(v.v); }
|
shader语法中只有结构体,可以代替过多的参数的输入,可以避免代码过于臃肿
输出结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| struct v2f// v vert dao frag { //SV_POSITION予以告诉unity :pos为裁剪空间中的位置信息 float4 pos:SV_POSITION; //COLOR0 语义可以储存颜色信息 fixed3 color:COLOR0; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); //将 -1~1这个区间转变为0~1区间的常用计算方法 o.color = v.normal * 0.5 + fixed3(0.5,0.5,0.5); return o; }
fixed4 frag(v2f i):SV_TARGET { return fixed4(i.color, 1); }
|
代替单一的返回
属性控制
在Properties里定义的属性,只有在CGPROGRAM内再次定义一个与属性块内米子与类型相同的变量,属性快对应的变量才能起作用。
1 2 3 4 5 6 7 8 9 10 11 12 13
| Properties { _MainTex ("Texture", 2D) = "white" {} _Color("Color", Color) = (1,1,1,1) } Pass { CGPROGRAM fixed4 _Color; ENDCG }
|
Shader库里的输入输出结构体
UnityCG.cginc文件中定义有一些结构体,使用其中的默认结构在直接引入便可以使用。
1 2 3 4
| Pass { #include "UnityCG.cginc" }
|
输入语义
1 2
| float4 v:POSITION float4 texcoord:TEXCOORD0;
|
例如:TEXCOORD0便是将第一套uv赋予texcoord,只用正确赋予,之后调用时才不会出错。POSITION便是将模型的顶点坐标赋予给v。
对于SV_TARGET和SV_POSITION这类语义比较特殊,不可以随便定义。SV_POSITION包含POSITION(一般建议不混用),在特殊平台混用会出错。

Shader MOdel各个版本中TEXCOORDn中n的支持个数。

输出结构体中常用语义

片元着色器输出时常用语义

表示矩阵可以使用4个float4表示
调试工具
方法一:使用输出调试
根据输出的颜色进行判别红色为(1,0,0),绿色为(0,1,0),蓝色为(0,0,1)
方法二:unity的工具Frame Debugger
方法三:使用第三方工具
Inter Gpa , Snapdragon Profiler等
平台差距
坐标差距:
这个unity平台会自动适应。当开启了Anti Aliasing(抗锯齿),并且同时吹多张渲染图像是,unity无法帮助我们翻转坐标此时我们需要在代码中自行翻转。代码如下:

UNITY_UV_STARTS_AT_TOP判断当前平台是否是DX平台,使用_MainTex_TexelSize.y < 0来判断是否开启了抗锯齿。
语法差异:
在DX中语言的定义更加的严格,例如如下写法:

前者在DX中是会报错的,必须要严格使用第二种写法。
在表面着色器中可能会需要对结构体进行初始化:

Cg
编译方式
Cg通常采用动态编译的方式(Cg也支持静态编译方式),即在宿主程序运行时,利用Cg运行库(Cg Runtimer Library)动态编译Cg代码。使用动态编译的方式,可以将Cg程序当做一个脚本,随时修改随时运行,节省时间,在OGRE图形引擎中就采用了这种方式。
Cg Profiles
Cg 程序的编译不但依赖于宿主程序所使用的三维编程接口,而且依赖于图形硬件环境,因为图形硬件自身的限制,不一定支持某种 Cg 语句。
被特定的图形硬件环境或 AIP 所支持的 Cg 语言子集,被称为Cg Profiles 。profile分为:顶点程序的profile和片段程序的profile,所以编译顶点着色程序时必须选用当前图形硬件支持的顶点profile ,同理,编译片段着色程序时必须选用当前图形硬件支持的片段profile 。顶点 profile 和片段 profile 又基于 OpenGL 和 DirectX 的不同版本或扩展,划分为各种版本。
基本数据类型
总共有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,half,fixed三种类型没有区别,所有的half和fixed都被换算为float进行计算。但是在手机端,三者需要区分开来。
数据结构
数组
数组数据类型在Cg中的作用:作为函数的形参,用于大量数据的传递,例如:顶点参数数组、光照参数数据等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 一维数组:
float a[10];//声明了一个数组,包含 10 个 float 类型数据
float a[4] = {1.0, 2.0, 3.0, 4.0}; //初始化一个数组
int length = a.length;//获取数组长度
多维数组:
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
|
结构体
结构体的声明以关键字 struct 开始,然后紧跟结构体的名字,接下来是一个大括号,并以分号结尾(不要忘了分号) 。大括号中是结构体的定义,分为两大类:成员变量和成员函数。
Shader Target
Unity中所支持的Shader Target

在Shader中计量少用if else和嵌套,因为部分Gpu会把if和else中的所有东西都会跑,会造成浪费,嵌套也是同理。
函数
基础函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 函数 功能描述 abs(x) 返回输入参数的绝对值 acos(x) 反余切函数,输入参数范围为[-1,1], 返回[0,π]区间的角度值 all(x) 如果输入参数均不为0,则返回ture; 否则返回flase。&&运算 any(x) 输入参数只要有其中一个不为0,则返回true。 asin(x) 反正弦函数,输入参数取值区间为,返回角度值范围为, atan(x) 反正切函数,返回角度值范围为 atan2(y,x) 计算y/x的反正切值。实际上和atan(x)函数功能完全一样,至少输入参数不同。atan(x) = atan2(x, float(1))。 ceil(x) 对输入参数向上取整。例如: ceil(float(1.3)) ,其返回值为2.0 clamp(x,a,b) 如果x值小于a,则返回a; 如果x值大于b,返回b; 否则,返回x。 cos(x) 返回弧度x的余弦值。返回值范围为 cosh(x) 双曲余弦(hyperbolic cosine)函数,计算x的双曲余弦值。 cross(A,B) 返回两个三元向量的叉积(cross product)。注意,输入参数必须是三元向量! degrees(x) 输入参数为弧度值(radians),函数将其转换为角度值(degrees) determinant(m) 计算矩阵的行列式因子。 dot(A,B) 返回A和B的点积(dot product)。参数A和B可以是标量,也可以是向量(输入参数方面,点积和叉积函数有很大不同)。
|
1 2 3 4 5 6 7 8 9 10 11 12
| exp(x) 计算的值,e=2.71828182845904523536 exp2(x) 计算的值 floor(x) 对输入参数向下取整。例如floor(float(1.3))返回的值为1.0;但是floor(float(-1.3))返回的值为-2.0。该函数与ceil(x)函数相对应。 fmod(x,y) 返回x/y的余数。如果y为0,结果不可预料。 frac(x) 返回标量或矢量的小数 frexp(x, out i) 将浮点数x分解为尾数和指数,即, 返回m,并将指数存入i中;如果x为0,则尾数和指数都返回0 isfinite(x) 判断标量或者向量中的每个数据是否是有限数,如果是返回true;否则返回false; isinf(x) 判断标量或者向量中的每个数据是否是无限,如果是返回true;否则返回false; isnan(x) 判断标量或者向量中的每个数据是否是非数据(not-a-number NaN),如果是返回true;否则返回false; ldexp(x, n) 计算的值 lerp(a, b, f) 计算或者的值。即在下限a和上限b之间进行插值,f表示权值。注意,如果a和b是向量,则权值f必须是标量或者等长的向量。 lit(NdotL, NdotH, m) N表示法向量;L表示入射光向量;H表示半角向量;m表示高光系数。 函数计算环境光、散射光、镜面光的贡献,返回的4元向量。 X位表示环境光的贡献,总是1.0; Y位代表散射光的贡献,如果 ,则为0;否则为 Z位代表镜面光的贡献,如果 或者,则位0;否则为;W位始终位1.0
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| log(x) 计算的值,x必须大于0 log2(x) 计算的值,x必须大于0 log10(x) 计算的值,x必须大于0 max(a, b) 比较两个标量或等长向量元素,返回最大值。 min(a,b) 比较两个标量或等长向量元素,返回最小值。 modf(x, out ip) 把x分解成整数和分数两部分,每部分都和x有着相同的符号,整数部分被保存在ip中,分数部分由函数返回 mul(M, N) 矩阵M和矩阵N的积 mul(M, v) 矩阵M和列向量v的积 mul(v, M) 行向量v和矩阵M的积 noise(x) 根据它的参数类型,这个函数可以是一元、二元或三元噪音函数。返回的值在0和1之间,并且通常与给定的输入值一样 radians(x) 函数将角度值转换为弧度值 round(x) 返回四舍五入值。 rsqrt(x) x的平方根的倒数,x必须大于0 saturate(x) 把x限制到[0,1]之间 sign(x) 如果则返回1;否则返回0
|
1 2 3 4 5 6 7 8 9
| sin(x) 输入参数为弧度,计算正弦值,返回值范围 为[-1,1] sincos(float x, out s, out c) 该函数是同时计算x的sin值和cos值,其中s=sin(x),c=cos(x)。该函数用于“同时需要计算sin值和cos值的情况”,比分别运算要快很多! sinh(x) 计算x的双曲正弦 smoothstep(min, max, x) 值x位于min、max区间中。如果x=min,返回0;如果x=max,返回1;如果x在两者之间,按照下列公式返回数据: step(a, x) 如果,返回0;否则,返回1 sqrt(x) 求x的平方根,,x必须大于0 tan(x) 计算x正切值 tanh(x) 计算x的双曲线切线 transpose(M) 矩阵M的转置矩阵
|
几何函数
1 2 3 4 5 6 7
| distance(pt1, pt2) 两点之间的欧几里德距离(Euclidean distance) faceforward(N,I,Ng) 如果,返回N;否则返回-N。 length(v) 返回一个向量的模,即sqrt(dot(v,v)) normalize(v) 返回v向量的单位向量 reflect(I, N) 根据入射光纤方向I和表面法向量N计算反射向量,仅对三元向量有效 refract(I,N,eta) 根据入射光线方向I,表面法向量N和折射相对系数eta,计算折射向量。如果对给定的eta,I和N之间的角度太大,返回(0,0,0)。 只对三元向量有效
|
纹理映射函数
1 2 3 4 5 6
| tex1D(sampler1D tex, float s) 一维纹理查询 tex1D(sampler1D tex, float s, float dsdx, float dsdy) 使用导数值(derivatives)查询一维纹理 Tex1D(sampler1D tex, float2 sz) 一维纹理查询,并进行深度值比较 Tex1D(sampler1D tex, float2 sz, float dsdx,float dsdy) 使用导数值(derivatives)查询一维纹理, 并进行深度值比较 Tex1Dproj(sampler1D tex, float2 sq) 一维投影纹理查询 Tex1Dproj(sampler1D tex, float3 szq) 一维投影纹理查询,并比较深度值
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Tex2D(sampler2D tex, float2 s) 二维纹理查询 Tex2D(sampler2D tex, float2 s, float2 dsdx, float2 dsdy) 使用导数值(derivatives)查询二维纹理 Tex2D(sampler2D tex, float3 sz) 二维纹理查询,并进行深度值比较 Tex2D(sampler2D tex, float3 sz, float2 dsdx,float2 dsdy) 使用导数值(derivatives)查询二维纹理,并进行深度值比较 Tex2Dproj(sampler2D tex, float3 sq) 二维投影纹理查询 Tex2Dproj(sampler2D tex, float4 szq) 二维投影纹理查询,并进行深度值比较 texRECT(samplerRECT tex, float2 s) 二维非投影矩形纹理查询(OpenGL独有) texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy) 二维非投影使用导数的矩形纹理查询(OpenGL独有) texRECT (samplerRECT tex, float3 sz) 二维非投影深度比较矩形纹理查询(OpenGL独有) texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy) 二维非投影深度比较并使用导数的矩形纹理查询(OpenGL独有) texRECT proj(samplerRECT tex, float3 sq) 二维投影矩形纹理查询(OpenGL独有) texRECT proj(samplerRECT tex, float3 szq) 二维投影矩形纹理深度比较查询(OpenGL独有) Tex3D(sampler3D tex, float s) 三维纹理查询 Tex3D(sampler3D tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值(derivatives)查询三维纹理 Tex3Dproj(sampler3D tex, float4 szq) 查询三维投影纹理,并进行深度值比较 texCUBE(samplerCUBE tex, float3 s) 查询立方体纹理 texCUBE (samplerCUBE tex, float3 s, float3 dsdx, float3 dsdy) 结合导数值(derivatives)查询立方体纹理 texCUBEproj (samplerCUBE tex, float4 sq) 查询投影立方体纹理
|