DirectX10 几何着色器带流输出






2.47/5 (6投票s)
GS-SO 基础效果教程
引言
本文向初学者和中级图形程序员介绍了 DirectX10(和 DX11)与几何着色器。 在阅读本文时,请参考附带的代码。
这里还演示了流输出,用于从 GPU 读回值。
背景
几何着色器是 DX10 API 的最新补充,它使程序员能够使用图形硬件生成新的几何体并销毁现有的几何体,这允许更花哨的效果,例如爆炸、逼真的增长、衰变(在此处添加新效果 :-))等,而无需重新加载网格。
Using the Code
附带的解决方案是使用 VS2010-Beta2 创建的,并使用来自 DirectX-SDK (Aug/2009) 的库文件。
第一个块解释了 DirectX 设备的创建,这里的目标是实例化设备对象以访问对 GPU 执行操作的方法。
与任何 COM 设备一样,DirectX 设备必须使用类工厂创建。 幸运的是,DX-SDK 允许程序员通过全局 API 来完成此操作,这允许 DX 编程以最少的 COM 暴露,除了必须释放每个 COM 对象以避免内存泄漏的事实。
D3D10CreateDeviceAndSwapChain( NULL, D3D10_DRIVER_TYPE_HARDWARE ,
NULL,0, D3D10_SDK_VERSION, &sd, &pSwapChain, &pd3dDevice );
D3D10CreateDeviceAndSwapChain
创建设备和交换链。 通过交换链,我们获取后备缓冲区(后备缓冲用于无闪烁动画)。 然后我们使用设备创建一个渲染目标,并使用后备缓冲区进行写入(请参考代码)。
下一个块向我们展示了如何创建顶点布局。
我们首先为顶点指定布局,这可以通过使用结构来完成(参考代码)。 顶点布局需要告诉 DX 驱动程序它可以从用户那里期望的顶点格式。 在以下示例中,我们指定前 3 个浮点数是 x-y-z 坐标,接下来的 2 个将是纹理坐标。
D3D10_INPUT_ELEMENT_DESC
D3D10_INPUT_ELEMENT_DESC layout[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = sizeof(layout)/sizeof(layout[0]);
D3D10_PASS_DESC PassDesc;
pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
ID3D10InputLayout *pVertexLayout=0;
pd3dDevice->CreateInputLayout(layout, numElements, PassDesc.pIAInputSignature,
PassDesc.IAInputSignatureSize, &pVertexLayout );
然后我们必须使用以下方法设置顶点缓冲布局:
pd3dDevice->IASetInputLayout( pVertexLayout );
此顶点布局将设置为活动布局,您可以在渲染期间多次设置活动布局,具体取决于不同对象所需的顶点布局(大多数基于 DX10 的引擎只期望一种类型的布局)
struct SimpleVertex
{
D3DXVECTOR3 Pos; // Position
D3DXVECTOR2 Tex; // Texture Coordinate
};
SimpleVertex vertices[] = { D3DXVECTOR3( 0.5f, 0.5f, 0.0f ),
D3DXVECTOR2(1.0,1.0), D3DXVECTOR3( -0.5f, -0.5f, 0.0f ),
D3DXVECTOR2(0.0,0.0), D3DXVECTOR3( -0.5f, 0.5f, 0.0f ),D3DXVECTOR2(0.0,1.0), };
请注意,只提供了三个顶点。 这很重要,以便提供三角形的坐标。
然后,我们为 GPU 读访问创建一个内存缓冲区,并将其设置为使用简单顶点结构中指定的坐标(参考代码)。 这将帮助我们向 GPU 传输顶点数据,请注意,此数据必须根据前面讨论的活动顶点布局进行对齐
...
InitData.pSysMem = vertices;
...
pd3dDevice->CreateBuffer( &bd, &InitData, &pVertexBuffer );
然后我们加载 FX 文件(着色器文件:- effects.txt),其中包含顶点着色器、几何着色器、像素着色器的程序,创建的对象是一个效果指针,此指针可用于设置与 DX9-D3D 类似的渲染。
请注意,与 DX9 不同,这里的顶点着色器是必需的,因为已删除了定点变换,并且所有变换都必须通过使用顶点着色器并将参数传递给在顶点着色器中设置的变量来完成。
需要像素着色器来控制渲染(以及在附带的示例代码中看到的纹理处理),我们可以通过设置不同效果的变量来更改渲染(我可能会稍后写一篇关于此的文章)。
实际上不需要几何着色器,我们在这里需要它……好吧,这就是我写这篇文章的原因。 请参考代码以查看如何使用效果指针获取 ID3D10EffectTechnique
指针,该指针在渲染循环中使用。
D3DX10CreateEffectFromFile( L"effects.txt", NULL, NULL, "fx_4_0",
D3D10_SHADER_ENABLE_STRICTNESS, 0, pd3dDevice, NULL,NULL, &pEffect, &pErrors, NULL );
注意 effects.txt 文件中的几何着色器。
几何着色器使用以下方法创建:
GeometryShader gStream=ConstructGSWithSO( CompileShader( gs_4_0, GS() ),"SV_POSITION.xyz" );
SetGeometryShader( gStream); //to set the geometry shader
在附带的解决方案中,几何着色器用于使用命令生成额外的三角形:TriStream.Append
。 在效果通道中执行此着色器后,屏幕上的输出将得到一个正方形(两个三角形)。 现在到了从显卡读回值的环节。
这分三个部分完成
- 首先涉及创建一个具有 CPU 访问权限的临时缓冲区,另一个用于将顶点数据转储到其中。
sbdesc.CPUAccessFlags =D3D10_CPU_ACCESS_READ ; //notice this setting //pd3dDevice->CreateBuffer( &sbdesc, NULL, &pStaging );
- 下一步是使用
SOSetTargets(1,&pBuff,&offset)
设置流输出 (SO)。 请注意,在效果文件 (effects.txt) 中,GS 着色器是使用 SO 创建的。 - 最后一步是将数据从转储复制到临时缓冲区,以供读取(或反馈:用于模拟增长效果)。 这是通过调用
pd3dDevice->CopyResource(pStaging,pBuff);
完成的D3DXVECTOR3 *ptr = 0; //since buffer is created with //D3D10_BIND_VERTEX_BUFFER pStaging->Unmap();
关注点
几何着色器和流输出也可以修改以提供 GPGPU,因为我们现在能够轻松地从 GPU 读回值。