游戏开发基础(十七)

第十七章

顶点着色器(vertex shader)是一段运行在图形卡GPU中的程序,可取代固定功能流水线中的变换和光照环节(当然,不是绝对的,在硬件部支持顶点着色器的情况下,Direct3D运行时就会用软件运算方式来模拟顶点着色器).

顶点着色器其实就是用HLSL语言编写的一段定制程序,这样在可实现的图形效果上就获得了很大的灵活性,例,借助顶点着色器,可使用任何可在顶点着色器中实现的光照算法

使用顶点数据结构也更加灵活,而且可编程流水线中的顶点结构可以包含比固定功能流水线更加丰富的数据

顶点着色器是一项比较新的特性,目前许多图形卡尚不支持该特性,尤其伴随DirectX 9.0发布的那些较新的顶点着色器版本,可通过检查D3DCAPS9结构的成员VertexShaderVersion并与宏D3DVS_VERSION进行比较,来检测图形卡是否支持某个顶点着色器版本

检测过程:

 //if the device's supported version is less than version 2.0
 if (caps.VertexShaderVersion < D3DVS_VERSION(2,0))//主次版本号
  // then vertex shader version 2.0 is not supported on this device
目前D3DXCompileShaderFromFile函数支持的顶点着色器版本为1.1,2.0和3.0

顶点声明:
在可编程流水线中,顶点结构甚至可以包含那些超出FVF描述能力的数据,因此,通常使用能力更强,功能更丰富的顶点声明(vertex declaration)

在可编程流水线中,如果顶点结构可用FVF来描述,仍可使用,但是,这是为了表示方便,实际上可编程流水线内部,FVF最终被转换为顶点声明。

顶点声明描述为一个D3DVERTEXELEMENT9类型的结构数组,该结构数组中的每个元素都描述了顶点结构的一个分量,所以,如果顶点结构具有3个分量(比如位置,法向量,颜色),则相应的顶点声明级可用一个维数为3的D3DVERTEXELEMENT9类型的结构数组来描述

typedef struct D3DVERTEXELEMENT9
{
 WORD Stream;//指定与顶点分量关联的数据流
 WORD Offset;//自顶点数据起始点到特定数据类型相关的数据的字节偏移量
 BYTE Type;//指定数据类型,该参数可取枚举类型D3DDECLTYPE的任何一个成员,D3DDECLTYPE_FLOAT1浮点类型标    //量,D3DDECLTYPE_FLOAT2浮点类型的2D向量,D3DDECLTYPE_FLOAT3浮点类型的3D向量,D3DDECLTYPE_FLOAT4浮点   //类型的4D向量,D3DDECLTYPE_D3DCOLOR一个被扩展为RGBA浮点类型颜色向量(r,g,b,a)的D3DCOLOR类型,其颜色  //向量的每个分量都被规范化至区间[0,1]内
 BYTE Method;//指定了网格化(tesselation)方法,该章默认使用D3DDECLMETHOD_DEFAULT来指定
 BYTE Usage;//指定了顶点分量的用途,例,即,某一个分量是作为位置向量,法向量还是纹理向量等,标识符取自枚举类    //型D3DDECLUSAHE;
 BYTE UsageIndex;//标识具有同用法的多个顶点分量,用法索引(usage index)是一个位于区间[0,15]内的整数,例,有3   //个顶点分量的用法都为D3DDECLUSAGE_NORMAL,则可按序将这3个顶点分量的用法索引分别指定为      //0,1,2,按照这种方式,可通过用法索引表示每个特定的法向量
}D3DVERTEXELEMENT9,*LPD3DVERTEXELEMENT9;

typedef enum D3DDECLUSAGE
{
 D3DDECLUSAGE_POSITION     = 0,//如果一个顶点声明中具有该标识,则表明该顶点已经经过了变换,并指示图形卡不要     //将该顶点输送到顶点处理环节中(变换和光照处理)
 D3DDECLUSAGE_BLENDWEIGHT  = 1,
 D3DDECLUSAGE_BLENDINDICES = 2,
 D3DDECLUSAGE_NORMAL       = 3,
 D3DDECLUSAGE_PSIZE        = 4,//用于指定顶点的点尺寸,该类型主要用于点精灵(point sprite),这样对每个尺寸进行     //控制
 D3DDECLUSAGE_TEXCOORD     = 5,

 D3DDECLUSAGE_TANGENT      = 6,
 D3DDECLUSAGE_BINORMAL     = 7,
 D3DDECLUSAGE_TESSFACTOR   = 8,
 D3DDECLUSAGE_POSITIONT    = 9,
 D3DDECLUSAGE_COLOR        = 10,
 D3DDECLUSAGE_FOG          = 11,
 D3DDECLUSAGE_DEPTH        = 12,
 D3DDECLUSAGE_SAMPLE       = 13
}D3DDECLUSAGE,*LPD3DECLUSAGE;

按照这种方式,就可通过用法索引表示每个特定的法向量

