DirectX11SDK文档五 directx sdk文档

总结

在前面的教程中,我们成功地在应用程序窗口的中央绘制了一个三角形,我们没有吧注意力集中在顶点缓冲区里的坐标信息。在这个教程中,我们将详细描述3D坐标和Transformation。

3D空间

在前面的教程中,我们很明智地把三个顶点信息放置在屏幕上。然而,不具有一般性。那么,我们需要一个系统来表示在3D空间中的对象和一个系统将他们显示出来。

在现实世界里,对象存在于3D空间内。那就意味着,要将一个对象放置在一个特定的位置时,我们需要一个坐标系统,定义三个坐标轴来定义一个位置。在计算机图形学中,3D空间使用的是卡迪尔坐标系。在这个坐标系统中,有X,Y,Z三个坐标轴,并互相垂直,可以表示3D空间的任意点。这个坐标系统有两种表现形式,左手坐标系或者右手坐标系。如图:

既然我们讨论的3D空间的坐标系。一个点在3D空间的不同位置,将会有不同的坐标。以1D为例,假设我们有一把尺子,并且我们在上面标记了点P,P点在5英寸处。现在,如果我们把尺子向右平移1英寸,那么对于P点,现在变成了在4英寸处。通过移动尺子,这个参考系就发生了变化。所以,点并没有移动,它只是参考系变了。如图:

在3D中,一个空间由一个原点和X,Y,Z三个坐标轴定义。在计算机图形学中,使用几个空间坐标系:对象空间,世界空间,观察空间,投影空间,屏幕空间。如图:

对象空间

注意到这个立方体是以原点为中心,对象空间也叫模型空间,美工在制作模型的时候就是使用对象空间。美工在制作模型的时候,通常以对象空间的原点为中心,以便于进行变换:比如旋转模型。在我们讨论Transformation的时候将会看到。以下是八个顶点:

(-1, 1, -1)
(1, 1, -1)
(-1, -1,-1)
( 1, -1,-1)
(-1, 1, 1)
(1, 1, 1)
(-1,-1, 1)
( 1,-1, 1)

因为对象空间是美工创建和制作模型的典型应用,所模型所保存的顶点坐标信息都是相对于对象空间。一个应用程序能够创建一个顶点缓冲区来表示一个模型,并用模型数据来初始化这个缓冲区。所以顶点缓冲区的顶点坐标也是相对于对象空间来说。也就意味着顶点渲染器所接收到的顶点都是相对于对象空间。

世界空间

在一个场景中,所有对象将共享一个世界空间。它通常用来表示要渲染的对象之间的空间关系。想象一下这个世界空间,我们可以想象我们站在一个矩形空间的西南角,并面向北面。我们定义我们所站的这个角是坐标原点(0,0,0)。X轴指向我们的右边,Y轴指向我们的上面,Z轴指向我们的前面(即我们所面向的方向)。当我们做好这些,这个空间里的每个点都可以用XYZ坐标轴定义。现在,可能有一张椅子在我们前面5步,右手边2步的位置。可能有一盏灯在椅子上面8步高的位置。那么我们就可以知道椅子的坐标是(2,0,5),灯的坐标为(2,8,5)。正如我们所看到的,在世界中,对象之间的空间关系就用世界空间把他们联系起来。

观察空间

观察空间,有时也叫摄像机空间,跟世界空格键类似,是场景的典型应用。然而,在观察空间中,原点是观察者或者摄像机。摄像机所看到的方向定义为Z轴。应用程序定义了Y轴的正方向为摄像机向上的方向。如图所示:

左图显示了一个场景,该场景由一个像小人的对象和观察者组成,观察者正观察这个对象。红色部分表示使用世界空间的原点和坐标轴。右图显示观察空间和世界空间的关系。蓝色部分表示使用观察空间的坐标系。为了更清楚的说明插图,观察空间的坐标系于世界空间的坐标系有明显的不同。注意到观察空间中,观察者所朝着的方向是Z轴正方向。

投影空间

投影空间是用来将观察空间中的对象进行投影变换。在这个空间里,可见的范围是X,Y在[-1,1],Z在[0,1]。

屏幕空间

屏幕空间经常指帧缓存的位置。因为帧缓存通常是2D的纹理,所以屏幕空间是一个2D空间,左上角表示屏幕坐标原点。X水平向右,Y轴垂直向下。对于一个缓冲来说,它有w像素宽,h像素高。

空间到空间的转换

Transformation是指将顶点从一个空间到另一个空间的转换。在3D计算机图形学中,在pipeline中有3个逻辑转换:世界变换,观察变换,投影变换。每个变换操作如:平移,旋转,缩放将在下一个教程讲解。

世界变换

世界变换,顾名思义,将顶点从对象空间变换到世界空间。它通常包括一个或者多个的缩放,旋转,平移操作来变换对象,当然这些变换要根据我们要给的,大小,方向,位置信息。每个对象在场景中都有它自己的世界变换矩阵。因为每个对象都有自己的大小,方向和位置。

观察变换

在所有顶点都变换到世界空间后,世界变换将这些顶点从世界空间变换到观察空间。以观察者的视角来观察世界空间出现的对象。在观察空间,观察者在坐标系原点,观察方向为Z轴正方向。

以观察者的参考系来观察世界空间没有什么价值。观察变换矩阵是作用于顶点,而不是观察者。所以,当我对观察者进行变换时,观察变换矩阵执行相反的变换。比如,如果我们要观察者沿着Z轴的负方向移动5个单位,观察变换矩阵则被计算成沿着Z轴正方向移动5个单位。虽然摄像机向后移动,但是相对于观察者而言,顶点向前移动。在XNAMath中一个很方便地函数叫XMMatrixLookAtLH()经常被用来计算观察矩阵。我们只要告诉它观察者的位置,观察方向,观察者向上的方向来获取观察变换矩阵。

投影变换

投影变换将顶点从3D空间(比如世界空间和观察空间)变换到投影空间。在投影空间,顶点的X,Y坐标通过3D空间中的X/Z和Y/Z的比来计算。如图:

在3D空间中,所有事物出现在视角以内。也就是说近大远小。众所周知,一棵树的顶端h单位高,d单位远,还有一棵树2h单位高,2d单位远,那么观察者将看到两棵树的顶点重合。所以,顶点出现在屏幕上的位置可以根据X/Z和Y/Z来计算。

在参数中有一个用于顶点3D空间中可见的区域,它叫FOV。当朝着特定的方向看的时候,FOV表示根据对象特定的位置判断它是否可见。人又能在前面所能看到的FOV(我们看不到我我们背面的东西),并且我们看不到太近,或者太远的东西。在计算机图形学中,FOV包含一个平截体,在3D中,这个平截体由6个平面定义。在6个平面中的2个跟XY平面平行,这两个分别叫near-Z和far-Z平面。如图:

GPU过滤掉平截体外面的对象,所以不会花时间去渲染不会显示的图像。这个操作叫做裁剪。平截体的四个面像被割掉头的金字塔。根据体积进行裁剪是非常复杂的,GPU必须将每个顶点跟平截体的六个平面进行计算。换个角度,GPU一般先进行投影变换,然后再根据平截体裁剪。投影变换的效果就是将金字塔形的平截体转换成一个盒子。这是因为,正如前面提到的,在投影空间中X,Y坐标分别是根据X/Z和Y/Z计算出来的。所以点a和点b在投影空间中将是同一个点,正是这个原因平截体变成了一个盒子。

想象一下两棵树的顶点在平截体的顶部边缘,假设d =2h。那么在投影空间中,Y轴的坐标沿着ab这条线将都是0.5(因为h/d=0.5)。所以顶点的Y坐标在投影变换后大于0.5则被GPU裁剪掉。对于不同的平截体将会有不同的裁剪结果。为了使这个操作更方便,3D程序一般缩放投射的X,Y大小是它们能在[-1,1]内。换句话说,任意的X或Y的坐标在[-1,1]区间之外,将被裁剪掉。为了让它按计划工作,投影矩阵必须缩放投射过来的X,Y坐标(通过将它们乘上h/d,或者d/h),d/h也是FOV一半的余切。经过缩放,平截体的头部将变成h/d*d/h = 1。任何顶点经过投影变换后的X,Y坐标大于1的将被GPU裁剪掉。这就是我们想要的。

在投影空间中Z轴坐标也有相同的操作。在投影空间中我们更喜欢将Z坐标控制在[0,1]。在3D空间中,当Z=near-Z时,在投影空间中,Z=0;当Z=far-Z时,投影空间中,Z=1.当这个操作好之后,所有的Z值在[0,1]之外的将被GPU裁剪掉。

在Direct3D11中,获取投影矩阵对简单的方法就是调用XMMatrixPerspectiveFovLH()方法。我们只要提供四个参数--FOVy,Aspect,Zn,Zf,函数返回一个矩阵,能实现上面所提到的功能。FOVy是指在Y轴方向的视野,Aspect指渲染目标的宽高比,根据FOVy和Aspect就可以算出FOVx。Zn和Zf分别表示near-Z和far-Z。

使用变换

