现在的位置: 首页 > 综合 > 正文

高级D3D应用

2012年08月23日 ⁄ 综合 ⁄ 共 5717字 ⁄ 字号 评论关闭

高级D3D应用

09_01_高级阴影发生器语言入门(Introduction to the High-Level Shading Language

Overview

在这一节中我们描述High-Level Shading Language (HLSL),那个我们用于在接下来的三节中用于编程顶点和像素阴影发生器的东东。暂时的,顶点和像素shader是我们写出的小的特定的程序,在图形卡的GPU(图形存取单元graphics processing unit)执行,这就代替了一部分固定功能管道。通过用我们自己的shader程序代替一部分固定功能管道,我们获得了在图形效果上能达到的巨大灵活性。我们不再受限于预先确定的“固定”操作。

为了写出shader程序,我们需要一种把它们写入的语言。在DirectX 8.x中,shaders被用一种低级shader汇编语言(low-level shader assembly language)写入。幸运的,我们不用再用汇编语言写shaders了,在DirectX 9中支持一种High-Level Shading Language我们用于写shaders。用HLSL代替汇编语言写shader就象用高级语言,如C++代替汇编语言写应用程序一样有利,即:

·         增加生产力用高级语言写程序比用低级语言更快更容易。我们可以分配更多时间聚焦于运算法则而不是编码。

·         改良可读性用高级语言编程易于阅读,这意味着用高级语言写的程序易于调试与维护。

·         编译器,常常而不是从不,比手写汇编码产生更有效率的汇编码。

·         HLSL编译器,我们能编译我们的代码到任何可用shade版本。使用汇编语言,我们就要不得不转换到不同的目标版本。

HLSL也有非常近似于CC++的语法,因而具有非常短的学习曲线。

最后,如果你的物理卡不支持顶点和像素shader,你可能要切换到REF设备以执行shader例程。使用REF设备意味着shader例程运行非常慢,但它们仍会显示正确的结果,以允许我们校验我们的代码是正确的。


 

提示 

顶点shader能被软件顶点处理在软件中模仿D3DCREATE_SOFTWARE_VERTEX-PROCESSING.

Objectives

·         学习如何写和编译一个HLSL shader程序

·         学习如何从应用程序传递数据到shader程序

·         熟悉HLSL的功能的语法、定义及构建

一、 写一个HLSL Shader(Writing an HLSL Shader)

我们能够在我们的应用程序的源文件中用一个长的字符串直接写HLSL shader代码。然而,更便利和模块化的方法是从应用程序代码中分离shader代码。基于这个原因,我们用记事本写我们的shaders并保存它们为ASCII文本文件。然后我们用D3DXCompileShaderFromFile函数编译我们的shaders

作为入门,下面的代码是一个简单的用HLSL写出的被保存为文本文件的用记事本产生的名字叫Transform.txt vertex shader。完整工程可以在例程中找到。这个vertex shader用一个视图和放射结合的距阵转换顶点,并设置顶点的漫反射颜色成分为兰色。


 

Note 

这个例子用一个vertex shader做为例子,但不用担心这样做vertex shader不被支持,它们在下一节解释。现在,目的是让你自己熟悉HLDL程序的语法和格式。

/////////////////////////////////////////////////////////////////////
//
// File: transform.txt
//
// Author: Frank D. Luna (C) All Rights Reserved
//
// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP,
//         MSVC++ 7.0
//
// Desc: Vertex shader that transforms a vertex by the view and
//       projection transformation, and sets the vertex color to blue.
//
/////////////////////////////////////////////////////////////////////
 
//
// Globals
//
 
// Global variable to store a combined view and projection
// transformation matrix.  We initialize this variable
// from the application.
matrix ViewProjMatrix;
 
// Initialize a global blue color vector.
vector Blue = {0.0f, 0.0f, 1.0f, 1.0f};
 
//
// Structures
//
// Input structure describes the vertex that is input
// into the shader.  Here the input vertex contains
// a position component only.
struct VS_INPUT
{
     vector position  : POSITION;
};
// Output structure describes the vertex that is
// output from the shader. Here the output
// vertex contains a position and color component.
struct VS_OUTPUT
{
     vector position : POSITION;
     vector diffuse  : COLOR;
};
 
//
// Main Entry Point, observe the main function
// receives a copy of the input vertex through
// its parameter and returns a copy of the output
// vertex it computes.
//
 
VS_OUTPUT Main(VS_INPUT input)
{
     // zero out members of output
     VS_OUTPUT output = (VS_OUTPUT)0;
 
     // transform to view space and project
     output.position  = mul(input.position, ViewProjMatrix);
 
     // set vertex diffuse color to blue
     output.diffuse = Blue;
 
     //Output the projected and colored vertex.
     return output;
}

1.1全局( Globals)

首先我们例示两个全局变量:

matrix ViewProjMatrix;
vector Blue = {0.0f, 0.0f, 1.0f, 1.0f};

第一个变量,ViewProjMatrix,,是一个距阵类型,是一个在HLSL中建立的4 X 4距阵类型。这个变量存贮一个由视图和放射组合的距阵,因而它描述两种转换。通过这种方式我们只要做一次向量距阵乘法而不是两次。注意在shader源代码中我们哪儿都没初始化这一变量。那是因为我们在应用程序代码中设置它而不是在shader中。从应用程序到shader程序的通讯是个频繁的操作,我们在2.1节中解释。

第二个变量,Blue,是用vector类型建立的,它是一个4D向量。我们简单的初始化它的组成成分为兰色,按RGBA颜色向量处理它。

1.2 输入输出Structures (Input and Output Structures)

全局变量声明后,我们定义两个特殊结构体,我们叫它们为input and output structures。对于vertex shaders,这些结构体分别定义我们shader输入输出的顶点数据。

struct VS_INPUT
{
     vector position : POSITION;
};
 
struct VS_OUTPUT
{
     vector position : POSITION;
     vector diffuse  : COLOR;
};
 


 

Note 

The input and output structures for pixel shaders define pixel data.

本例中,我们输入到我们的vertex shader的顶点只包含一个位置成员。我们输出的顶点包含一个位置成员和一个颜色成员。

独特的冒号表示一种语义(semantic),它用于指示变量的用法。这与顶点结构的灵活顶点格式(FVF)相似。举例来说,在VS_INPUT中,我们有成员:

vector position : POSITION;

符号" : POSITION"是说vector position是用于描述输入顶点的位置的。做为另一个例子,在VS_OUTPUT中我们有:

vector diffuse  : COLOR;

这里 ": COLOR" 是说vector diffuse 是用于描述输出顶点的颜色的。对于更多的可用的标识符我们将在下两节谈到。


 

Note 

从低级观点来看,这种语义的语法关联到一个shader中的与硬件寄存器有关的变量。也就是说,input变量关联到输入寄存器,output变量关联到输出寄存器。举例来说,VS_INPUT的位置成员连接顶点输入位置寄存器。同样的,diffuse连接到一个特殊的顶点输出颜色寄存器。

1.3 入口点函数(Entry Point Function

就象在C++程序中一样,每一个HLSL程序有一个入口点。在我们的示例shader,我们把入口点函数叫做Main,然而,这个名字不是强制性的。shader的入口点函数名字可以为任何有效的函数名,它常常传递输入顶点到我们的shader。入口点函数也会返回一个输出结构的实例,它常常用于输出经我们的shader处理过的顶点。

VS_OUTPUT Main(VS_INPUT input)
{
 


 

Note 

实际上,不是强制使用inputoutput结构。举例来说,你可能有时会看到与下面相似的语法,独特的pixel shaders:

float4 Main(in float2 base : TEXCOORD0,
            in float2 spot : TEXCOORD1,
            in float2 text : TEXCOORD2) : COLOR
{
...
}

参数被输入shader,在这个例子中我们输入三个纹理坐标。shader返回一个单一颜色做为输出,它被在函数后面的: COLOR语法所指定。这种定义方法等同于:

struct INPUT
{
     float2 base : TEXCOORD0;
     float2 spot : TEXCOORD1;
     float2 text : TEXCOORD2;
};
 
struct OUTPUT
{
     float4 c : COLOR;
};
OUTPUT Main(INPUT input)
{
...
}

入口点函数的函数体负责通过输入顶点计算输出顶点。本例中的shader简单的转换输入顶点到视图空间和放射空间,设置顶点颜色为兰色,返回结果顶点。首先我们实例化一个VS_OUTPUT实例并设置它的所有成员为0

VS_OUTPUT output = (VS_OUTPUT)0; // zero out all members

    然后我们的shaderViewProjMatrix变量使用mul函数转换输入顶点位置,mul是一个内置(built-in)函数,既能做vector-matrix乘法又能做matrix-matrix乘法。我们保存转换后的vector结果到输出实例的位置成员:

// transform and project
output.position = mul(input.position, ViewProjMatrix);

接下来,我们设置输出的漫反射颜色为蓝色:

// set vertex diffuse color to blue
output.diffuse = Blue;

最后,我们返回结果顶点:

return output;
}

 

二、编译一个HLSL Shader(Compiling an HLSL Shader)

2.1 系数表(The Constant Table

每一个shader都有一个系数的表用于存贮它的变量。D3DX库提供我们的应用程序通过ID3DXConstantTable界面操作shader的系数表的权力。通过这一界面我们能从我们的应用程序代码设置shader代码中的变量。

我们现在描述一个ID3DXConstantTable工具的简化的函数表,完整表,请看Direct3D文档。

2.1.1 获得系数的句柄(Getting a Handle to a Constant

    为了从我们的应用程序设置一个在一个shader中的一个特定变量。我们能在我们的应用程序中用D3DXHANDLE提取一个shader中的变量。下面的方法当给出一个名字时返回一个到shader中的变量的D3DXHANDLE

D3DXHANDLE ID3DXConstantTable::GetConstantByName(
     D3DXHANDLE hConstant, // scope of constant
     LPCSTR pName          // name of constant
);

·         hConstant一个 D3DXHANDLE识别我们要操作的变量所存活的父结构体。举例来说,如果我们想得到一个特定结构实例中的单一数据成员的句柄,我们将在此传递这个结构实例句柄。如果获得一个顶级变量的句柄,我们可以传递0到这个参数。

·         pName

抱歉!评论已关闭.