Clayman的专栏

It's all about XNA & GPU Programming

用户操作
[即时聊天] [发私信] [加为好友]
claymanID:soilwork
193003次访问,排名382好友0人,关注者13
soilwork的文章
原创 85 篇
翻译 15 篇
转载 0 篇
评论 330 篇
clayman的公告
嘿嘿 ^o^....
最近评论
ffffk:研究到这的都是高手
jym5596337:我也不知道我怎么就走到了你的路上来了呵呵...
太晕了,我们专业就学的C#... 那我就凑合着用它学习MDX喽,但到了2008你的这个时期,感觉形式有点尴尬,以前的人说 在中国搞软件是 前有微软,后有盗版。
现在是 前有XNA后有C++ ... MDX 学习资料太太太难找了。。太太太少了。 师兄给介绍下你学历路途中的资料目录咯。。。我好找来学习咯。。 感谢哦感谢。。
jym5596337:好象没有继续哇 ...
shapin:ATI的网站有个支持HLSL语法高亮的vs插件,可以支持其他版本,只要修改相应的那个注册表就行
flip:To linxv :
貼圖座標有用投影嗎?
文章分类
收藏
    相册
    blogs
    David Weller
    nVidia Developer blog
    Rico Mariani
    Shawn Hargreaves
    XNA Team blog
    XNA资源
    XNA Creators Club
    ZBuffer
    Ziggyware XNA Resources
    中国XNA开发网
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 《The Complete Effect and HLSL Guide》翻译连载(八) 收藏

    新一篇: 努力看书中~~ | 旧一篇:  《The Complete Effect and HLSL Guide》翻译连载(七)

    The Complete Effect and HLSL Guide(八) 

    本文版权归原作者所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。
    由于本人水平有限,难免出错,不清楚的地方请大家以原著为准。欢迎大家和我多多交流。
    翻译:clayman
    Blog:
    http://blog.csdn.net/soilwork
    clayman_joe@yahoo.com.cn

    定义变量

     

           HLSL允许把变量定义为常量,输入,输出和临时变量。变量的标准定义语法如下:

     

           [static  uniform  vloatile  extern  shared ] [ const ] type id  [ array_suffix ]

           [ :semantics ]  [ = initializers ]  [ annotations ]   [ , id …];

     

           从语法定义规范可以看出,对变量可以使用多个变量关键字前缀,来告诉编译器如何对待变量。表2-5列出了不同前缀所表示的含义。

     

    2 – 5 变量前缀

    前缀            描述

    static                       static用于全局变量,表示值为一个内部变量,仅能被当前shader中的代码访问。用于局部变量则表示这个值将在多次调用间驻留。静态变量只能进行一次初始化操作,如果没有使用特定值进行初始化,则默认为0

    uniform                   使用uniform声明的全局变量表示对整个shader来说,它是一个统一的输入值,即不能在shader运行期间改变。所有非静态全局变量都被认为是统一的。

    extern                     使用extern声明的全局变量表示对shader来说,它是一个外部输入的值。所有非静态全局变量都被认为是外部的。

    volatile                    这个关键字提示编译器变量将频繁改变。

    shared                     这个关键字用来修饰非全局变量,告诉编译器这个值将被多个effect共享。

    const                      声明为const的变量表示在初始化之后,就不能改变它的值。

     

           声明变量的语法中,需要注意的是semantics部分。语义(semantixs)对HLSL语言来说并没有什么特别含义,它是用来定义如何把shader中的变量及变量的含义映射到effect framewrok中的。

     

           语义通常用于顶点和像素程序的输入和输出变量,把他们映射为特定含义,比如顶点位置或纹理坐标。举例来说,COLOR0语义用来告诉编译器,指定变量表示第一种漫反射颜色,并且在大多数shader版本中,将把它放到d0寄存器中。

     

           如语法定义规范所示,允许全局变量包含一个注解(annotation)。注解以 { member_list }的形式出现。Member_list是一个程序声明的集合,其中每个成员都被初始化为指定字面值。注解只能用来为effect传递元数据,不能在程序中对它进行引用。

     

           我们将在第六章详细讨论语义和注解。

     

    语句和表达式

     

           其它高级语言一样,HLSL也包含语句和表达式。虽然这些元素通常作为函数的一部分来使用,而我们要在下一章才讲解函数。但由于他们是构建shader的主要元素,因此,现在就来看看这些元素。

     

    语句

     

           语句用来控制程序流的执行顺序。HLSL定义了多种类型的语句供开发者使用。下面按功能的不同,对这些语句分为了四类:

     

    l         表达式

    l         语句块

    l         返回语句

    l         流程控制语句

     

           接下来将详细讨论上面的每种元素,第一项是表达式,但我想把它们放到这节的后面一点,先来看看第二项,语句块。

     

           简单来说,语句块就是包含在一对大括号中的语句集合。它把语句组织为一个群组,同时定义了一个子范围,块中所定义的变量只存在于当前语句块范围中。

     

           { [ statements ] }

     

           接下来看返回语句。返回语句用于把函数执行的结果返回给调用者。它的语法如下:

     

           return [ expresstion] ;

     

           上面可以看出,使用return关键字和一个紧随的表达式来定义返回语句。记住,为了让程序通过编译,表达式类型必须和函数所定义的返回值类型相匹配。

     

           最后一项流程控制语句,它们用来控制程序的执行顺序:

     

    if  ( expression )  statement  [else statement ]

     

    do statement while ( expression )

     

    while (expression) do statement

     

    for ( [ expression | variable_decleration ] ; [ expression ] ; [exxpression ] )

    statement

     

           可以看到,HLSL中的流程控制语句与CC++中的基本相同。但与CC++不同的是,在shader中使用流程控制语句,必须进行一些性能上的考虑。

     

    流程控制性能考虑

     

           目前,大多数顶点和像素着色器硬件都以线性方式执行shader,每条指令执行一次。HLSL支持的流程控制形式包括静态分支,断言指令,静态循环,动态分支和动态循环。由于某些着色器实现的限制,部分流程控制指令可能会带来重大的性能损失。

     

           举例来说,顶点着色器1.1版的构架并不支持动态分支,因此使用if语句,产生的汇编代码将同时实现if语句中所有代码。Shader将顺序执行完这些代码,但只使用if语句中某一块代码的输出作为结果。这里是一段将使用vs_1_1编译的程序:

     

    if ( Value > 0 )

         Position = Value1;

    else

         Position = Value2;

     

           下面是编译之后的汇编代码:

     

    // r0.w中计算线性插值量

    mov     r1.w, c2.x

    slt         r0.w, c3.x, r1.w

     

    //根据比较结果对Value1Value2进行插值

    move    r7, -c1

    add       r2, r7, c0

    mad      oPas, r0.w, r2, c1

     

           从上面的代码可以看到,在顶点着色器模型1.1中使用if语句,将导致if语句中的所有表达式都被执行,之后通过插值来计算最终输出。在真正支持动态分支的情况下,这个语句只会产生一条指令,但这里确需要五条指令。

     

           if语句外,一些硬件也允许使用动态或静态循环,但多数情况下他们都是线性执行的。

     

    除像素着色器1.1以外,所有着色模型都支持流程控制语句,但只有支持顶点和像素着色器3.0的硬件才是真正使用18条流程控制语句来支持流程控制的。这意味着所有非3.0shader都将把流程控制转换为一系列代码,执行分支的所有部分,或者把循环展开来使用。对图形硬件来说,硬件流程控制还处于起步阶段,所以性能欠佳。编写代码时应该注意如何才能让程序合理的执行。在第七章中,我将深入讨论关于动态分支的性能。

     

           流程控制可以分为静态或动态的。对静态流程控制来说,语句块中的表达式实际上是常量,并且在shader执行前就确定了。举例来说,静态分支允许根据shader中的一个布尔常量来决定是否执行一块代码。这是一个很方便的功能,我们可以根据当前所渲染的对象类型来控制代码执行的路径。在调用渲染函数之前,你可以选择让当前shader支持哪些特性,之后,为相应代码块设置布尔标志。

     

           相反,大部分开发者最熟悉的还是动态分支。对于动态分支来说,条件表达式的值是一个变量,只有在运行时才能确定。考虑动态分支的性能时,应该包括分支语句本身的代价以及分支中指令的代价。目前只有在硬件支持动态流程控制的顶点着色器中动态分支才是可用的。

     

    表达式

     

           在讨论了语句之后,我们来看看表达式。表达式定义为字面值,变量或通过运算符对两者的组合。表2-6列出了所有可用的运算符以及以及它们的含义。

     

    2 – 6 运算符

    运算符          用法                定义                                结合方向

    ()                         (value)                          子表达式                                                        左到右

    ()                         id(arg)                           函数调用                                                        左到右

    ()                         type(arg)                       类型构器                                                        左到右

    []                         array[int]                       数组下标                                                        左到右

    .                          structure.id                    选择成员                                                        左到右

    .                          value.swizzle                  分量重组                                                        左到右

    ++                       variable++                     递增后缀(作用于所有分量)                  左到右

    --                         variable--                       递减后缀(作用于所有分量)                  左到右

    ++                       ++variable                     递增前缀(作用于所有分量)                  右到左

    --                         --variable                       递减前缀(作用于所有分量)                  右到左

    !                          !value                            逻辑非(作用于所有分量)                        右到左

    -                          -value                            一元减法(作用于所有分量)                    右到左

    +                         +value                           一元加法(作用于所有分量)                    右到左

    ()                         (type)value                    类型转换                                                          右到左

    *                         value * value                  乘法(作用于所有分量)                           左到右

    /                          value / value                   除法(作用于所有分量)                           左到右

    %                        value % value                 模运算(作用于所有分量)                      左到右

    +                         value + value                  加法(作用于所有分量)                           左到右

    -                          value – value                  减法(作用于所有分量)                           左到右

    <                         value < value                  小于(作用于所有分量)                           左到右

    >                         value > value                  大于(作用于所有分量)                           左到右

    <=                       value <= value                小于等于(作用于所有分量)                  左到右

    >=                       value >= value                大于等于(作用于所有分量)                  左到右

    ==                       value == value                等于(作用于所有分量)                          左到右

    !=                        value != value                不等于(作用于所有分量)                       左到右

    &&                      value && value              逻辑与(作用于所有分量)                     左到右

    ||                          value || value                  逻辑或(作用于所有分量)                        左到右

    ?:                         float ? value : value         或条件                                                            右到左

    =                         value = value                  赋值(作用于所有分量)                           右到左

    *=                       variable *= variable         乘法赋值(作用于所有分量)                 右到左