例:要描述的顶点格式包含了一个位置向量和3个法向量,则相应的顶点声明可指定为
 D3DVERTEXELEMENT9 decl{} =
 {
 {0,0,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_POSITION,0},
 {0,12,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_NORMAL,0},
 {0,24,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_NORMAL,1},
 {0,36,D3DDECLTYPE_FLOAT3,D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_NORMAL,2},
 D3DDECL_END()//初始化D3DVERTEXELEMENT9数组中的最后一个顶点元素
 };


顶点声明的创建: 将顶点声明描述为一个D3DVERTEXELEMENT9类型的数组,就可用如下方法获得指向接口IDirect3DVertexDeclaration9指针:
HRESULT CreateVertexDeclaration(
    CONST D3DVERTEXELEMENT9* pVertexElements,//指向一个D3DVERTEXELEMENT9类型的结构数组          //描述了要创建的顶点声明
    IDirect3DVertexDeclaration9** ppDecl//返回指向所创建的IDirect3DVertexDeclaration9接        //口指针
    );

例 :
 IDirect3DVertexDeclaration9* _decl = 0 ;
 hr = _device->CreateVertexDeclaration(decl,&_decl);

灵活顶点格式是一项很有用的特性,在可编程流水线内部它将被转换为顶点声明,所以,直接使用顶点声明时,无需调用:
 Device->SetFVF(fvf);
而只是调用:
 Device->SetVertexDeclaration(_decl);//_decl是一个指向接口IDirect3DVertexDeclaration的指针

需要一种方式来定义从顶点声明中的元素到顶点着色器的输入结构的数据成员的映射,在输入结构中通过为每个数据成员指定一种语义(:usage -type[usage-index])来定义这种映射,该语义通过用法类型和用法索引来标识顶点声明中的每个元素,由数据成员的语义所标识的那个顶点元素就被映射到该数据成员的那个元素
例:与前面提到的那个顶点声明对用的输入结构为:
struct VS_INPUT
{
 vector position:POSITION;
 vector normal  :NORMAL0;
 vector facenormal1  :NORMAL1;
 vector facenormal2  :NORMAL2;
};

如果略去了用法索引,就意味着该索引为0,例,POSITION含义与POSITION0完全相同

顶点着色器支持的输入用法包括:
#POSITION[n]位置
#BLENDWEIGHTS[n]位置融合权值(blend weights)
#BLENDINDICES[n]融合索引(blend indices)
#NORMAL[n]法向量
#PSIZE[n]顶点的点尺寸
#DIFFUSE[n]漫反射颜色
#SPECULAR[n]高光颜色(specular color)
#TEXCOORD[n]纹理座标
#TANGENT[n]切向量(tangent vector)
#BINORMAL[n]副法向量(binormal vector)
#TESSFACTOR[n]网格化因子(tessellation factor)
n为一个可选整数,但必须取自区间[0,15]内

对于输出结构,必须指定每个成员的用途,例如,该数据成员应看作位置向量,颜色向量,还是纹理座标等,对于各数据成员的用途,图形卡无从知晓,需要显示指定,这种指定也是在语义层次实现,例:
 struct VS_OUTPUT
 {
  vector position :POSITION;
  vector diffuse :COLOR0;
  vector specular :COLOR1;
 };

顶点着色器支持的输出用法包括:
#POSITION[n]位置
#PSIZE[n]顶点的点尺寸
#FOG[n]雾融合值(fog blend value)
#COLOR[n]顶点颜色,注意可输出多个顶点颜色,这些颜色混合在一起生成最终颜色
#TEXCOORD[n]顶点纹理座标,注意,可能输出多个顶点纹理座标
n为一个可选整数,但必须取自区间[0,15]内


使用顶点着色器的步骤:
1 编写顶点着色器程序,并进行编译
2 创建一个IDirect3DVertexShader9接口的对象,以表示基于所编译的着色器代码的顶点着色器
3 用IDirect3DDevice9::SetVertexShader方法启用顶点着色器

当顶点着色器使用完毕后,必须进行销毁


该方法获取IDirect3DVertexShader9接口指针,该接口代表一个顶点着色器
HRESULT IDirect3DDevice9::CreateVertexShader(
         const DWORD *pFunction,//指向经过编译的代码指针,
         IDirect3DVertexShader9** ppShader//指向IDirect3DVertexShader接口的指针
         );

例;变量shader是一个指向ID3DXBuffer接口指针,则获取指向IDirect3DVertexShader9接口指针:
 IDirect3DVertexShader9* ToonShader = 0 ;
 hr = Device->CreateVertexShader(
     (DWORD*)Shader->GetBufferPointer(),
     &ToonShader);

D3DXCompileShaderFromFile函数能够返回经过编译的着色器代码(对应上面的shader)

该方法启用顶点着色器
HRESULT IDirect3DDevice9::SetVertexShader(IDirect3DVertexShader9 * pShader);
该方法接收一个单个参数,可将一个指向希望被启用的顶点着色器的指针赋给该参数
例:
 Device->SetVertexShader(ToonShader);

IDirect3DVertexShader9在使用完毕后,必须调用其自身的Release来释放资源
例:
 d3d::Release<IDirect3DVertexShader9*>(ToonShader);

发布了79 篇原创文章 · 获赞 17 · 访问量 23万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章