Shader编程学习笔记(九)—— Cg语言入门1 - 输入输出、语义、profile和基本数据类型

24 篇文章 1 订阅
18 篇文章 1 订阅


1、引言

  这里我们开始了解CG语言。本篇涉及知识点:

  • 输入输出
  • 语义
  • profile
  • 基本数据类型

  这里我们使用一个示例来了解一个简单的shader的顶点和片段程序的输入输出以及常用语义。

2、示例

2.1、输入输出和语义

  编写一个简单的顶点和片段着色器,代码如下:

Shader "lxt610/fragmentVertexShader"{
    SubShader{
        pass{
            CGPROGRAM
            #pragma vertex vert			//声明一个顶点着色器
            #pragma fragment frag		//声明一个片元着色器

            void vert(in float2 objPos:POSITION, out float4 pos:POSITION){
                pos = float4(objPos,0,1);
            }

            void frag(out float4 col:COLOR){
                col = float4(1,0,0,1);
            }
            ENDCG
        }
    }
}

vertex&fragment

Surface Shader没有pass通道,Vertex & Frament Shader至少有一个pass通道。

  Cg是一个镶嵌的代码段,在ShaderLab语法中需要使用关键词“CGPROGRAM”和“ENDCG”将Cg代码段包含起来才能编译使用,需要注意的是这两个关键词都是大写的。
  顶点程序会对顶点做一系列的处理,如几何变换,在处理后把需要的数据传递给片段程序,片段程序拿到顶点程序当中处理后的数据继续进行最终的计算。因此一个顶点片元着色器必须同时包含顶点着色器和片元着色器。

”void vert(in float2 objPos:POSITION, out float4 pos:POSITION)”中有两个参数,

  • 其中第一个参数中的“in”表示引擎提供的输入,“float2”表示数据的类型为二阶的向量,参数名“objPos”冒号后需要带上语义,语义指的是顶点程序和片段程序能够被识别的变量的实际意义,这里使用“POSITION”。
  • 第二个参数中“out”表示输出,数据类型为“float4”,语义也是“POSITION”。

  如果顶点程序要输出一个“POSITION”语义的变量,这个变量必须要以“float4”四阶向量的形式。另外,在片段程序中需要有语义为“COLOR”的变量作为输入,这里使用“out float4 col:COLOR”作为颜色变量的输出,语义“COLOR”就是指“COLOR0”。接下来创建一个使用该shader的Material,并在场景创建一个Cube使用该Material。效果如下:
在这里插入图片描述
  拖动场景窗口,可以发现物体的大小随着窗口的变化而变化。目前需要了解的就是传递给顶点程序的就是模型的顶点数据,由模型的(x,y)凑成一个四阶向量,“POSITION”语义变量并没有在片段程序中输出,但是物体确实有大小上的变化,实际上“POSITION”语义是比较特殊的,可以不用在片段程序中直接使用“POSITION”输出,它被图形硬件直接做最后的处理和显示。在这里目前需要关心的是颜色的显示,我们可以在顶点程序中为颜色计算做一个输出,代码和效果如下:

Shader "lxt610/fragmentVertexShader"{
    SubShader{
        pass{
            CGPROGRAM
            #pragma vertex vert				//声明一个顶点着色器
            #pragma fragment frag		//声明一个片元着色器

            void vert(in float2 objPos:POSITION, out float4 col:COLOR, out float4 pos:POSITION){
                pos = float4(objPos,0,1);
                col = float4(0,0,1,1);
            }

            void frag(inout float4 col:COLOR){
                // col = float4(0,1,0,1);
            }
            ENDCG
        }
    }
}

vertex&fragment

在这里插入图片描述
  片段程序的颜色设置已经注释掉了,否则会覆盖顶点程序的颜色值。需要注意的是作为输出的“COLOR”变量要放在作为输出的“POSITION”语义之前,如“vert(in float2 objPos:POSITION, out float4 col:COLOR, out float4 pos:POSITION)”,否则颜色输出始终是无法改变的。
  计算机图形硬件想要对3D场景中的物体做一个正确的显示时,它需要经过一系列的坐标系变换,如果输入一个物体的坐标系,这个物体的坐标系是没有参考价值的,它只存在物体自身的空间当中,物体在世界坐标中,与其他物体之间有一个相对位置,被摄像机照射时,物体在不同的位置,摄像机最终获取的结果是不一样的。通过这一些列的变换,会得到一个称为“CVV(Canonical View Volume)”的裁剪立方体,“CVV”实际上就是在进行摄像机透视投影在齐次空间当中的一个裁剪立方体,称为“正规化可视空间”,它的x值和y值总是在-1到1之间。
  对于Unity中默认创建的一个Cube,它的网格数据的顶点信息中存储的x值和y值最大为0.5,最小为-0.5,模型的坐标中心为正中间(0,0)。当模型空间当中的x和y作为一个“POSITION”语义的输入时,可以知道它最大值为(0.5,0.5,0,1),最小为(-0.5,-0.5,0,1),在“CVV”的裁剪立方体当中x值和y值始终是-0.5到0.5,场景窗口最左边位置x为-1,正中间x为0,最右边位置x为1,y值同理。因此拖动窗口时,物体总是会随着窗口的变化而变化。
  注释掉片段程序中的颜色输出,在顶点程序中将位置信息“pos”作为颜色信息,在Cg当中只要数据类型相同,两者之间是可以互相赋值的,尽管语义不同,语义只是在顶点和片段程序中输入输出的一个规范。代码和效果如下:

Shader "lxt610/fragmentVertexShader"{
    SubShader{
        pass{
            CGPROGRAM
            #pragma vertex vert				//声明一个顶点着色器
            #pragma fragment frag			//声明一个片元着色器

            void vert(in float2 objPos:POSITION, out float4 col:COLOR, out float4 pos:POSITION){
                pos = float4(objPos,0,1);
                col = pos;
            }

            void frag(inout float4 col:COLOR){
                // col = float4(0,1,0,1);
            }
            ENDCG
        }
    }
}

vertex&fragment

在这里插入图片描述
  物体的颜色会随着位置的变化而变化,颜色值的范围是(-0.5,-0.5,0,1)到(0.5,0.5,0,1)。而实际上当颜色值小于0时会当做0处理。

2.2、基本数据类型

  Cg作为一种类C的语言,它的基本数据类型也有float,32位浮点数,来使用一下float:

Shader "lxt610/fragmentVertexShader"{
    SubShader{
        pass{
            CGPROGRAM
            #pragma vertex vert				//声明一个顶点着色器
            #pragma fragment frag			//声明一个片元着色器

            void vert(in float2 objPos:POSITION, out float4 col:COLOR, out float4 pos:POSITION){
                pos = float4(objPos,0,1);
                col = pos;
            }

            void frag(inout float4 col:COLOR){
                // col = float4(0,1,0,1);
                float r = 1;
                float g = 0;
                float b = 0;
                float a = 1;

                col = float4(r,g,b,a);
            }
            ENDCG
        }
    }
}

vertex&fragment
  • float ,float4也是Cg语言中的基本数据类型,它是一个四阶向量,可以用四个float值组合成一个float4,可以了解它会形成一个红色。
  • half,在Cg当中除了“float”这个32位浮点数之外,还有一个16位的浮点数“half”,精度为“float”的一半。将当前shader程序中的float改为half,float4改为half4,在工程中可以得到跟原来一样的结果。
  • fixed,Cg还有一种基本类型为“fixed”,它是一种定点数,将程序中的float修改为fixed,float4修改fixed4也能得到相同的结果。

针对float,了解一些Cg的数据类型。float可以组成二阶向量float2,三阶向量float3和四阶向量float4,其他类型同理,如half、fixed等。其中需要注意的是,Cg向量最高的维度为四阶

2.3、profile

  关于Cg的profile,一个Cg profile定义了一个“被特定图形硬件或API所支持的Cg语言子集”,任意一种shader language都是基于可编程图形硬件的(寄存器、指令集等),这也就意味着,不同的图形硬件对应着不同的功能子集。这些可选的语言功能包括某些控制结构和标准库函数。profile还定义了数据类型的精度,并且指定数据类型是否全局部或仅部分支持。profile按照功能可以划分为顶点profile和片段profile,而顶点profile和片段profile又基于OpenGL和DirectX的不同版本或扩展,划分为各种版本。从某种意义上而言,OpenGL和DirectX的发展历程成就了Cg语言。
  关于Cg profile fp20和Cg language的描述英伟达公司给出了相关的描述,这里已经打不开了!
  关于Cg profile的定义,它主要描述的就是有些硬件有特定的性能,不一定得完全地支持Cg的某些内容,在这种情况下profile就做了对硬件做了特性能力的描述。在fp20 profile中,尤其比较重要的就是“fixed”数据类型,相当于本地化的有符号的9位整型,并被标准化范围为-1到+1。如果颜色值的分量都用fixed类型,那么每个颜色值分量都有256种,这个就是目前概念中的真彩色。因此在Unity中,fixed的精度已经足够表示颜色值了。fp20中使用的各种语义和函数就不一一列举了,要使用时可以查看一下文档。
  Cg最新版本已经到了3.1,Cg语言也是遵循Ansi C规范的语言,但它不同于C语言,Cg有bool类型,C语言没有bool类型,C语言非零即是真,零即为假。Cg中数组为第一类类型,因为Cg不支持指针。第三个方面Cg函数参数使用值传递,使用“out”、“inout”、“in”等进行输入输出。
  语言profile实际上就是语言的一种特性,在不同的处理方法中会拥有不同的特性。在特殊情况下,语言profile就是关于一个使用for或者while循环的限制,意思就是有些情况下它不支持for或者while循环,有些profile仅仅loop循环。

  • Cg不支持goto、switch、case、default等保留关键字;
  • 也不支持指针和指针相关的运算能力;
  • Cg支持数组,但是有尺寸和维度的限制;
  • Cg没有枚举和联合;
  • Cg在结构体当中没有位成员;
  • Cg中所有的整型都是有符号,没有signed关键字。
  • Cg有绑定语义,比如POSITON、COLOR0等
  • Cg内建的有swizzle操作
  • 对于一个值来说,swizzle操作可以允许进行拼凑一个向量或矩阵;
  • swizzle操作可以去访问所有的分量
  • 数据有不同的有限的类型,主要的类型有float、half、fixed,片段profile必须支持这三种数据类型,但是可以选择使用half或fixed去实现float,顶点profile要求实现half和float,但是可以选择实现half和float,顶点profile可以忽略支持fixed,Cg允许profile去忽略支持运行时的int,实际上会把int转换成float;
  • Cg中的操作很多都是对于向量的操作,可以对向量的基本元素进行操作,
  • Cg中也有?问号表达式,
  • Cg中没有全局的非静态变量;
  • Cg有新的sampler*集合;
  • 函数拥有默认值最为参数;
  • 函数和它们的操作可以被重载;
  • 变量可以定义在任何地方,但要在使用之前定义就行。
  • 还有其他一些不同于C语言的地方,详细内容可以查看该文档。

3、总结

  通过以上我们了解了:

  • 输入使用“in”关键词,
  • 输出使用“out”关键词,
  • 既是输入也是输出则使用“inout”关键词;
  • 也了解了Cg基本的语义,顶点程序传递给片段程序的位置坐标使用“POSITION”语义,它不需要在片段程序中做特殊处理,图形硬件会自动针对“POSITION”数据进行处理。

4、结束语


The End
  好了,今天的分享就到这里,如有不足之处,还望大家及时指正,随时欢迎探讨交流!!!


喜欢的朋友们,请帮顶、点赞、评论!您的肯定是我写作的不竭动力!

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

对酒当歌﹏✍

您的鼓励是我写作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值