利器:HLSL起步教程-完整篇(4)

2019-05-27 21:23

return output; }

下面就针对上述代码讲解一下HLSL着色器程序的编写:

1.3.1全局变量

代码中声明了两个全局变量:

matrix WVPMatrix; vector color;

变量WVPMatrix是一个矩阵类型,它包含了世界、观察、投影的合矩阵,用于对顶点进行坐标变换; 变量color是一个向量类型,它用于设定顶点颜色; 代码中并没有对全局变量进行初始化,这是因为我们对全局变量的初始化过程将在应用程序中进行,全局变量在应用程序中赋值而在着色器程序中使用,这是应用程序和着色器通信的关键所在。具体赋值过程将在后续部分讲述。

1.3.2输入输出

? 输入输出结构

程序中定义了两个输入输出结构VS_INPUT和VS_OUTPUT

struct VS_INPUT { vector position : POSITION; };

struct VS_OUTPUT { vector position : POSITION; vector color : COLOR; };

自定义的结构可以采用任意名称,结构不过是一种组织数据的方式,并不是强制的,你也可以不使用,而将本程序的输入改为:

vector position : POSITION; ? 标志符

用于输入输出的变量采用用一种特殊的声明方式:

Type VariableName : Semantic

这个特殊的冒号语法表示一个语义,冒号后面的标志符用来指定变量的用途,如

vector position : POSITION;

其中,POSITION标志符表明该变量表示顶点位置,另外还有诸如COLOR、NORMAL等很多表示其他意义的标志符。 本节所说的输入输出其实是指着色器代码和编译器、GPU之间的通信,和应用程序是无关的,所以这些变量不需要在应用程序中进行赋值,标志符告诉编译器各个输入输出变量的用途(顶点位置、法线、颜色等),这是着色器代码和编译器、GPU之间通信的关键。

1.3.3入口函数

程序中还定义了一个函数SetColor:

OUTPUT SetColor(INPUT input) { VS_OUTPUT output = (VS_OUTPUT)0; output.position = mul(input.position, WVPMatrix); output.color = color; return output; }

1. 该函数以input和output类型作为输入输出;

2. 使全局变量WVPMatrix和input.position相乘,以完成顶点的世界、观察、投影变换,并把结果赋值到

output.position; output.position = mul(input.position, WVPMatrix);

3. 将全局变量color的值赋给output.color;

output.color = color;

4. 在同一个着色器代码文件中,可以有多个用户自定义函数,因此在应用程序中需要指定一个入口函数,相当于

windows程序的WinMain函数,本程序只包含SetColor一个函数而且它将被做为入口函数使用。

1.3.4总结

至此,一个HLSL着色器编写完毕,渲染过程中,当一个顶点被送到着色器时:

1. 全局变量WVPMatrix、color将在应用程序中被赋值;

2. 入口函数SetColor被调用编译器根据标志符将顶点信息填充到VS_INPUT中的各个字段;

3. SetColor函数中,首先定义一个VS_OUTPUT信息,之后根据WVPMatrix和color变量完成顶点的坐标

变换和颜色设定操作,最后函数返回VS_OUTPUT结构;

4. 编译器将会再次根据标志符把返回的VS_OUTPUT结构中的各字段映射为顶点相应的信息。 5. 顶点被送往下一个流程接受进一步处理。

上述过程中,全局变量在应用程序中赋值而在着色器程序中使用,这是应用程序和着色器通信的关键所在;标志符告诉编译器各个输入输出变量的用途(顶点位置、法线、颜色等),这是着色器代码和编译器、GPU之间通信的关键。个人认为这是着色器中最为精义的地方:)

1.4怎么用HLSL着色器

应用程序中对HLSL着色器的使用分为以下步骤: 1. 加载(称为编译更为妥当)着色器代码; 2. 创建(顶点/像素)着色器;

3. 对着色器中的变量进行赋值,完成应用程序和着色器之间的通信。 4. 把着色器设定到渲染管道中;

本例使用的着色器是一个顶点着色器,因此我们将通过顶点着色器的使用来讲解着色器的使用过程,像素着色器的使用过程与此大同小异,二者之间仅有些微差别。

