Real-Time Rendering 第六章 texture

路人張德帥 2022-01-07 20:58:25 阅读数:837

real-time real time rendering 第六章

在計算機圖形學中,紋理化就是使用一些圖片,函數或者其它的一些數據,修改錶面錶現的一個過程

6.1 The Texturing Pipeline

紋理是通過修改shader 中算法中的值,來最終改變渲染結果的

紋理中的像素叫texel,紋理和屏幕上的pixel 區別開來,並沒有其它含義

紋理管線的流程是:首先 獲取模型上的某一點的比特置,這個比特置是在模型坐標空間下的,因為隨著模型動,紋理也在動,然後經過 projector 方法,獲得了紋理坐標(uv坐標,從0-1),這個過程又叫mapping,然後經過一些列的 correspond 方法,把紋理坐標轉換到 texture 空間下(也就是具體的texel坐標,範圍是width-hight,比如1920*1080),然後用該空間下的坐標,從紋理中獲取存儲的值,這些值有可能在經過一些處理

 上面的過程就是整個過程,最後一步不是必須的

 

 這個圖就是上述過程

6.1.1 The Projector Function

projector function 一般由建模師控制,通過把一個三維的坐標,轉換成一個二維的uv坐標,這個過程一般由建模軟件提供,在建模的時候就處理了

常用地projector 方法包括 spherical, cylindrical,  planar projections

不光是點的坐標可以用來作為projector 方法的輸入參數,其它參數也可以用來當做projector的參數,比如頂點的法線,視角方向,projector 的最終目標就是生成正確的uv坐標 ,頂點坐標只是其中的一種方式

一般來說,一個模型用一種projector 方法就够了,但是對於複雜的模型,模型師需要拆分模型,然後應用不同的projector方法,比如

正如前面所說,projector 過程一般在建模軟件中就執行了,然後把uv坐標存儲在頂點數據中,但是可以在shader中執行,比如uv動畫,來改變頂點的uv

但是這種自動映射,會在邊緣處有些縫隙,導致uv不正確,所以一般建模師都會展開貼圖,然後平面映射,目的就是讓頂點的uv坐標更正確

uv 坐標不僅僅是二維的,也有可能是三維的,uvw ,w 用來錶示映射的深度值,也有可能是四維的,uvwq,q用來錶示齊次坐標空間下的坐標

另一個很重要的紋理坐標空間--directional,在該空間下,通過輸入一個方向值,來獲取點的坐標,將這種空間形象化的一種方法是將其作為單比特球體上的點,每個點的法線代錶在該比特置訪問紋理的方向. 使用方向參數化的最常見紋理類型是cube map

同時一維的紋理坐標也有它的用途,比如地形可以從裏面獲取地形的高度

這些uv 坐標在三角形面內進行差值,然後獲取紋理值,在差值之前,我們需要  corresponder functions 把它們轉換到texture image 坐標空間下

6.1.2 The Corresponder Function

Corresponder functions把uv坐標轉換到 texture-space locations 坐標下

我們知道如果uv 在【0-1】內是很好映射的,但是如果uv 超過了這個範圍,該如何錶現呢?

相對應的corresponder function 有

• wrap (DirectX), repeat (OpenGL), or tile—重複

• mirror—過程就像0-1,1-0,0-1,1-0.

• clamp (DirectX) or clamp to edge (OpenGL)—限制在【0-1】

• border (DirectX) or clamp to border (OpenGL)—超過邊界的會繪制成邊界顏色,這個顏色可自定義

Repeated  帶來的一個問題時,當重複超過三次以上,就會顯得不那麼真實,避免這種問題的方法就是,把該貼圖和一個不使用repeated 的貼圖一起使用,從而削弱這種周期性的錶現

6.1.3 Texture Values

在這之後,就是真正獲取到紋理中的texel值了

6.2 Image Texturing

我們通過texture2D(u,v)來獲取紋理中對應的值,這個方法裏面進行了 相對應的corresponder function,有一點不同的是,DX 是左上角為(0,0)點 ,OpenGL是左下角為(0,0)點

dependent texture read:當像素著色器單獨訪問一個紋理時,而不是經過頂點著色器傳入的紋理坐標,就會產生依賴讀取,也就是該紋理坐標的值依賴於之前紋理坐標的值,比如 一個紋理可能改變了法線坐標,同時反過來也影響了 訪問 cube map 的紋理坐標,這個操作在之前是不支持的,現在雖然支持,但是也影響性能。

6.2.1 Magnification

比如你的紋理大小是48*48的,但是覆蓋的模型錶面是480*480的,這時候,底層圖形處理系統,就會放大該紋理,以適應模型錶面,但是這時候就涉及到一個texel 對應多個pixel 的問題,原來一個texel 對應一個pixel ,顏色值正好,現在就涉及到其它9個pixel 的顏色取值問題

常用的filter算法是:nearest neighbor和 bilinear interpolation 和cubic convolution

cubic convolution 用一個4 × 4 or 5 × 5 的texel 數組,來計算最終的顏色值,比較精准,但是硬件一般不支持,可以在shader 中執行

左邊的使用nearest neighbor ,只采樣鄰近的單個texel值 作為 該pixel的值,產生了像素化的效果

中間的使用bilinear interpolation,通過采取鄰近四個texel的值,然後進行水平垂直方向上的差值,獲得最後的color,結果就是會模糊

最右邊的使用bicubic filter ,同樣也能移除像素畫的效果,但是他要比 bilinear filters花費更高的性能

比如我們獲取到的pixel 坐標為(pu,pv) = (81.92,74.24),也就是它在(81.42, 73.74)的坐標空間原點下,那麼該texel的坐標為(81, 73) 到 (82, 74).而該點具體的顏色值,在(0.42,0.74)的比特置,首先分為兩步,我們要計算左下角和右上角的顏色值,然後進行差值

然後計算一個權重,當前texel 的權重為 0.42 × 0.74, 順時針依次為 0.42 × 0.26, 0.58 × 0.26, and 0.58 × 0.74, 加起來正好 1.0. 

解决圖片模糊的方法可以使用額外的一張細節貼圖

6.2.2 Minification 

當一個pixel 對應多個texel 的時候,需要綜合所有的texel 來决定最終pixel的值

一個方法就是nearest neighbor, 和放大是一樣的,選擇裏pixel中心的texel 作為最終的顏色值,會造成鋸齒的效果,如下圖

 另一種方法是 bilinear interpolation, 和 magnification filter.一樣,通過對四個texel采樣,得到最終的顏色,但是如果一個pixel 覆蓋超過了四個texel 也會出現鋸齒問題

 為了解决鋸齒問題,我們上一張討論過,提高采樣率,我們避免出現鋸齒的最低情况,就是一個texel 對應一個 pixel

所有紋理抗鋸齒算法的最終思想都是一樣的,就是預處理紋理,生成不同的數據結構,來適應不同的情况,但是這也會增加處理的時間和內存大小.

Mipmapping

“Mip” 錶示 multum in parvo, 拉丁語是 “many things in a small place”的意思

使用mipmapping ,原始圖像會分成多個不同等級的小圖像,在最低一層,也就是0級,紋理大小是原始大小的四分之一,

需要注意的一點是,在mipmapping的時候,需要把顏色空間轉換到線性空間,生成mipmapping之後,再轉換成gamma 空間保存,這裏面有一個轉換的過程

For this reason, it is important to convert such textures from sRGB to linear space (Section 5.6), perform all mipmap filtering in that space, and convert the final results back into sRGB color space for storage.

這裏使用pixel 框來錶示具體的texel ,其實並不准確,因為周圍的texel 也會影響該pixel的顏色值

DX中用d來錶示mipmapping的等級,等級越高,也到金字塔尖,也就是更模糊,但是d 並不一直是整數,也可能是小數,錶示在兩個mipmapping 之間,這時會采樣兩個mipmap,然後進行線性插值,這個方法叫做 trilinear interpolation

mipmap 的缺點就是 overblurring. 如果一個pixel 僅僅在一個軸向上覆蓋了多個texel,但是mipmap 會在兩個軸向上縮小。

Summed-Area Table

該方法可以避免overblurring 問題,它創建了一個紋理大小的數組,然後每一個值都存儲了更高京都的顏色值,然後决定該pixel 的顏色值,是通過計算覆蓋的texel的平均值

 

 

x , y 是texel 在矩形中的比特置坐標,s(x,y)是錶中的顏色值

 

 summed-area table 是 anisotropic filtering(各向异性) 算法的一個例子, 這種算法在非正方形區域上檢索texel值, SAT 在水平上或者垂直上效率更高

同時也要注意 summed-area tables 對於大小為16 × 16或更小的紋理,需要至少兩倍的內存,對於更大的紋理需要更高的精度。

6.2.6 Texture Compression

一個直接解决內存過大,或者帶寬、緩存問題的的方法 就是 紋理壓縮,通過讓GPU在運行當中解壓縮紋理,可以增大緩存大小,我們壓縮的主要目的 是為了减少帶寬,增大緩存大小,次級目的是為了添加更大的紋理,比如一個512*512的紋理,如果沒有壓縮,一個pixel 占用3byte ,一共需要768kb,而壓縮的1024*1024的紋理,壓縮比是6:1才使用512KB

對於不同的圖像文件格式,如JPEG和PNG,有各種各樣的圖像壓縮方法,但在硬件中實現這些解碼是非常耗性能的

DXTC,DX10之後叫做BC(Block Compress) ,是DX 、OpenGL中標准的壓縮方法,因為很多GPU 都支持它

DXTC 發展到現在,一共有七種變體,分別使用不同的情况,但是它們擁有共同的指標,只不過數值不一樣,在DXTC中,每4*4個texel ,稱為一個block,也叫tile,每一個block都是單獨壓縮,壓縮是基於差值的,對於每一個壓縮的block中,存儲兩個值,比如顏色,block中的每一個texel 都存儲一個interpolation factor(差值因子),然後在這兩個值中取顏色值

 壓縮是因為:只存儲兩種顏色以及每個像素的短索引值,如下圖,也就是每一個塊存儲兩個顏色,就那BC1來說,存儲了兩個RGB值,每一個通道所占的比特數分別為5,6,5,然後就是indices ,每一個texel 占用2個bit,16個就是32bit,使用該差值因子,從兩個存儲的顏色值中獲取該texel的顏色,所以它相對於不壓縮的24比特的紋理,壓縮比為6:1

 BC6H 是為了壓縮HDR(原通道每一個占16bit),BC7是為了LDR

 BC1-5的缺點就是降低了圖像的質量,用4bit/8bit 來錶示16個texel ,如果這16個texel 中的顏色值差別很大,就會造成精度丟失,還有一個原因就是存儲的兩個顏色,都是一條線上的顏色值,但是它並不能代錶整個塊中的顏色值, BC6H and BC7 支持多條線上的顏色值,從而獲取到的顏色更精准

在OpenGL ES,采取了另一種壓縮方法,Ericsson texture compression (ETC),它和DXTC一樣,每一個 4 × 4 的block ,采用 64 bits,每一個texel 4 bits . 但是它每一個 2 × 4 block (or 4 × 2, depending on which gives best quality) 存儲一個基本色stores a base color. 每一個block 還存儲了從a small static lookup table挑選的4個常量值,block中的每一個texel 也可以從錶中選擇一個值,它改變了像素的光照條件,生成的圖像質量和DXTC 差不多

在OpenGL ES 3.0中出現的ETC2算法中,使用未使用的比特組合(unused bit combinations)來為原有的ETC算法增加更多的模式。一個未使用的比特組合(unused bit combinations)是壓縮錶示(compressed representation),它解壓縮到與另一個壓縮錶示相同的圖像,

比如,在BC1中如果存儲的兩個顏色值是相同的,就錶明這個block是一個常量顏色值,這樣其實只用存儲一個顏色值就够了, 在 ETC中,一個顏色值可以通過signed number 從另一個顏色中獲取到 . ETC2  增加了四種顏色的兩種新模式,  Ericsson alpha compression (EAC) 僅僅壓縮圖像 的單個通道,比如alpha 通道,每個像素存儲4個bit

壓縮法線需要注意一下,因為法線是單比特法線,所以一個值可以由另外兩個值獲取到,所以只用存儲兩個值,xy,我們假設z 值是正的,在切線空間下,確實如此,所以法線紋理一般是切線空間下的法線

PVRTC 是為iPhone 或者iPad 准備的壓縮格式,每一個texel占用2-4bit,其關鍵思想是通過對圖像的兩個低頻(平滑)信號,對相鄰的texel data block插值得到。然後在圖像上的兩個信號之間進行插值。

Adaptive scalable texture compression (ASTC)把 n × m texels的block壓縮到  128 bits. block 從 4 × 4 到 12 × 12, 壓縮率也從 0.89 btp 到8 bpt.  ASTC 可以處理1-4個通道的texture, LDR and HDR textures也可以.

所有的壓縮方法都是有損的,也就是質量要比之前低,壓縮要比解壓縮花費更多的時間,因為解壓是通過固定功能的硬件執行的,有的壓縮時間長,有的壓縮時間段,所以一般是離線壓縮,但也有運行時壓縮,比如,天空盒的紋理,每幾秒就壓縮解壓縮一次。

6.3 Procedural Texturing 

給定一個 texture-space 的坐標比特置, 查找image的所以值,是獲取texture 值得一種方法,另一種方法是執行一個方法,因此定義了procedural texture.

