Unity&Shader基础篇-Cg语法

https://blog.csdn.net/zhangxiao13627093203/article/details/52850518


转载请注明出处凯尔八阿哥专栏

1.2、Cg语法基础

 如C++、C#和Java等高级语言一样,Cg语言也有自己的数据类型和关键字。掌握和理解这些关键字是写好Cg程序的基础。

1.2.1、Cg的数据类型与关键字

基本数据类型:Cg支持7种基本的数据类型

1、float,32位浮点数据,一个符号位。浮点数据类型被所有的图形接口支持;

2、half,16位浮点数据;

3、int,32位整形数据

4,fixed,12位定点数,

5、bool,布尔数据,被所有的图形接口支持;

6、sampler*,纹理对象的句柄,分为sampler、sampler1D、sampler2D、sampler3D、samplerCUBE和samplerRECT。

内置的数据类型:基于基础数据类型,如float3,表示float类型的三维向量;同理,bool2表示布尔类型的二维向量。

注:向量最长不能超过四元,如float5  vector;//编译错误

向量的赋值,float2 a=float(1.0,1.0);       //编译通过

            float2 a=float(1.0f,1.0f);     //编译错误

            float3 b=float(a,0.0);            //编译通过

矩阵数据类型,float1X1 m1;                    //即float m1,一维矩阵

              float3X4 m34                    //3*4阶矩阵

注:X是字符,不是乘号,最大的维数为4*4阶

矩阵的初始化 float 2*2 m22={1.0,2.0,3.0,2.3};

float3 x和floatx[3]是不同的,前者为向量是内置的数据类型,而数组则是一种数据结构,不是内置的数据类型。

类型转换:Cg中的类型转换有强制转换和隐式转换;如果是隐式转换则数据类型从低精度向高精度转换。如:

           float a=1.0;

           half b=2.0;

           float c=a+b;      //等价于float c=a+(float)b;

Cg语言中可以对常量数据加上类型后缀表示该数据类型的数据,如:

           float a=1.0h;     //1.0h为half类型常量数据

这样的后缀类型有三种:

f:表示float;

h:表示half;

x:表示fixed;

Swizzle操作符:Cg语言中的其他操作符和高级CPU语言C++类似,包括关系操作符、逻辑操作符和位移操作符以及条件操作符。而Swizzle操作符是Cg语言中特有的,它可以将一个向量的成员取出组成一个新的向量。对于坐标或者角度等其他多维向量,Swizzle操作符(.)后接x、y、z、w分别表示原始向量的第一个、第二个、第三个和第四个元素;同样,对于颜色可以后接r、g、b和a来表示同样的索引。

例如:

              float4(a,b,c,d).xwz  等价于 float(a,d,c)

              float4(a,b,c,d).xxy  等价于 float(a,a,b)

注:Swizzle操作符只对结构体和向量使用,不能对数组使用。

输入数据关键字:Cg中输入数据流一般分为两类

1、varying 参数:在Cg程序中通过语义进行绑定变量, Cg语言提供了一组语义词,用以表示参数是由顶点的那些数据初始化的,一旦这个变量使用了语义词进行绑定,那么这个变量值被初始化的同时也意味着它有了特殊的含义,如表示位置、法线等含义。语义提供了一种使用随顶点变化或随片段变化而变化的值来初始化Cg程序参数的方法,这些数据都是从应用程序输入到GPU的数据,如顶点位置、法向量、纹理坐标数据等。

2、Uniform 参数:Uniform是用来限制一个变量的初始值的来源,当声明一个变量为Uniform类型的时候,表示这个变量的初始值来自于外部的其他环境。除了获取初始值的这点之外,Uniform关键字声明的变量和其他变量是完全一样的。通常用Uniform来定义一些与三维渲染有关的离散信息数据,并通常不会随着图元信息的变化而变化,如材质对光的反射信息。Uniform表示一个参数,通常使用uniform表示函数的形参,不能定义一个uniform表示的局部变量。

Unity的内置Uniform输入参数如下:

uniform float4 _Time, _SinTime, _CosTime; // 时间量

uniform float4 _ProjectionParams; // x = 1 or -1 (如果投影翻转就是-1)

// y = 近平面; z = 远平面; w = 1/远平面

uniform float4 _ScreenParams; // x = width; y = height; z = 1 +1/width; w = 1 + 1/height

 uniform float3_WorldSpaceCameraPos;

uniform float4x4 _Object2World; //模型矩阵

uniform float4x4 _World2Object; // 模型矩阵的逆

uniform float4 _LightPositionRange; // xyz = pos, w = 1/range

uniform float4 _WorldSpaceLightPos0; // 光源的位置和方向

uniform float4x4 UNITY_MATRIX_MVP; // 模型视图投影矩阵

uniform float4x4 UNITY_MATRIX_MV; // 模型视图矩阵

uniform float4x4 UNITY_MATRIX_V; // 视图矩阵

uniform float4x4 UNITY_MATRIX_P; // 投影矩阵

uniform float4x4 UNITY_MATRIX_VP; // 视图投影矩阵

uniform float4x4 UNITY_MATRIX_T_MV; // 模型视图矩阵的转置矩阵

uniform float4x4 UNITY_MATRIX_IT_MV; // 模型视图矩阵的逆矩阵的转置矩阵

uniform float4x4 UNITY_MATRIX_TEXTURE0; // 贴图纹理矩阵

uniform float4x4 UNITY_MATRIX_TEXTURE1; //贴图纹理矩阵

uniform float4x4 UNITY_MATRIX_TEXTURE2; //贴图纹理矩阵

uniform float4x4 UNITY_MATRIX_TEXTURE3; //贴图纹理矩阵

uniform float4 UNITY_LIGHTMODEL_AMBIENT; // 环境色

这些变量在Unity中可以直接使用,本章第三节中将会展现如何在Unity中使用这些内置的Uniform变量。

1.2.2、输入输出和语义

 输入输出:在第一节中我们了解到对于程图形渲染管线,可编程控制的部分只有两个,顶点着色器和片段着色器。对于编程控制这两个部分,首要的任务就是要怎么给它们传参数。Cg语言的参数传递同样也有“值传递”和“引用传递”之分。因为GPU不支持指针,所以Cg语言采用了如下的方式来修辞参数传递:

1、in:修辞一个形参只是用于输入,进入函数体时被初始化,且该形参值的改变不会影响实参值,传递方式为值传递。

2、out:修辞一个形参只是用于输出,进入函数体时没有被初始化,一般为函数的返回值。

3、inout:修辞一个形参即用于输入也用于输出,这是典型的引用传递。

语义:表示图元数据的含义(顶点的位置、法向量或者纹理信息),也表明这些图元数据存放的硬件资源。因为顶点着色器的输出即是片段着色器的输入,所以顶点着色器的输出必须和片段着色器的输入语义是一致的。语义是顶点程序和片段程序之间输入\输出数据和寄存器之间的桥梁,因此语义只对这两个处理阶段有意义,并且只在入口函数才有效,在内部函数无效。语义概念的提出和图形流水线工作机制大有关系。从前面所讲的GPU 处理流程中可以看出,一个阶段处理数据,然后传输给下一个阶段,那么每个阶段之间的接口是如何确定的呢?例如:顶点处理器的输入数据是处于模型空间的顶点数据(位置、法向量),输出的是投影坐标和光照颜色;片段处理器要将光照颜色做为输入,问题是“片段处理器怎么知道光照颜色值的存放位置”。在高级语言中(C/C++),数据从接口的一端流向另一端,是因为提供了数据存放的内存位置(通常是指针信息);由于Cg 语言并不支持指针机制,且图形硬件处理过程中,数据通常暂存在寄存器中,故而在Cg 语言中,通过引入语义绑定(binding semantics)机制,指定数据存放的位置,实际上就是将输入\输出数据和寄存器做一个映射关系(在OpenGL Cg profiles 中是这样的,但在DirectX-based Cgprofiles 中则并没有这种映射关系)。根据输入语义,图形处理器从某个寄存器取数据;然后再将处理好的数据,根据输出语义,放到指定的寄存器。

