D3D10 技术Mipmap

来源:互联网 发布:java 线性拟合 斜率 编辑:程序博客网 时间:2024/05/01 08:17

 Mipmap 是我们在使用纹理的时候一种常用的技术. 在上次写 D3D10 Demo 的时候我已经发现 D3D10 在创建纹理的时候不能自动生成 Mipmap , 通过这两天的仔细了解总结一下在 D3D10 中与纹理 Mipmap 有关的东西.

 
     与 Mipmap 有关的参数(结构)有下列几个:
  • D3D10_TEXTURE2D_DESC::MipLevels : Number of subtextures (also called mipmap levels). Use 1 for a multisampled texture; or 0 to generate a full set of subtextures.
  • D3D10_TEXTURE2D_DESC::MiscFlags , D3D10_RESOURCE_MISC_GENERATE_MIPS : Enables an application to call ID3D10Device::GenerateMips on a texture resource. The resource must be created with the bind flags that specify that the resource is a render target and a shader resource.
  • D3D10_SHADER_RESOURCE_VIEW_DESC::D3D10_TEX2D_SRV::MostDetailedMip : Index of the most detailed mipmap level to use; this number is between 0 and MipLevels.
  • D3D10_SHADER_RESOURCE_VIEW_DESC::D3D10_TEX2D_SRV::MipLevels : Number of mipmap levels to use.

     其中 D3D10_TEXTURE2D_DESC 结构被 ID3D10Device::CreateTexture2D 使用, D3D10_SHADER_RESOURCE_VIEW_DESC 被 ID3D10Device::CreateShaderResourceView 使用. 还有一个和 Mipmap 有关的函数是 ID3D10Device::GenerateMips . 现在就说一下他们之间的关系.

     首先, 作为 ShaderResource 这种输入类型的纹理(1)来讲, D3D10 是不会自动生成 Mipmap 的, 这类纹理要不没有 Mipmap 要不就自己计算 Mipmap. 从现在的技术来看一般都是在制作完纹理存储到文件的时候制作工具(例如 nVidia 提供的 Photoshop DDS 导出插件)会帮助制作人员创建 Mipmap 并存储, DDS 格式的纹理文件也支持 Mipmap . 然后在程序初始化的时候读出这些 Mipmap 数据然后交给 D3D . 如何交给 D3D 呢? 有两种方式, 这两种方式和纹理创建时候的 Useage 有关, 也就是 D3D10_TEXTURE2D_DESC::D3D10_USAGE . 

  • D3D10_USAGE_IMMUTABLE : 只有一种方法能够把 Mipmap 提交给 D3D10 , 那就是初始化. 在 CreateTexture2D 的时候通过第二个参数 const D3D10_SUBRESOURCE_DATA *pInitialData 可以把纹理的全部数据提交给 D3D10 , 这个参数是一个指向 D3D10_SUBRESOURCE_DATA 结构的指针, 如果我们的纹理有五个级别的 Mipmap 那么我们就创建一个长度为 5 的 D3D10_SUBRESOURCE_DATA 数组传进去
  • D3D10_USAGE_DEFAULT : 除了上面的方法之外可以通过 ID3D10Device::UpdateSubresource 来初始化纹理和 Mipmap 数据, 其中 UINT DstSubresource 可以指定你要 Update 哪一个 level 的 Mipmap.
  • D3D10_USAGE_DYNAMIC : 除了用上面的方法之外还可以用另外一个方法 ID3D10Texture2D::Map/ID3D10Texture2D::Unmap . Map 和 Unmap 是配对出现的, 这个方法接近 D3D9 时代的 IDirect3DTexture9::LockRect/IDirect3DTexture9::UnlockRect . 同样也由 UINT DstSubresource 指出 Map 哪个 level .

     为什么会有这么多方法呢? 因为这几种存储数据的方式不一样. 以 IMMUTABLE 创建的资源在创建之后数据是不能改变的(其实我们在渲染的时候大多数纹理都属于这种类型, 比如说模型的 BaseTexture NormalMap SpecularMap LightMap , 这些都是只需要初始化一次就可以, 没有更改的必要). UpdateSubresource 是先把数据拷贝到 D3D 的命令缓冲区, 然后执行到拷贝命令的时候再由 GPU 拷贝到 Resource 里面. 使用 Map 方法时候 CPU 和 GPU 是要同步的, 具体说明见 DXSDK 的 Copying and Accessing Resource Data 部分, 使用 Map 的时候一定要注意时机, 如果时机不好会极大降低性能和效率.

     现在说一说 RenderTarget 这种输出型的纹理(1). 有时候我们需要使用 R2T 的纹理当作输入纹理再传进 Shader 里, 这时候如果需要 Mipmap 怎么办呢? ID3D10Device::GenerateMips 就可以帮上忙了. 使用 GenerateMips 必须有以下几个条件:

  • 创建纹理的时候的 BindFlag 必须有 D3D10_BIND_RENDER_TARGET 标志. 也就是只有 RenderTarget 作为 ShaderResource 使用的时候才可以对其使用 GenerateMips 生成 Mipmap .
  • 创建纹理的时候的 D3D10_TEXTURE2D_DESC::MiscFlags 必须有 D3D10_RESOURCE_MISC_GENERATE_MIPS 标志.
  • Mipmap 从最大级别创建到 ResourceView 中声明的最小级别.
  • Mipmap 的创建对纹理有格式要求, 具体参见 DXSDK.

     以上就是对 D3D10 使用 Mipmap 的一些总结. 其中 ShaderResource 的数据上传方法不仅对 Mipmap 有用, 同时也是初始化纹理的方法.

 

注: (1) 所谓的输入型纹理就是输入到 Shader 中进行采样的普通纹理, 输出型纹理就是 RenderTarget , 往往渲染到纹理之后我们还需要用 RT 当作数据再次输入到Shader 中进行操作(比如说 PostProcessEffect), 这种数据的来源不是文件或者初始化的时候人工数据, 而是在运行期实时计算出来的.