效果圖形中的精確度和數值裁剪

使用 Direct2D 轉譯效果的應用程式必須小心,才能達到數值精確度所需的品質和可預測性層級。 本主題描述 Direct2D 中的最佳做法和相關設定,如果:

  • 您的效果圖形依賴 [0, 1] 範圍以外的高數值精確度或色彩,而且您想要確定一律可以使用這些精確度或色彩
  • 或者,您的效果圖形依賴轉譯實作,將中繼色彩固定到 [0, 1] 範圍,而且您想要確保一律會發生此限制

Direct2D 通常會將效果圖形分割成區段,並在個別步驟中轉譯每個區段。 某些步驟的輸出可能會儲存在中繼 Direct3D 紋理中,根據預設,其數值範圍和精確度有限。 Direct2D 不保證是否使用這些中繼紋理或位置。 此行為可能會根據 GPU 功能以及 Windows 版本之間而有所不同。

在Windows 10中,Direct2D 會因為使用著色器連結而使用較少的中繼紋理。 因此,Direct2D 可能會產生與先前 Windows 版本不同的預設設定結果。 這主要會影響效果圖形中可能連結著色器的案例,而該圖表也包含產生延伸範圍輸出色彩的效果。

效果轉譯和中繼概觀

為了呈現效果圖表,Direct2D 會先尋找「轉換」的基礎圖形,其中轉換是效果中使用的圖形節點。 有不同類型的轉換,包括提供 Direct3D 著色器以供 Direct2D 使用的轉換。

例如,Direct2D 可能會轉譯效果圖表,如下所示:

具有中繼紋理的效果圖表

Direct2D 會尋找減少用來呈現效果圖形的中繼紋理數目的機會;此邏輯對應用程式不透明。 例如,使用一個 Direct3D 繪製呼叫和沒有中繼紋理,Direct2D 可以轉譯下列圖表:

沒有中繼紋理的效果圖

在Windows 10之前,如果相同效果圖表中使用多個圖元著色器,Direct2D 一律會使用中繼紋理。 大部分的內建效果,只要 (調整色彩值,例如亮度或飽和度) 則使用圖元著色器。

在Windows 10中,Direct2D 現在可以避免在這種情況下使用中繼紋理。 它會透過在內部連結相鄰圖元著色器來這樣做。 例如:

具有多個圖元著色器且沒有中繼紋理的 Windows 10 效果圖形

請注意,圖形中的所有相鄰圖元著色器可能連結在一起,因此,只有特定圖表會在Windows 10產生不同的輸出。 如需完整詳細資料,請參閱 效果著色器連結。 主要限制如下:

  • 如果第一個效果是當做輸入連接到多個效果,效果就不會與取用其輸出的效果連結。
  • 如果第一個效果在與其輸出不同的邏輯位置取樣輸入,效果將不會與效果集連結為輸入。 例如,色彩矩陣效果可能會與其輸入連結,但不會有卷積效果。

內建效果行為

許多內建效果可能會在未取代的色彩空間中產生 [0, 1] 範圍以外的色彩,即使其輸入色彩位於該範圍內亦然。 發生這種情況時,這類色彩可能會受限於數值裁剪。 請注意,即使內建效果通常會在預先乘法的空間中產生色彩,但請務必考慮未取代空間中的色彩範圍。 這可確保色彩會保留在範圍內,即使其他效果後續未取代它們也一樣。

某些可能會發出這些超出範圍色彩的效果提供 「ClampOutput」 屬性。 其中包括:

將這些效果上的 ClampOutput 屬性設定為 TRUE 可確保不論著色器連結之類的因素為何,都會達到一致的結果。 請注意,固定會在未取代的空間中發生。

其他內建效果也可能在未取代的空間中產生超出 [0, 1] 範圍的輸出色彩,即使其色彩圖元 (,如果任何) 在該範圍內,仍會產生 「Color」 屬性。 其中包括:

強制效果圖形內的數值裁剪

雖然使用上述沒有 ClampOutput 屬性的效果,但應用程式應該考慮強制數值限制。 這可以藉由將額外的效果插入圖形,以限制其圖元。 可以使用色彩矩陣效果,並將其 'ClampOutput' 屬性設定為 TRUE,並將 'ColorMatrix' 屬性保留為預設 (傳遞) 值。