在前面的教程中,我们写了一段程序,将一个简单的三角形渲染在屏幕上。当我们创建顶点缓冲区时,顶点的坐标直接当做投影后的坐标来使用,以至于我们没有进行任何的变换。既然我们已经了解了3D空间和变换。我们将改写这个程序,顶点缓冲区保存的将是对象空间的顶点数据。然后,我们改写我们的顶点渲染器将顶点经过一系列的变换,从对象空间变换到投影空间。

改写顶点缓冲区

现在我们开始在三维空间定义对象,我们将前面的平面三角形改成一个立方体。这样更容易地展示这些概念。

SimpleVertex vertices[] = {
{ XMFLOAT3( -1.0f, 1.0f, -1.0f), XMFLOAT4( 0.0f, 0.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, -1.0f), XMFLOAT4( 0.0f, 1.0f, 0.0f, 1.0f ) },
DirectX11SDK文档(五) directx sdk文档
{ XMFLOAT3( 1.0f,1.0f, 1.0f ), XMFLOAT4( 0.0f, 1.0f, 1.0f, 1.0f )},
{ XMFLOAT3( -1.0f, 1.0f, 1.0f), XMFLOAT4( 1.0f, 0.0f, 0.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 0.0f, 1.0f, 1.0f) },
{XMFLOAT3( 1.0f, -1.0f, -1.0f), XMFLOAT4( 1.0f, 1.0f, 0.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, 1.0f), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT4( 0.0f,0.0f, 0.0f, 1.0f ) },
};

可能你会注意到,我们指定了立方体的8个顶点,但是我们并没有描述每个三角形。如果我们就这样把数据传进去,输出将不会是我们想要的结果。我们必须通过这8个点指定三角形来组成立方体。

在一个立方体上,会有许多的三角形共享同一个顶点。并且很多顶点会被重复地定义,这样会浪费内存空间。像这样的情况,我们有一个办法只要定义8个顶点就可以了,然后告诉Direct3D使用那些点来组成三角形。通过索引缓存可以实现。一个索引缓存包含一个链表,它保存的是顶点缓冲区的索引,用它来指定使用那些顶点来组成三角形。代码如下:

// Create index buffer
WORD indices[] = {
3,1,0,
2,1,3,

0,5,4,
1,5,0,

3,4,7,
0,4,3,

1,6,5,
2,6,1,

2,7,6,
3,7,2,

6,4,5,
7,4,6,
};

正如你所看到的,第一个三角形由点3,1,和0。这意味着第一个三角形的顶点分别在:( -1.0f, 1.0f, 1.0f ),(1.0f, 1.0f, -1.0f ), and ( -1.0f, 1.0f, -1.0f),一个立方体有6个面,每个面由3个三角形组成。那么我们将会看到这里定义了12个三角形。

既然每个顶点已经被明确定义了,并且没有任何两个三角形没有共享边缘,这是考虑到使用三角形列。总之,包含12个三角形的三角列,我们需要36个顶点。

顶点索引缓冲区的创建跟顶点缓冲区的创建类似。我们提供指定的参数,比如一个结构体包含大小和类型,然后创建缓冲区。这个类型是D3D11_BIND_INDEX_BUFFER。既然我们使用DWORD来申请数组,那我们用sizeof(DWORD)。

D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( WORD ) *36;// 36 vertices needed for 12 triangles in a triangle list
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
InitData.pSysMem = indices;
if( FAILED( g_pd3dDevice->CreateBuffer(&bd, &InitData,&g_pIndexBuffer ) ) )
return FALSE;

一旦我们创建好缓冲区,我们就要去设置它,以至于Direct3D能知道如何去使用索引缓冲区来获得三角形。我们指定顶点的缓冲区,格式,和偏移量。代码如下:

// Set index buffer
g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );

改写顶点渲染器

在前面教程中的顶点渲染器,我们以顶点坐标为输入,以相同的顶点坐标为输出,没有进行任何的修改。我们能够完成这个是因为输入的顶点坐标已经被定义在投影空间内。现在,因为我们的顶点是被定义在对象空间。在顶点渲染器输出之前,必须对顶点进行变换。我们需要3个步骤:将对象空间转换到世界空间,然后转换到观察空间,最后转换到投影空间。我们第一件事要做的是申请静态的缓冲变量。静态缓冲区用来保存应用程序需要传入渲染器的数据。在渲染之前,应用程序通常将重要的数据写入静态缓冲区,并且在渲染数据期间西欧哪个渲染器中可以获取这些数据。在一个FX文件中,静态缓冲变量就像C++结构体中的全局变量。我们要用的者3个变量分别是世界矩阵,观察矩阵,投影矩阵,在HLSL中,他们的数据类型为matrix。

一旦我们清楚了我们所需要的矩阵,我们利用这些矩阵里运行顶点渲染器来处理输入的坐标数据。一个向量将被矩阵中多个向量变换。在HLSL,通过使用内置函数mul()。代码如下:

