D3D紋理映射

1,要點
首先我覺得D3D紋理映射的選項太多,給人一種眼花繚亂的感覺,而且剛看的時候並不容易分辯不同選項之間的差別,不知道如何使用這些選項,或者說不知道這些選項對應以前經驗中的哪些效果。這些選現包括:
  • Dark mapping
  • Animated Dark mapping
  • Blending with Material Diffuse Color
  • Darkmap with Material Diffuse Color
  • Glow mapping
  • Detail mapping
  • Modulate mapping
  • Blending with Frame Buffer
  • Trillinear Filtering
  • Clamp Addressing Mode
  • Mirror Once
  • Border Color.
使用的主要API就是:
  • HRESULT SetSampleState(
                 DWORD Sampler,//紋理階段號
                 D3DSAMPLERSTATETYPE type,//採樣器狀態類型
                 DWORD value)//採樣器狀態值
,用於指定紋理的過濾方式,貼夾方式(tiling/clamping)和MIPLOD方式等等。
  • HRESULT SetTextureStageState(
                     DWORD Stage,//紋理階段號
                     D3DSAMPLERSTATETYPE type,//採樣器狀態類型
                     DWORD value)//採樣器狀態值

用於爲使用固定功能的多紋理單元提供附加的操作功能。包括:不同的紋理座標,顏色操作,alpha操作,凹凸映射/環境映射。
--------------------------------------------
2,紋理座標
對於一個頂點,最多允許使用八組紋理座標(D3DFVF_TEX1到D3DFVF_TEX8),可以利用D3DTSS_TEXCOORDINDEX來選擇某組特定的紋理座標:

m_pd3dDevice->SetTexture(0,m_pWallTexture);
m_pd3dDevice->SetTextureStateState(0,D3DTSS_TEXCOORDINDEX,0);
m_pd3dDevice->SetTexture(1,m_pWallTexture);
m_pd3dDevice->SetTextureStateState(1,D3DTSS_TEXCOORDINDEX,1);
上邊第一張紋理使用了頂點的第一組紋理座標,第二張紋理使用了頂點的第二組紋理座標。當然也可以讓第二張紋理也使用第一組紋理座標,這要是情況而定。

--------------------------------------------
3,四種紋理尋址模式

紋理尋址方式實在是我又查詢了其他一些網站之後才知道的事情,因爲以前用openGL的時候對紋理映射方式一點都沒有接觸過,因此這部分看起來就的確顯得有點難度了。

一般來說,分配的U、V紋理座標值都在0.0到1.0範圍內(包括它們)。但是,如果我們分配了超出這個範圍的紋理座標,可能會得到一些特別的紋理效果。通過設置紋理尋址模式,我們就可以在紋理座標超出範圍時進行控制,紋理尋址模式就是用來幹這個的。

 包裝(Wrapping)紋理尋址模式

  “Wrapping”紋理尋址模式由D3DTEXTUREADDRESS枚舉類型的D3DTADDRESS_WRAP成員來確定,它使Direct3D在每一個整數結點(integer junction)對紋理進行重複。假設我們要創建一個正方形圖元,並將紋理座標聲明爲(0.0,0.0)、(0.0,3.0)、(3.0,3.0)和(3.0,0.0)。這時,如果我們設置了紋理尋址模式,就可以使紋理在U、V方向都重複三次。,如下圖所示:

pic76.gif (64086 bytes)

  這種紋理尋址模式的效果與“鏡像”模式比較相似,但在本質上是不同的。

鏡像紋理尋址模式

  “鏡像”紋理尋址模式由D3DTEXTUREADDRESS枚舉類型的D3DTADDRESS_MIRROR成員來確定,它使Direct3D在每個整數邊界處(integer boundary)對紋理進行鏡像處理。想在我們創建一個正方形圖元,爲座標爲(0.0,0.0)、(0.0,3.0)、(3.0,3.0)和(3.0,0.0)。我們設置鏡像紋理尋址模式,紋理在U、V方向都重複了三次,並且每一行、每一列都與相鄰的行和列成鏡像關係。如下圖所示:

pic77.gif (15582 bytes)

鉗位紋理尋址模式

  “鉗位”紋理尋址模式由D3DTEXTUREADDRESS枚舉類型的D3DTADDRESS_CLAMP成員確定,它使Direct3D將紋理座標鉗制在[0.0, 1.0]範圍內。也就是說,它只使用一次紋理,然後將邊緣像素的顏色抹去。我們創建一個正方形圖元,紋理地址分配爲(0.0,0.0)、(0.0,3.0)、(3.0,3.0)和(3.0,0.0)。這時,設置鉗位紋理尋址模式,紋理將只使用一次,並且最頂一行和最後一列上的像素顏色會一直延伸到圖元的最頂端和最右段,如下圖所示:

pic78.gif (5443 bytes)

 

邊界顏色紋理尋址模式

  “邊緣顏色”紋理尋址模式由D3DTEXTUREADDRESS枚舉類型的D3DTADDRESS_BORDER成員確定,它使Direct3D可以在紋理座標超過範圍的地方使用一個任意的顏色,也就是邊界顏色。

  下圖中展示了一個使用了紋理的圖元,它使用了紅色的邊界色:

pic79.gif (5657 bytes)

一次鏡像尋址模式

這個模式由D3DTEXTUREADDRESS枚舉類型的D3DTADDRESS_MIRRORONCE成員確定,是從DirectX8才引入的新的紋理尋址模式,類似於鏡像模式於夾持模式的組合。紋理再-1.0到1.0之間做鏡像,而在該範圍之外做夾持。

-----------------------------------------
4,紋理包裝(Wrapping)
簡單來說,紋理Wrapping就是要改變Direct3D光柵使用紋理座標對有紋理的多邊形進行光柵操作的基本方式。我們對一個多邊形進行光柵操作時,系統在每一個多邊形頂點的紋理座標之間進行內插運算,這樣來決定在多邊形的每個像素上所使用的紋理像素。通常,系統將紋理看作一個二維平面,在這個平面內A、B兩點間的連線上進行內插。如果點A的U、V座標爲(0.8, 0.3),點B爲(0.1,.9),那麼進行內插的連線就如下圖所示:

pic85.gif (2608 bytes)
  注意,上圖中A、B兩點的最短連線穿過了紋理的中間部分。U、V紋理Wrapping的使用會影響Direct3D在U、V方向上對紋理座標間最短連線的選取。現在我們假定0.0與1.0重合,那麼通過定義,紋理Wrapping就會導致光柵在紋理座標設置之間來選擇最短距離。我們可以認爲一個方向上的紋理Wrapping就是讓系統認爲將一個紋理包裹在了一個圓筒上,就象下圖中那樣:

pic86.gif (3890 bytes)

   上圖中我們在U方向上進行了Wrapping,它影響了系統對紋理座標進行的插值操作。我們使用同樣的兩個點A和B,可以看到,它們之間最短的連線不再通過紋理的中間部分;它現在穿越了0.0和1.0所在的交界線。沿V方向的Wrapping與它相似,只不過紋理所包裹的圓筒橫躺在地上。U、V方向上同時進行Wrapping比較複雜,這時我們可以將紋理想象成一個園環面或者是麪包圈的形狀。
   再具體說明一下,就是說如果按照U方向來包裝就取U方向的最小距離線段,在該段上做插值;如果如果按照V方向來包裝就取V方向的最小距離線段,然後做插值。那麼設置了按U&V方式可以將紋理想象成一個環形。
   需要注意的是,在啓用紋理包裝之後將使[0,1]之外的紋理座標成爲無效值,所以紋理包裝不能於各種紋理尋址模式共用。
----------------------------------------------

5,紋理過濾和抗鋸齒(反走樣Anti-Aliasing)

紋理過濾和反走樣解決的是同一類問題,就是屏幕鋸齒的問題,不同的是文理過濾解決的是紋理映射過程中的鋸齒,而反走樣解決的是幾何體邊沿的鋸齒。

  • MipMap:是由一系列紋理組成的分辨率分級的特殊紋理形式。

一個mipmap就是一系列的紋理,每一幅紋理都與前一幅是相同的圖樣,但是分辨率都要比前一幅有所降低。mipmap中的每一幅或者每一級圖象的高和寬都比前一級小二分之一。Mipmap並不一定必須是正方形。
高分辨率的mipmap圖象用於接近觀察者的物體。當物體逐漸遠離觀察者時,使用低分辨率的圖象。Mipmap可以提高場景渲染的質量,但是它的內存消耗卻很大。
  Direct3D將mipmap描繪成一系列相互聯繫的表面。高分辨率的紋理位於開始處,並與下一級紋理相互聯繫。以此類推,紋理相互聯繫,逐漸排列到分辨率最小的一級。
 下面這套插圖顯示了這樣的一個例子。這套紋理是一個三維場景中一個集裝箱的標籤。當我們創建了一個mipmap時,分辨率最高的一幅紋理就是這一套紋理的第一個。這套mipmap中的每一個紋理寬高都是前一個紋理寬高的二分之一。這樣,最大分辨率的紋理是256x256,接下來的紋理就是128x128,最後一個紋理就是64x64。
我們有一個能看到這個標籤的最大距離。如果觀察者從遠處向標籤走近,那麼場景中首先會顯示最小的一幅紋理,它的大小是64x64的。

pic84.gif (19673 bytes)pic83.gif (8944 bytes)pic82.gif (3304 bytes)

當觀察者走進標籤時,我們就使用更高分辨率一幅紋理;當觀察者走到允許的最近距離時,我們使用分辨率最高的那幅紋理.

  這是方法能夠模擬紋理的透視效果並能夠減少處理時的計算量。與將一幅紋理用於不同的分辨率相比,這種方法更加快速。
  Direct3D能夠訪問mipmap中與我們想要輸出的分辨率最接近的那個紋理設置,並將像素映射到它的紋理像素空間中。如果最終圖象的分辨率在mipmap紋理的分辨率的中間,那麼Direct3D會對兩幅紋理中的紋理像素進行檢查,並將它們的顏色值進行融合。
  提供給CreateTexture()正確的參數就可以自動創建MipMap紋理。
  • 紋理過濾方法:最近點採樣,線性紋理過濾,各項異性過濾,混合過濾

   過濾是指通過給定的UV座標從紋理貼圖中獲取圖素的一種方法。一張64*64的紋理映射到400*400象素的多邊形就會出現因放大而造成的鋸齒,這稱爲放大問題;一張64*64的紋理映射到10*10象素的多邊形的時候,一個屏幕象素對應多個紋理圖素,就會因交替佔有象素而出現抖動。那麼爲了解決這個問題,就要採用紋理過濾方法。在默認的顯卡設置中,紋理過濾的方法是由驅動程序控制的。

   最近點採樣是最簡單的過濾方法,顧名思義,就是採用離象素最近的圖素作爲顏色。將紋理座標對齊到最接近的整數,再將那個位於整數座標的紋理圖素作爲最終的顏色。這種方法在處理圖素邊界的時候會發生一些錯誤。

   線性紋理過濾在Direct3D中採用的是雙線性紋理過濾,它計算相對於採樣點距離最近的4個圖素的平均值。採用如下形式進行設置: 
m_pd3Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
m_pd3Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);

   三線性過濾:選擇兩張最接近的mipmap,將它們雙線性過濾爲兩張理想大小的mipmap,然後根據理想的mip級組合這兩張過濾厚的mipmap中的對應象素。採用如下形式進行設置: 
m_pd3Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
m_pd3Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
m_pd3Device->SetSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_LINEAR);

各向異性過濾:雙線性過濾和三線性過濾的缺點是他們都使用正方形採樣區域來採樣圖素,如果紋理是側着朝向視點的化則會發生一種稱之爲“各向異性”的失真效果。那麼各向異性過濾則會把因爲透視投影拉伸的幾何體大小映射回紋理空間中,使得紋理在投射時候被伸張,因此來獲得更佳的深度細節和精確顯示。使用各向異性過濾的代碼如下:
m_pd3Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
m_pd3Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC);
m_pd3Device->SetSamplerState(0,D3DSAMP_MAXD3DTEXF_ANISOTROOPY,16);

  • 反走樣:現在反走樣已經是DirectX中的一項默認特徵。

全屏反走樣(FSAA):採用全屏多采樣對每個象素進行對此採樣,進行混合後進行輸出,通過這種方式來調整圖像中每條斜線周圍的亮度來隱藏騎上的鋸齒效果,它沿着這些邊沿產生局部模糊的效果。一種更爲高級的多采樣成爲“可屏蔽多采樣(maskable multisampling)”。

  • alpha混合

alpha混合不知道怎麼搞到這一章來介紹,可能是爲了利用這一個沒有程序的篇章把該介紹的基本知識介紹完吧。我也姑且寫到這裏。

alpha混合的原理很簡單,就是利用混合因子把要繪製到幀緩存中的顏色和當前幀緩存中的顏色進行一個疊加,因此可以實現多次渲染,從而實現許多特效。對應的代碼像下面這種形式:
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ZERO);
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章