1.4.1声明全局变量

IDirect3DVertexShader9* BasicShader = 0; //顶点着色器指针

ID3DXConstantTable* BasicConstTable = 0; //常量表指针

D3DXHANDLE WVPMatrixHandle = 0; D3DXHANDLE ColorHandle = 0;

ID3DXMesh* Teapot = 0; //指向程序中D3D茶壶模型的指针

1.4.2编译着色器

通过D3DXCompileShaderFromFile函数从应用程序外部的文本文件BasicHLSL.txt中编译一个着色器:

//编译后的着色器代码将被放在一个buffer中,可以通过ID3DXBuffer接口对其进行访问,之后的着色器将从这里创建

ID3DXBuffer* shaderBuffer = 0; //用于接受错误信息

ID3DXBuffer* errorBuffer = 0; //编译着色器代码

D3DXCompileShaderFromFile(\着色器代码文件名

0, 0,

\入口函数名称 \顶点着色器版本号

D3DXSHADER_DEBUG,// Debug模式编译 &shaderBuffer, //指向编译后的着色器代码的指针 &errorBuffer,

&BasicConstTable); //常量表指针

1.4.3创建着色器

应用程序通过CreateVertexShader创建一个顶点着色器,注意使用了上一步得到的shaderBuffer:

g_pd3dDevice->CreateVertexShader((DWORD*)shaderBuffer->GetBufferPointer(), &BasicShader); 1.4.3对着色器中的变量进行赋值

1.3.4节说到着色器的全局变量在应用程序中赋值而在着色器程序中使用,这是应用程序和着色器通信的关键所在,这里就具体说明赋值过程。

着色器中的全局变量在编译后都被放在一个叫常量表的结构中,我们可以使用ID3DXConstantTable接口对其进行访问,参照1.4.1中编译着色器函数D3DXCompileShaderFromFile的最后一个参数,该参数即返回了指向常量表的指针。

对一个着色器中变量进行赋值的步骤如下:

1. 通过变量名称得到指向着色器变量的句柄;

还记得在BasicHLSL.x着色器文件中我们声明的两个全局变量吗:

matrix WVPMatrix; vector color;

我们在应用程序中相应的声明两个句柄:

D3DXHANDLE WVPMatrixHandle = 0; D3DXHANDLE ColorHandle = 0; 然后通过变量名得到分别得到对应的两个句柄:

WVPMatrixHandle = BasicConstTable->GetConstantByName(0, \ ColorHandle = BasicConstTable->GetConstantByName(0, \2. 通过句柄对着色器变量进行赋值;

我们可以先设置各变量为默认值:

BasicConstTable->SetDefaults(g_pd3dDevice);

之后,可以使用ID3DXConstantTable::SetXXX函数对各个变量进行赋值:

HRESULT SetXXX(

LPDIRECT3DDEVICE9 pDevice, D3DXHANDLE hConstant, XXX value );

其中XXX代表变量类型,例如Matrix类型的变量就要使用SetMatrix函数赋值,而Vector类型的则要使用SetVector来赋值。

1.4.4把着色器设定到渲染管道中

这里我们使用SetVertexShader方法把顶点着色器设定到渲染管道中:

g_pd3dDevice->SetVertexShader(BasicShader);

1.4.5整个渲染过程如下

在渲染过程中,我们设定顶点的变换坐标和颜色值,渲染代码如下:

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,

D3DCOLOR_XRGB(153,153,153), 1.0f, 0 ); //开始渲染

g_pd3dDevice->BeginScene();

//得到世界矩阵、观察矩阵和投影矩阵

D3DXMATRIX matWorld, matView, matProj;

g_pd3dDevice->GetTransform(D3DTS_WORLD, &matWorld); g_pd3dDevice->GetTransform(D3DTS_VIEW, &matView);

g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &matProj); D3DXMATRIX matWVP = matWorld * matView * matProj;

//通过句柄对着色器中的WVPMatrix变量进行赋值

BasicConstTable->SetMatrix(g_pd3dDevice, WVPMatrixHandle, &matWVP);

