使用 gamma 修正

簡短的 Gamma 校正或 gamma 是系統用來編碼和解碼影像中圖元值的非線性作業名稱。

何謂 gamma,以及其用途為何?

在圖形管線的結尾,只有影像離開電腦以沿著監視器纜線進行旅程的位置,有一小段硬體可以即時轉換圖元值。 此硬體通常會使用查閱表格來轉換圖元。 此硬體會使用來自表面的紅色、綠色和藍色值來顯示,以查閱資料表中的 gamma 更正值,然後將更正的值傳送至監視器,而不是實際表面值。 因此,此查閱表格有機會以任何其他色彩取代任何色彩。 雖然資料表具有該等級的電源,但一般使用方式是稍微調整影像,以補償監視器回應的差異。 監視器的回應是將圖元的數值與該圖元顯示亮度相關的函式。

這就是此表格的用途,但遊戲開發人員發現它的創意用途,例如將整個螢幕閃爍為紅色,以取得創意效果。 在現代遊戲應用程式中,作為每個畫面後處理的一部分,我們通常會提供其他方式來執行這類動作。 事實上,我們建議您單獨離開 gamma 資料表,因為它可能用來校正監視器的回應,而對 gamma 坡道的徹底變更將會終結這個仔細的校正。

判斷 gamma 校正的科學很複雜,但這裡未顯示,除了用來照亮名稱 「gamma」 的來源以外。 CRT (,也就是舊式玻璃) 監視器的回應是複雜的函式,但這些監視器的物理特性表示它們會顯示可由此電源函式所代表的回應:

亮度 (輸入) = 輸入gamma

gamma 值通常接近 2.0 的值。 針對這些新技術,系統會特別設計用於呈現類似的回應,因此我們所有的軟體和映射都不需要重新建構這些新技術。 sRGB 標準宣告此 gamma 值剛好是 2.2,而這個值已成為廣泛實作的標準。

人類眼睛也有一個回應函式,大約會反轉 CRT 電源函式。 這表示圖元的認知亮度會以線性方式與該圖元中的 RGB 值一起增加。

由於 gamma 值為 2.2 已成為事實標準,因此我們通常不需要擔心此資料表中編碼的 gamma 曲線太多,而且可以將它保留為線性、一對一對應。 正確色彩比對當然需要謹慎處理此函式,但該討論超出本主題的範圍。 Windows 包含一個工具,可讓使用者校正其顯示器至 gamma 2.2,此工具會使用查閱表格硬體來衍生其電腦的謹慎選擇細微調整。 使用者可以藉由搜尋「校正色彩」來執行此工具。 特定監視器也有定義完善的色彩設定檔,可將此程式自動化。 「校正色彩」工具可以偵測這些較新的監視器,並通知使用者已就緒校正。

這種將電源法編碼為色彩值的概念,在圖形管線的其他位置也很有用,特別是在紋理中。 對於紋理,您會想要更深色的精確度,因為我們剛才討論的對數人眼回應。 在管線的這個部分中仔細處理 gamma 很重要。 如需詳細資訊,請參閱 轉換色彩空間的資料

本主題的其餘部分只著重于管線最後一個部分的 gamma 修正,其位於畫面格緩衝區資料與監視器之間。 如果您想要撰寫校正精靈,或在全螢幕應用程式中建立特殊效果,其中後置處理步驟並不實用,以下是您需要的資訊。

Windows 上的 gamma 背景

Windows 電腦通常會有 gamma 資料表,這是採用三倍位元組的查閱表,並輸出三倍位元組。 這些三倍數是 768 (256 x 3) 個 RAM 位元組。 當您的顯示格式包含三倍的 RGB BYTE 值,但無法表達足以描述當顯示格式的範圍大於 [0,1] 時,您可能想要的轉換,例如浮點值。 Windows 中控制 gamma 的 API 遵循演進,因為顯示格式變得更複雜。