语义词和语义绑定:Unity的顶点着色器(程序)中常用的语言词有如下:

1、POSITION\SV_POSITION :模型坐标的位置,

2、TANGENT:正交于表面法线的向量

3、NORMAL:表面法线向量,需要进行归一化

4、TEXCOORDi:第i组纹理坐标(也即UV坐标,坐标范围在0~1之间),i是0~7中的一个数字

5、COLOR:颜色

6、PSIZE:点的大小

7、BLENDINDICES:通用属性,可以用它和TANGENT来替换TEXCOORDi

注:SV_POSTION和POSTION的唯一区别是用在顶点着色器中作为输出语义时,SV_POSTION表示的顶点位置会被固定,不能被改变。如果作为片段着色器的输入语义就是一样的,都可以被改变。

顶点着色器的输出语义词有:

1、COLOR:颜色

2、FOG:输入雾坐标

3、PSIZE

4、 POSITION

5、TEXCOORD0-TEXCOORD7

片段着色器的输入语义即为顶点着色器的输出语义。

片段着色器的输出语义如下:

1、COLOR:颜色

2、DEPTH:片段的深度

语言绑定的三种方法:

1、绑定语义放在函数的参数列表的参数声明后面中:

[const][in|out|inout|uniform][ :][=]

voidvert(float4 obj_position:POSITION,

  float4 obj_normal:NORMAL,

outfloat4 outPos:POSITION,

  uniform float4 uColor:COLOR

{

...

}

其中,const作为可选项,const修饰符同C和C++语言里的一样,表示这个变量的值是不能改变的;in、out、inout作为可选项,说明数据的调用方式;

uniform也是可选项,表示变量的值的初始化是来自外部应用程序;type是必选项,声明数据的类型;identifier是必选项,形参变量名:一个冒号“:”加上一个绑定语义,是可选项;最后是初始化参数,是可选项。

参数1、2、5绑定到输入语义;参数3、4绑定到输出语义;尽管参数1和3的绑定语义词一样,但前者是输入语义,后者是输出语义,所以这两个参数数据所对应存储的硬件位置是不一样的。

2、绑定语义可以放在结构体的成员变量后面:

Struct

{

[:binding-semantic>];

};。

如在结构体vertexOutput中两个成员变量分别绑定语义SV_POSITOIN和TEXCOORD0,这个结构体在顶点程序vert中作为输出,为顶点程序的输出语义,同时顶点程序的输入即是片段程序的输入,该结构体也为片段程序的输出语义。

structvertexOutput {

            float4 pos : SV_POSITION;

            float4 col : TEXCOORD0;

        };

vertexOutputvert(appdata_full input)

        {

            vertexOutput output;

            output.pos =  mul(UNITY_MATRIX_MVP, input.vertex);

            output.col = input.texcoord;

returnoutput;

        }

float4frag(vertexOutput input) : COLOR

        {

returninput.col;

        }

3、绑定语义词可以放在函数声明的后面,其形式为: 

() [:

{


}

如下面的代码中,片段程序的后面带有“COLOR”语义,表示该程序最后要返回一个颜色的值给GPU,所以在最后,返回的变量值类型是float4类型的。那这里为什么不直接使用float4呢,语义绑定,顾名思义绑定的变量是要有含义的,直接使用发咯float4就不能理解它到达表示什么含义,因为float4类型的变量可以是颜色、位置等。

float4frag(vertexOutput input) : COLOR

        {

float4 oColor =float4(1,0,0,1);

returnoColor;

        }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容