達到一致結果的第二個選項是要求 Direct2D 使用具有更高精確度的中繼紋理。 如下所述。

控制中繼紋理的有效位數

Direct2D 提供數種方式來控制圖形的精確度。 在 Direct2D 中使用高精確度格式之前,應用程式必須確定 GPU 已充分支援它們。 若要檢查此問題,請使用 ID2D1DeviceCoNtext::IsBufferPrecisionSupported

應用程式可以使用 WARP 建立 Direct3D 裝置 (軟體模擬) ,以確保所有緩衝區精確度都不受裝置上實際 GPU 硬體支援。 這在將效果套用至相片時,建議在儲存至磁片時套用效果。 即使 Direct2D 支援 GPU 上的高精確度緩衝區格式,在功能層級 9.X GPU 上建議使用 WARP,因為某些低階行動 GPU 的著色器算術和取樣精確度有限。

在下列每個案例中,要求的有效位數實際上是要使用的最小精確度 Direct2D。 如果不需要中繼,可以使用較高的精確度。 Direct2D 也可以共用相同圖形或不同圖形不同部分的中繼紋理。 在此情況下,Direct2D 會使用所有涉及作業所要求的最大精確度。

ID2D1DeviceCoNtext::SetRenderingControls 的有效位數選取

控制 Direct2D 中繼紋理精確度的最簡單方式是使用 ID2D1DeviceCoNtext::SetRenderingControls。 這可控制所有中繼紋理的精確度,只要精確度未直接在效果或轉換上手動設定。

if (Device->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
  // Get the current rendering controls
  D2D1_RENDERING_CONTROLS renderingControls = {};
  Context->GetRenderingControls(&renderingControls);

  // Switch the precision within the rendering controls and set it
  renderingControls.bufferPrecision = D2D1_BUFFER_PRECISION_32BPC_FLOAT;
  Context->SetRenderingControls(&renderingControls);
}
              

輸入和轉譯目標的精確度選取

應用程式也可能依賴效果圖形的輸入精確度來控制中繼紋理的精確度。 只要未使用 ID2D1DeviceCoNtext::SetRenderingControls指定緩衝區有效位數,就不會在效果上手動設定,而且不會直接進行轉換。

效果輸入的有效位數會透過圖形傳播,以選取下游中繼的精確度。 效果圖表中的不同分支符合時,會使用任何輸入的最大精確度。

根據 Direct2D 點陣圖選取的有效位數取決於其像素格式。 針對 ID2D1ImageSource 所選取的有效位數取決於用來建立 ID2D1ImageSource之基礎 IWICBitmapSource 的 WIC 像素格式。 請注意,Direct2D 不允許使用 Direct2D 和 GPU 不支援的有效位數,使用 WIC 來源建立影像來源。

Direct2D 可能無法根據其輸入來指派有效位數的效果。 當效果沒有輸入,或是使用 ID2D1CommandList 時,就會發生此情況,其沒有特定的有效位數。 在此情況下,中繼紋理的有效位數會從點陣圖集決定為內容的目前轉譯目標。

直接在效果和轉換上選取精確度

中繼紋理的最小精確度也可以在效果圖形內的明確位置設定。 這僅適用于進階案例。

您可以使用效果上的 屬性來設定最小精確度,如下所示:

if (Device->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
  hr = Effect->SetValue(D2D1_PROPERTY_PRECISION, D2D1_BUFFER_PRECISION_32BPC_FLOAT);
}
              

在效果實作中,可以使用 ID2D1RenderInfo::SetOutputPrecision 來設定最小精確度,如下所示:

if (EffectContext->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
  hr = RenderInfo->SetOutputBuffer(
  D2D1_BUFFER_PRECISION_32BPC_FLOAT,
  D2D1_CHANNEL_DEPTH_4);
}
              

請注意,除非在這些下游效果上設定不同的有效位數,否則效果上設定的有效位數將會傳播至相同效果圖形中的下游效果。 在效果內的轉換上設定的有效位數不會影響下游轉換節點的有效位數。

以下是用來判斷儲存指定轉換節點輸出之中繼緩衝區之最小精確度的完整遞迴邏輯:

中繼緩衝區最小精確度邏輯