Koo叔说Shader-CG语言介绍

作者: koo叔 分类: 专栏 发布时间: 2018-05-31 22:31 编辑

前言

开始着手写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},其它一样。
  • 数组:和CC++声明方法一样: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<type><identifier>:<binding-semantic>
  • struct <struct-tag>{

    <type><identifier>[:<binding-semantic>];

    };

  • <type><identifier>(<parameter-list>)[:<binding-semantic]{<body>}

函数

函数的定义和声明,同C语法类似

内置函数库

  • reflect 求发射向量
  • refract 求折射向量
  • mul 矩阵相乘
  • normalize 归一化
  • 五大类: 数学函数、几何函数、纹理映射函数、调试函数

特定关键字,修饰函数的参数

  • in:输入
  • out :输出
  • inout:输入输出
  • uniform (被修饰的变量从外部传入)
  • const: 常量

总结

以上就是CG的主要语法,比较好掌握,内置的函数,vertex shader,fragment shader的具体执行和调用方式,在真正写Shader后再慢慢学习,这篇主要是为之后的编写Shader做准备。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

你的email不会被公开。必填项已用*标注

更多阅读
标签云