提供 gamma 控制的第一個 Windows API 是 Windows 圖形裝置介面 (GDI) 的 SetDeviceGammaRampGetDeviceGammaRamp。 這些 API 使用三個 256 個專案的 WORD 陣列,每個 WORD 編碼零最多一個,以 WORD 值 0 和 65535 表示。 WORD 的額外精確度通常無法在實際的硬體查閱資料表中使用,但這些 API 的目的是要有彈性。 這些 API 與本節稍後所述的其他 API 相反,只允許與身分識別函式的小型偏差。 事實上,坡形中的任何專案都必須在識別值的 32768 內。 此限制表示沒有應用程式可以將顯示器完全黑色或轉換成其他無法讀取的色彩。

下一個 API 是 Microsoft Direct3D 9 的 SetGammaRamp,其遵循與 SetDeviceGammaRamp相同的模式和資料格式。 Direct3D 9 gamma 坡形的預設值並不特別有用;它是初始化為 0-255 的 WORD 坡形,而不是 0-65535,即使 API 是以 0-65535 定義也一樣。

最新的 API 是 IDXGIOutput::SetGammaControl。 此 API 具有更彈性的配置來表示 gamma 控制項,因為 DXGI 增加的顯示格式集,包括每個通道的十個整數位、16 位浮點數格式,以及XR_BIAS擴充範圍格式。

所有這些 API 都會在相同的硬體上運作,並變更相同的值。 Direct3D 9 和 DXGI API 是「僅寫入」。 您無法讀取硬體的值、加以修改,然後加以設定。 您只能設定坡道。 此外,您只能在應用程式全螢幕時設定 gamma。 這項限制是保證桌面一律可讀取的另一種方式。 也就是說,應用程式可能會干擾自己的顯示,但當應用程式失去全螢幕 (時,Windows 會透過 alt-tab 或 ctrl-alt-del) 還原先前的 gamma 坡形。

顯示硬體的演進

某些較新的監視器可能會顯示各種不同的濃度。 但是,當顯示格式只能代表介於零到一之間的值時,顯示器必須將零對應至最深的值,另一個則對應至最亮的值。 這個最亮的值可能太亮,無法輕鬆在白色背景上檢視黑色文字的網頁,但對於超亮的特殊效果而言很完美,例如檢視湖外光或閃電飛出天形。 因此,我們需要一種方式來表達這些更廣泛的範圍。 DXGI 1.1 和更新版本包含顯示格式值,讓 1.0 代表一個熟悉的白色值,並保留較寬的顯示格式值,以供過度亮起的特殊效果使用。 DXGI 1.1 支援兩種顯示格式,可表示這些更廣泛的值:DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM和 16 位浮點數。 如需這些格式的完整討論,請參閱 擴充格式的詳細資料。 接下來,我們將探討 DXGI 的 IDXGIOutput::SetGammaControl gamma API 需要大於 1.0 的圖元值的原因。

DXGI 中的 Gamma 控制功能

DXGI 可讓顯示驅動程式將其 gamma 控制項表示為逐步線性函式。 這個步驟線性函式是由此函式的控制點所定義、函式可以轉換成的值範圍,以及可在轉換之後套用的其他選擇性刻度和位移作業。 應用程式可以呼叫 IDXGIOutput::GetGammaControlCapabilities 方法,以擷取 DXGI_GAMMA_CONTROL_CAPABILITIES 結構中的所有控制功能。

此圖表顯示只有四個控制點的線性函式。

gamma 修正線性函式

DXGI 會依其沿著介面色彩軸的位置來定義控制點。 在上圖中,控制點的位置為 0、0.5、0.75 和 1.0。 這些控制點表示硬體可以轉換範圍 0 到 1.0 中的值。 DXGI 會列出 controlPointPositions 陣列成員中 DXGI_GAMMA_CONTROL_CAPABILITIES 的這些控制點,而且一律會依遞增順序宣告這些控制點。 DXGI 只會填滿ControlPointPositions陣列的第一個專案,並指出具有 DXGI_GAMMA_CONTROL_CAPABILITIES之 NumGammaControlPoints成員的專案數目。 如果 NumGammaControlPoints 小於 1025,DXGI 會保留未定義的 ControlPointPositions 元素其餘部分。

