Koo叔说Shader-CG语言介绍

前言

开始着手写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做准备。

你可能感兴趣的:(Shader与效果,koo叔说shader,shaderlab,CG语法)