天天看點

D3D10 技術Mipmap

 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), 這種資料的來源不是檔案或者初始化的時候人工資料, 而是在運作期實時計算出來的.

繼續閱讀