此圖表所代表的硬體可以將值轉換成 0 到 1.25 的範圍。 因此,DXGI 會將 MinConvertedValueMaxConvertedValue 成員分別設定為 0.0f 和 1.25f。

DXGI 會設定DXGI_GAMMA_CONTROL_CAPABILITIESScaleAndOffsetSupported成員,以指出硬體是否支援縮放和位移功能。 如果硬體支援縮放和位移,它會保留簡單的一對一查閱表格,然後調整資料表的輸出,將輸出延展至大於 [0,1] 的範圍。 硬體會先調整查閱表格中產生的值,然後加以位移。

注意

連線到相同電腦的不同監視器可能會有不同的 Gamma 控制功能。 此外,gamma 控制項功能實際上可能會根據輸出的顯示模式而變更。 因此,建議您在 App 進入全螢幕模式之後,一律呼叫 IDXGIOutput::GetGammaControlCapabilities 來查詢 gamma 控制功能。

 

您可以使用這些 gamma 控制項功能值來衍生控制項值,然後使用 IDXGIOutput::SetGammaControl API 來設定這些值。

使用 DXGI 設定 gamma 控制項

若要設定 gamma 控制項,請在呼叫IDXGIOutput::SetGammaControl API 時,將指標傳遞至DXGI_GAMMA_CONTROL結構。

您可以設定DXGI_GAMMA_CONTROLScale和 Offset 成員,以指定您想要硬體套用至查閱表格中取得值的刻度和移值。 您可以將 Scale 設定為 1, 而 Offset 設定為零 (即刻度沒有作用,而零的位移沒有作用) ,如果您不想要使用縮放和位移功能,或硬體沒有該功能,則位移沒有作用。

您可以將DXGI_GAMMA_CONTROLGammaCurve陣列成員設定為 gamma 曲線上點的DXGI_RGB結構清單。 每個 DXGI_RGB 元素會指定代表該點之紅色、綠色和藍色元件的浮點數。 gamma 曲線不會使用 Alpha 值。 您可以使用從DXGI_GAMMA_CONTROL_CAPABILITIES 的 NumGammaControlPoints取得的數位來填滿GammaCurve陣列中的元素數目。 您在 GammaCurve 陣列中放置的每個元素都是每個控制點的高度。

請注意,在上圖中,您現在已控制每個控制點的垂直位置,而且您有個別的紅色、綠色和藍色控制項。 例如,您可以將所有綠色和藍色值設定為零,並將紅色值設定為從零到 1 的遞增指示器。 在此案例中,顯示的影像只會顯示其紅色部分,而藍色和綠色會顯示為黑色。 您也可以設定所有色彩的遞減水流,這會導致反轉顯示。 您在GammaCurve陣列中放置的任何值都必須包含在您從DXGI_GAMMA_CONTROL_CAPABILITIES 的 MinConvertedValueMaxConvertedValue成員取得的值內。

Gamma 控制項實際性

只要應用程式為全螢幕,DXGI 的 gamma 控制項才會套用。 當應用程式結束時或返回視窗模式時,Windows 會還原顯示器的先前狀態。 但如果應用程式重新進入全螢幕模式,Windows 就不會還原應用程式的 gamma 狀態。 當您的應用程式重新進入全螢幕模式時,必須明確還原其 Gamma 狀態。

並非所有配接器都支援 gamma 控制項。 如果配接器不支援 gamma 控制項,則會忽略設定 gamma 坡形的呼叫。

在遠端桌面下執行的應用程式完全無法控制 Gamma。

如果滑鼠游標是在硬體 (實作,因為大部分是) ,通常不會回應 gamma 設定。

DXGI 的程式設計指南