D3DXVECTOR4 color(1.0f, 1.0f, 0.0f, 1.0f);

//通过句柄对着色器中的color变量进行赋值,这里我们赋值为黄色

BasicConstTable->SetVector(g_pd3dDevice, ColorHandle, &color);

//把顶点着色器设定到渲染管道中

g_pd3dDevice->SetVertexShader(BasicShader);

//绘制模型子集

Teapot->DrawSubset(0);

//渲染完毕

g_pd3dDevice->EndScene();

g_pd3dDevice->Present(NULL, NULL, NULL, NULL);

编译运行程序,运行效果如图1.2所示,这里我们将顶点颜色设置为黄色,如果读者在渲染过程中不断变换对着色器变量color的赋值,你将会得到一个色彩不断变幻的D3D茶壶。

D3DXVECTOR4 color(1.0f, 1.0f, 0.0f, 1.0f); //读者可以尝试改变颜色值

BasicConstTable->SetVector(g_pd3dDevice, ColorHandle, &color);

图1.2 着色器效果

第二章 HLSL着色语言

这一章我们将学习HLSL的大部分基本内容,包括丰富的变量类型,如何定义变量,和如何编写shader代码。你可能还

想知道如何在shader中使用函数。虽然它们是使用HLSL编写shader的必须元素,但我还是决定把所有关于函数的内容作为单独一章来讲解。在第三章中,我们将详细讲解如何定义函数,以及HLSL为开发者所编写的内置函数。

好了,闲谈到此为止,让我们直接进入本章主题,讨论在任何语言中都是最重要的元素,数据类型。

在继续学习之前,需要进行一点点说明,读者在前一章学习HLSL语法时可能注意到了诸如techniques,渲染状态,pas

s之类的概念。虽然它们也是HLSL语言的一部分,但事实上它们只在effect文件中使用,而effect 文件则是HLSL的一个超集。

数据类型

数据类型是任何一门编程语言的核心。没有它们你将无法定义变量或者在函数之间传递数据。如果连呈现数据的方法都没有,又怎么能储存数据呢?和其他高级语言一样,HLSL有一系列内置定义类型,可以把它们分为以下几类:

? 标量类型 ? 矢量类型 ? 矩阵类型 ? 对象类型

除了上面的内置类型外,HLSL同样允许自定义的复合类型,比如数组和结构。在介绍HLSL特定数据类型前,先来仔细看看大部分3D硬件上呈现数据的方式。当处理数据时,基本的选项是浮点值,根据硬件构架的不同,这些值可能为16或32位。记住,虽然可以让硬件同一时间只处理一个值,但这并不是最高效的方法。相反,如果硬件每次处理一个包含四个分量值的单元(或矢量),那么则可以同时对四个分量进行处理。当然,这就需要考虑硬件如何来保存非矢量的值。我稍后会讲解这一点。

除了浮点值以外,较新的硬件也内置支持整型和布尔值,但它们主要用于分支,循环,和条件测试语句。接下来的几页中,我将浏览每一种数据类型,并解释如何来使用它们。

标量类型

标量类型是由HLSL标准定义的,他们是最基本的类型。所有复杂类型,比如矢量,矩阵,和结构都由标量组成。表2-1列出了所有可用的标量类型以及它们所表示的值。

表 2 -1 HLSL标量类型 标量类型 值

bool int half float double

true或false 32位有符号的整型 16位浮点数 32位浮点数 64位浮点数

需要注意并不是所有shader目标都天生支持整型,half和double值。如果要将shader编译为不支持指定类型数据的目标,那么将模拟处理float值的方式来处理它们。与使用原生(native)类型相比,结果可能不正确。在确定目标平台支持某个特定类型之前,为了保证一致性和可移植性,最好坚持使用标准浮点数。

注意

我们在上一章已经简要讨论过profile,它用来告诉HLSL编译器为哪种构架的shader产生代码。通常Profile的值直接对应于可用的顶点和像素着色器版本,但对于指令集没有改变的情况可能会有例外。


利器:HLSL起步教程-完整篇(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:人教版PEP六年级毕业考试英语模拟试题(2)有答案

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: