這兩天看紋理映射看的頭大,我認為這是《Direct3D游戲入門教程》這本書寫的不好的一個地方,解釋的不清楚,或者說認為讀者水平太高。看了第一遍沒有什么感覺,又看了一遍,還是感覺不太清楚的樣子。反正先寫下來吧,將來有了更多的理解再進行補充。
-------------------
1,要點
首先我覺得D3D紋理映射的選項太多,給人一種眼花繚亂的感覺,而且剛看的時候并不容易分辯不同選項之間的差別,不知道如何使用這些選項,或者說不知道這些選項對應以前經(jīng)驗中的哪些效果。這些選現(xiàn)包括:
- 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就是:
DWORD Sampler,//紋理階段號
D3DSAMPLERSTATETYPE type,//采樣器狀態(tài)類型
DWORD value)//采樣器狀態(tài)值
,用于指定紋理的過濾方式,貼夾方式(tiling/clamping)和MIPLOD方式等等。
-
HRESULT SetTextureStageState(
DWORD Stage,//紋理階段號
D3DSAMPLERSTATETYPE type,//采樣器狀態(tài)類型
DWORD value)//采樣器狀態(tài)值
用于為使用固定功能的多紋理單元提供附加的操作功能。包括:不同的紋理坐標,顏色操作,alpha操作,凹凸映射/環(huán)境映射。
--------------------------------------------
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,四種紋理尋址模式
紋理尋址方式實在是我又查詢了其他一些網(wǎng)站之后才知道的事情,因為以前用openGL的時候?qū)y理映射方式一點都沒有接觸過,因此這部分看起來就的確顯得有點難度了。
一般來說,分配的U、V紋理坐標值都在0.0到1.0范圍內(nèi)(包括它們)。但是,如果我們分配了超出這個范圍的紋理坐標,可能會得到一些特別的紋理效果。通過設置紋理尋址模式,我們就可以在紋理坐標超出范圍時進行控制,紋理尋址模式就是用來干這個的。
包裝(Wrapping)紋理尋址模式
“Wrapping”紋理尋址模式由D3DTEXTUREADDRESS枚舉類型的D3DTADDRESS_WRAP成員來確定,它使Direct3D在每一個整數(shù)結(jié)點(integer junction)對紋理進行重復。假設我們要創(chuàng)建一個正方形圖元,并將紋理坐標聲明為(0.0,0.0)、(0.0,3.0)、(3.0,3.0)和(3.0,0.0)。這時,如果我們設置了紋理尋址模式,就可以使紋理在U、V方向都重復三次。,如下圖所示:

這種紋理尋址模式的效果與“鏡像”模式比較相似,但在本質(zhì)上是不同的。
鏡像紋理尋址模式
“鏡像”紋理尋址模式由D3DTEXTUREADDRESS枚舉類型的D3DTADDRESS_MIRROR成員來確定,它使Direct3D在每個整數(shù)邊界處(integer boundary)對紋理進行鏡像處理。想在我們創(chuàng)建一個正方形圖元,為坐標為(0.0,0.0)、(0.0,3.0)、(3.0,3.0)和(3.0,0.0)。我們設置鏡像紋理尋址模式,紋理在U、V方向都重復了三次,并且每一行、每一列都與相鄰的行和列成鏡像關(guān)系。如下圖所示:

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

邊界顏色紋理尋址模式
“邊緣顏色”紋理尋址模式由D3DTEXTUREADDRESS枚舉類型的D3DTADDRESS_BORDER成員確定,它使Direct3D可以在紋理坐標超過范圍的地方使用一個任意的顏色,也就是邊界顏色。
下圖中展示了一個使用了紋理的圖元,它使用了紅色的邊界色:

一次鏡像尋址模式
這個模式由D3DTEXTUREADDRESS枚舉類型的D3DTADDRESS_MIRRORONCE成員確定,是從DirectX8才引入的新的紋理尋址模式,類似于鏡像模式于夾持模式的組合。紋理再-1.0到1.0之間做鏡像,而在該范圍之外做夾持。
-----------------------------------------
4,紋理包裝(Wrapping)
簡單來說,紋理Wrapping就是要改變Direct3D光柵使用紋理坐標對有紋理的多邊形進行光柵操作的基本方式。我們對一個多邊形進行光柵操作時,系統(tǒng)在每一個多邊形頂點的紋理坐標之間進行內(nèi)插運算,這樣來決定在多邊形的每個像素上所使用的紋理像素。通常,系統(tǒng)將紋理看作一個二維平面,在這個平面內(nèi)A、B兩點間的連線上進行內(nèi)插。如果點A的U、V坐標為(0.8, 0.3),點B為(0.1,.9),那么進行內(nèi)插的連線就如下圖所示:

注意,上圖中A、B兩點的最短連線穿過了紋理的中間部分。U、V紋理Wrapping的使用會影響Direct3D在U、V方向上對紋理坐標間最短連線的選取。現(xiàn)在我們假定0.0與1.0重合,那么通過定義,紋理Wrapping就會導致光柵在紋理坐標設置之間來選擇最短距離。我們可以認為一個方向上的紋理Wrapping就是讓系統(tǒng)認為將一個紋理包裹在了一個圓筒上,就象下圖中那樣:
上圖中我們在U方向上進行了Wrapping,它影響了系統(tǒng)對紋理坐標進行的插值操作。我們使用同樣的兩個點A和B,可以看到,它們之間最短的連線不再通過紋理的中間部分;它現(xiàn)在穿越了0.0和1.0所在的交界線。沿V方向的Wrapping與它相似,只不過紋理所包裹的圓筒橫躺在地上。U、V方向上同時進行Wrapping比較復雜,這時我們可以將紋理想象成一個園環(huán)面或者是面包圈的形狀。
再具體說明一下,就是說如果按照U方向來包裝就取U方向的最小距離線段,在該段上做插值;如果如果按照V方向來包裝就取V方向的最小距離線段,然后做插值。那么設置了按U&V方式可以將紋理想象成一個環(huán)形。
需要注意的是,在啟用紋理包裝之后將使[0,1]之外的紋理坐標成為無效值,所以紋理包裝不能于各種紋理尋址模式共用。
----------------------------------------------
5,紋理過濾和抗鋸齒(反走樣Anti-Aliasing)
紋理過濾和反走樣解決的是同一類問題,就是屏幕鋸齒的問題,不同的是文理過濾解決的是紋理映射過程中的鋸齒,而反走樣解決的是幾何體邊沿的鋸齒。
- MipMap:是由一系列紋理組成的分辨率分級的特殊紋理形式。
一個mipmap就是一系列的紋理,每一幅紋理都與前一幅是相同的圖樣,但是分辨率都要比前一幅有所降低。mipmap中的每一幅或者每一級圖象的高和寬都比前一級小二分之一。Mipmap并不一定必須是正方形。
高分辨率的mipmap圖象用于接近觀察者的物體。當物體逐漸遠離觀察者時,使用低分辨率的圖象。Mipmap可以提高場景渲染的質(zhì)量,但是它的內(nèi)存消耗卻很大。
Direct3D將mipmap描繪成一系列相互聯(lián)系的表面。高分辨率的紋理位于開始處,并與下一級紋理相互聯(lián)系。以此類推,紋理相互聯(lián)系,逐漸排列到分辨率最小的一級。
下面這套插圖顯示了這樣的一個例子。這套紋理是一個三維場景中一個集裝箱的標簽。當我們創(chuàng)建了一個mipmap時,分辨率最高的一幅紋理就是這一套紋理的第一個。這套mipmap中的每一個紋理寬高都是前一個紋理寬高的二分之一。這樣,最大分辨率的紋理是256x256,接下來的紋理就是128x128,最后一個紋理就是64x64。
我們有一個能看到這個標簽的最大距離。如果觀察者從遠處向標簽走近,那么場景中首先會顯示最小的一幅紋理,它的大小是64x64的。



當觀察者走進標簽時,我們就使用更高分辨率一幅紋理;當觀察者走到允許的最近距離時,我們使用分辨率最高的那幅紋理.
這是方法能夠模擬紋理的透視效果并能夠減少處理時的計算量。與將一幅紋理用于不同的分辨率相比,這種方法更加快速。
Direct3D能夠訪問mipmap中與我們想要輸出的分辨率最接近的那個紋理設置,并將像素映射到它的紋理像素空間中。如果最終圖象的分辨率在mipmap紋理的分辨率的中間,那么Direct3D會對兩幅紋理中的紋理像素進行檢查,并將它們的顏色值進行融合。
提供給CreateTexture()正確的參數(shù)就可以自動創(chuàng)建MipMap紋理。
- 紋理過濾方法:最近點采樣,線性紋理過濾,各項異性過濾,混合過濾
過濾是指通過給定的UV坐標從紋理貼圖中獲取圖素的一種方法。一張64*64的紋理映射到400*400象素的多邊形就會出現(xiàn)因放大而造成的鋸齒,這稱為放大問題;一張64*64的紋理映射到10*10象素的多邊形的時候,一個屏幕象素對應多個紋理圖素,就會因交替占有象素而出現(xiàn)抖動。那么為了解決這個問題,就要采用紋理過濾方法。在默認的顯卡設置中,紋理過濾的方法是由驅(qū)動程序控制的。
最近點采樣是最簡單的過濾方法,顧名思義,就是采用離象素最近的圖素作為顏色。將紋理坐標對齊到最接近的整數(shù),再將那個位于整數(shù)坐標的紋理圖素作為最終的顏色。這種方法在處理圖素邊界的時候會發(fā)生一些錯誤。
線性紋理過濾在Direct3D中采用的是雙線性紋理過濾,它計算相對于采樣點距離最近的4個圖素的平均值。采用如下形式進行設置:
m_pd3Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
m_pd3Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
三線性過濾:選擇兩張最接近的mipmap,將它們雙線性過濾為兩張理想大小的mipmap,然后根據(jù)理想的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);
各向異性過濾:雙線性過濾和三線性過濾的缺點是他們都使用正方形采樣區(qū)域來采樣圖素,如果紋理是側(cè)著朝向視點的化則會發(fā)生一種稱之為“各向異性”的失真效果。那么各向異性過濾則會把因為透視投影拉伸的幾何體大小映射回紋理空間中,使得紋理在投射時候被伸張,因此來獲得更佳的深度細節(jié)和精確顯示。使用各向異性過濾的代碼如下:
m_pd3Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
m_pd3Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC);
m_pd3Device->SetSamplerState(0,D3DSAMP_MAXD3DTEXF_ANISOTROOPY,16);
- 反走樣:現(xiàn)在反走樣已經(jīng)是DirectX中的一項默認特征。
全屏反走樣(FSAA):采用全屏多采樣對每個象素進行對此采樣,進行混合后進行輸出,通過這種方式來調(diào)整圖像中每條斜線周圍的亮度來隱藏騎上的鋸齒效果,它沿著這些邊沿產(chǎn)生局部模糊的效果。一種更為高級的多采樣成為“可屏蔽多采樣(maskable multisampling)”。
alpha混合不知道怎么搞到這一章來介紹,可能是為了利用這一個沒有程序的篇章把該介紹的基本知識介紹完吧。我也姑且寫到這里。
alpha混合的原理很簡單,就是利用混合因子把要繪制到幀緩存中的顏色和當前幀緩存中的顏色進行一個疊加,因此可以實現(xiàn)多次渲染,從而實現(xiàn)許多特效。對應的代碼像下面這種形式:
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ZERO);
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR);
原載:http://blog.sina.com.cn/u/40d00f17010001qe