現在更多的使用貼圖紋理,是因為GPU的處理能力的提高, 然而,GPU架構正在向更簡單的計算和(相對地)更昂貴的內存訪問發展。這些趨勢使得程序紋理在實時應用中得到了更多的應用

這方面應用最多的是Volume textures,因為Volume textures 需要更多的內存,它是三維的,

 Alpha to coverage 它是利用該片元的透明度,來决定該片元的百分比,比如該片元75%是透明的,那麼該片元的四分三是透明的,剩下的四分之一是不透明的,不透明的部分完全剔除他後面的部分,這對草和樹葉非常有效

對於任何的 alpha mapping, 理解它是如何通過 bilinear interpolation 來影響顏色值的,是非常重要的。

比如兩個相鄰的texel,一個 rgbα = (255,0,0,255) 一個 rgbα = (0,0,0,2), 接近完全透明,那個該texel 的值並不是 (127, 0, 0, 128), 而是完全的紅色,在差值之前就乘以了它的透明度.假如旁邊的texel 換成  rgbα = (0, 255, 0, 2), 帶有一點點綠色,如果不預先乘以透明度,最後的結果是 (127,127,0,128) ,直接變成了黃色,如果旁邊是(0,2,0,2), 預乘以透明度,得到的差值結果是 (127, 1, 0, 128). 也就是乘以該透明通道所占的比例

6.7 Bump Mapping

所有的這些紋理,都是逐像素的去改變它片元的值,

它提供了一個比紋理映射更三維的外觀,但沒有添加任何額外的三角形面。

一個物體的細節可以從三個維度上來錶述:

宏觀上是整體的形狀,中觀上是一小部分的像素,微觀上是單個像素的錶現

這三種狀態是動態切換的,因為我們的視角在變化,和物體之間的距離也在變化

不同種類的 bump mapping 之間的不同,只要在它們錶述細節特點的方式

它直接改變頂點的法線,從而間接更改了光照的計算方式,頂點的法線還是原來的,我們更改的是在光照計算當中的法線值

6.7.1 Blinn’s Methods

Blinn’s original bump mapping中每一個texel存儲了兩個值:bu 和 bv, 它是通過給法線增加一個偏移,從而達到改變法線的目的.

 

另一種凹凸貼圖,是使用一個 heightfield 來修改法線的方向,每一個黑白點都是代錶一個高度,白色代錶高,黑色代錶低,它是通過與相鄰texel 高度的差值,來獲取水平和垂直方向的偏移,這也是最原始的改變法線方向的方法

6.7.2 Normal Mapping

 

 

這是最直接改變法線的方式,直接存儲了在渲染計算中需要用到的法線,因為法線紋理像素的顏色值是在[0-255]之間,但是法線是[-1,1]之間,所以就需要一個顏色值與法線值之間的一個映射關系,-1 代錶0 , 0代錶128  ,1 代錶255 ,很多法線都是淺藍色,錶示它的法線和原來比沒有變化,也就是[0,0,1],也就是法線貼圖中存儲的法線,並沒有改變原來法線的值

法線貼圖分為兩種類型,一種是存儲了世界空間下的法線,這個在渲染中可以直接從中獲取值,很少使用,或者是模型空間下的法線,但是,這種不好的地方就是  它跟著模型走,如果模型變了,它就不適用了,比如還了一個其它的模型

另一種是存儲切線空間下的法線,這個就是要把光照,視角方向轉換到切下空間下運算,而且z 防線永遠是正的,

6.8 Parallax Mapping

 視差指的是物體的比特置隨著視角的移動而相對地移動。隨著視角的移動,凸起應該看起來有高度。視差映射的關鍵思想是通過檢查一個像素中可見物體的高度來進行有根據的猜測

 在視差貼圖中,bump被存儲在一個heightfield texture中,也可以和其它的值合並在同一張貼圖中,反正它就占用一個通道。當觀察一個指定的像素時,檢測該像素的高度,然後以此來改變該錶面其它pixel的uv坐標,從而呈現出不同的狀態

改變方式如下圖:

 Given a texture-coordinate location p, an adjusted heightfield height h, and a normalized view vector v with a height value vz and horizontal component vxy, the new parallax-adjusted texture coordinate padj is

 它就是根據你視角的方向,改變了該比特置的uv ,也就是獲得了一個新的法線法線方向,從而改變了光照效果

但是如果當你靠近水平方向觀看時,因為新得到的比特置與原始地面比特置的高度差不多。因為Vz接近於0

6.8.1 Parallax Occlusion Mapping

 

版权声明:本文为[路人張德帥]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201072058248705.html