cbufferConstantBuffer : register( b0 ){
matrix World;
matrix View;
matrix Projection;
}

//
// Vertex Shader
//
VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR ){
VS_OUTPUT output = (VS_OUTPUT)0;
output.Pos = mul( Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Color = Color;
return output;
}

在这个顶点渲染器中,每个mul()函数应用一个变换作用于输入坐标。按顺序使用世界矩阵,观察矩阵,投影矩阵。这个顺序是固定的,不允许交换。

设置矩阵

通过使用这些矩阵,我们可以更新我们的顶点渲染器,但我们也需要在程序中定义这三个矩阵。在渲染的时候,这3个矩阵保存着我们需要使用的变换。在渲染之前,我们将这3个矩阵的值复制到渲染器的静态缓冲区。然后,通过调用Draw()来启动渲染,我们的顶点渲染器从静态缓冲区读出矩阵数据。除了这些矩阵,我们还需要一个ID3D11Buffer对象来表示静态缓冲区。代码如下:

ID3D11Buffer* g_pConstantBuffer = NULL;
XMMATRIXg_World;
XMMATRIX g_View;
XMMATRIX g_Projection;

为了创建ID3D11Buffer对象,我们使用ID3D11Device::CreateBuffer(),并指定D3D11_BIND_CONSTANT_BUFFER。

D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(ConstantBuffer);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
if( FAILED(g_pd3dDevice->CreateBuffer(&bd, NULL, &g_pConstantBuffer ) ))
return hr;

接下来我们需要做的就是利用这3个矩阵进行变换。我们要让三角形设置在原点,并平行于XY平面。那么相对于对象空间,这些顶点要如何保存呢?所以世界变换不需要做任何事情,我们只需要把世界矩阵设置为单位矩阵即可。我们要设置摄像机的位置在(0,1,-5),看着(0,1,0)点,向上的向量为(0,1,0)。我们调用XMMatrixLookAtLH()函数来方便地计算出观察矩阵。我们习惯Y轴的正方向为向上的方向。最后,计算投影矩阵,我们调用XMMatrixPerspectiveFovLH()函数,以90°的垂直视野(即pi/2),aspect宽高比为640/480,这个数据来自背景缓冲区的宽高。Zn=0.1,Zf=110,。这意味着任何事物力摄像机的距离小于0.1或者大于110将视为不可见。这三个矩阵分别保存在全局变量g_World,g_View, and g_Projection上。

更新静态缓冲区

我们已经有了这些矩阵,现在我们必须把这些数据写入静态缓冲区,以至于GPU进行渲染的时候能读到它。为了更新这个缓冲区,我们使用ID3D11DeviceContext::UpdateSubresource()函数,并传给它一个指向矩阵的指针,同样,传入指向静态缓冲区的指针。为了顺利地完成这个,我们创建一个包含于静态缓冲区同样格式的结构体。这是因为,矩阵在C++和HLSL的保存方式不一样。在更新之前,我们必须传送这些矩阵。

//
// Updatevariables
//
ConstantBuffer cb;
cb.mWorld =XMMatrixTranspose( g_World );
cb.mView =XMMatrixTranspose( g_View );
cb.mProjection = XMMatrixTranspose( g_Projection );
g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, NULL, &cb, 0, 0 );

  

爱华网本文地址 » http://www.413yy.cn/a/25101011/75851.html

更多阅读

双击office文档word,excel打开很慢解决方法大全 office 双击打开慢

今天电脑问题不断,word文档双击打开要等半分钟才有反应,电脑死机状态,遇到word文档双击打开慢的朋友估计也不少,想找一个处理总结,后来就按下面的能操作的都试了下,整理了双击office文档word,excel打开很慢解决方法大全供参考:1,在资源管理器

word文档加密破解 如何破译加密word文档

方法一:插入文件法启动WORD,新建一个空白文档,执行“插入——〉文件”命令,打开“插入文件”对话框,定位到需要解除保护的文档所在的文件夹,选中相应文档,单击“插入”按钮,将加密保护的文档插入到新文档中,文档保护会被自动撤销。方法二:文件

如何批量删除word文档中的向下箭头 word文档向下箭头

我们从网页上复制一篇文章粘贴到Word文档中时,经常会有很多向下的箭头符号(又称软回车符号,它是同时按住shift+enter得来的),占用了很多行距,而且实在不好看。以往我们只能手动一个一个地删除,实在太麻烦了,那么有没有什么方法能快速批量删

声明:《DirectX11SDK文档五 directx sdk文档》为网友一地月光分享!如侵犯到您的合法权益请联系我们删除