DirectX 9.0c遊戲開發手記之“龍書”第二版學習筆記之9: Chap11: Texturing

        這一章講的是紋理,也是Direct3D中必不可少的一個技術:你見過那種所有物體基本都是單色的遊戲嗎?

        以前我在這裏一直不明白光照和紋理的關係。更具體地說,是在啓用光照和材質之後,模型本身已經有了顏色,那麼再用紋理給模型增添顏色,這幾種顏色的關係是怎麼樣的呢?它們如何共存呢?

        以前看非shader方法(就是固定管道渲染方法)的時候老是搞不懂,現在用shader方法全明白了,因爲我可以看見實現的細節了!事實上,是這樣的:

        ambient color一般設爲灰度光,然後在VertexShader中,與根據光照和材質得到的diffuse color相加得到的結果作爲新的diffuse color,接着在Pixel Shader中,這個新的diffuse color會與材質的顏色進行modulate運算,得到一個調色後的效果,作爲最後的diffuse color。而specular color一直是單獨處理的,最後在Pixel Shader中與上面提到的最後的diffuse color做加法,從而得到最終的顏色。

 

        這一章的內容並不簡單,講了很多比較高端的知識。事實上,紋理是Direct3D中比較難的部分,以至於本書的第III部分還會有兩章內容來講述紋理映射的高級技術。

        這一章最令人納悶的恐怕就是第4節Mipmaps了,不過幸好,在我們的這些簡單程序示例中,並不需要太關注這一點。

 

        下面開始講習題吧!

 

習題1部分:

===============================================================================

        這道題很簡單,就是讓我們畫一個金字塔形的物體,然後在它的每個面上貼上板條箱的紋理。具體寫起來有點麻煩,但是是純體力活,沒什麼技術含量。

        本來我打算在每個面上貼上不同的紋理的,但是我發現沒辦法很方便地實現這一點,因爲這表示你必須將每個面作爲一個單獨的物體進行繪製,而這顯然很麻煩;當然你也可以將需要的幾種紋理拼湊在一起形成一張大的紋理圖,然後在填充頂點數據的時候注意一下就好了;不過這樣還是很麻煩。咳!看起來還是有3D建模軟件比較好啊!

不管怎麼說,這個程序做出來了,下面是運行時截圖:



        然後是程序的代碼:

習題1答案地址

 

===============================================================================

 


習題2部分:

===============================================================================

        這道題讓我們在SDK文檔中查找D3DXCreateTextureFromFileEx函數的用法。這道題想必大家都會做,所以俺就略過了。

        不過值得一提的是,這個函數使用起來很複雜,除非有特殊需要,或者你已經很熟練了,否則還是使用簡單的D3DXCreateTextureFromFile函數吧!

===============================================================================

 

 

 

習題3-5部分:

===============================================================================

        習題3、4和5 都是針對TiledGround demo 的,所以我就把它們放在一起做了,結果成了一個比較大、但是十分給力的程序!

        爲了好玩,我讓程序具有運行時改變MaxAnisotropy 值、texScale 值以及address mode 的功能。MaxAnisotropy 的值要改變很簡單,把它的取值作爲一個effect parameter傳遞進.fx 文件中就行了。至於 texScale 的值,其實類似;不過值得注意的是,我把它進行了不小的變動,就是從texScale 變成了texTiledTimes,也就是在u(或者也可以說是v)方向上tile 的次數。這樣,當texTiledTimes=1.0 的時候,紋理沒有進行重複;而當texTiledTimes =10.0 時,地面被tile了10×10=100次。

        至於address mode,這個稍微難辦一些,因爲你不應該把它當作數字來處理,而是當成一個指標,然後利用switch語句(或者if/else語句)進行匹配。注意到我定義了3個sampler。這是因爲在.fx文件中,只有在vertex shader和pixel shader中纔可以出現if/else這樣的高級語法,其他地方,比如說sampler內部,甚至是“全局空間”,都不可以出現這樣的語句。在在某種程度上來說是很令人鬱悶的。

        最後值得一提的是我用來改變texTiledTimes(還有addressmode)的方法。我設定是按下Q鍵,則會增大texTiledTimes;而按下E鍵,則會減小texTiledTimes。我本來覺得這個很簡單,每次增大或減小1就行了。然而我錯了:事實上,我嘗試了之後,發現不管你按得多麼快,它增加或減少的值都會遠遠高於1!後來我整明白了:由於幀率比較高,所以在你覺得你只是按下一瞬間的時候,那個updateScene 程序可能已經運行了10次,從而會讓texTiledTimes 變動10個單位!既然如此,那麼別讓它每次變動1個單位,讓它變動dt 就是啦!這個想法看上去很誘人,不過我嘗試了之後,又發現了更奇怪的問題,讓我不知所措。大家可以試試。總之,這個問題讓我很苦惱。不過昨天,我終於想到了解決辦法了!

        我的解決辦法就是設定一個輔助變量,一個static float 類型的dtexTiledTimes,它表示你想要對texTiledTimes 進行的改變。它在每次調用updateScene 函數時只會變動dt,這樣當updateScene 函數累計運行1秒鐘之後,dtexTiledTimes 纔會變動1,而這時候我們就對texTiledTimes 進行相應的增減操作,再讓dtexTiledTimes 歸零就行了!哦也!我是不是很聰明呢?

        不過我覺得最好的方法就是產生一個用戶界面,在這裏可以通過直接輸入或者下拉菜單的形式進行數字的輸入。不過這個實現起來有點太麻煩了,而且我暫時也不會。

 

        此外有一個神奇的問題:當keyDown的參數位四個方向鍵(DIK_UPDIK_DOWNDIK_LEFTDIK_RIGHT)時,編譯的時候會發出警告,然後雖然有時候仍然可以正常運行,但是有時候按鍵就不靈了。這讓我百思不得其解:究竟是什麼原因使得這四個鍵如此特殊呢?

 

        好了,來欣賞一下運行時的截圖吧!

        第3題的效果:





        第4題的效果:





        第5題的效果:




        下面是第3-5題的答案下載地址:

第3-5題答案下載地址

 

===============================================================================

 

 

 

習題6部分:

===============================================================================

        這道題讓我們來進行紋理的混合。其實跟書上多重紋理那一節差不多,但是不同的是,這裏只有一張color texture。

        所以具體實現上就有一些區別啦。我是這樣做的,覺得這也應該是作者的本意:那張flarealpha 的圖上每個像素的灰度代表的是flare這張圖上相應像素的權重,也就是說,如果flarealpha 上(1/4, 1/4) 位置處的顏色爲(122, 122, 122),那麼在最終得到的混合紋理上,(1/4, 1/4) 處的顏色值爲flare 這張圖上(1/4, 1/4) 處的顏色值的(122+122+122) / (255+255+255)。由於flarealpha 是一張黑白圖,所以那個權重也可以這樣計算:122/255。

        不過在具體計算的時候,需要注意一點:在vertex shader和pixel shader中,顏色是D3DXCOLOR類型的,也就是說顏色的每個成分值是0.0到1.0之間的浮點數!所以如果B(i, j) 是flarealpha 上位於(i, j) 處的D3DXCOLOR 類型的顏色,那麼權重應該這樣計算:

(B.r + B.g + B.b)/3.0

        或者,因爲是黑白圖,所以直接用B.r 的值就行了!

 

        下面是運行時的一個截圖:



        奉上答案下載地址:

習題6下載地址

 

===============================================================================

 

 

 

習題7-8部分:

===============================================================================

        這兩題讓我們分別利用球形紋理和柱狀紋理來給茶壺和圓錐貼上紋理圖。這個很簡單,按照書上的來做就行了。

        值得注意的是,書上提過在計算球形紋理座標的時候,在兩極位置會出現偏差(distortion),但是並沒有對這種偏差進行處理。我爲了圖省事,也沒有進行處理,所以在運行的時候,你們可以看見兩極位置的圖案有點怪怪的。

 

        運行時截圖:




        答案下載地址:

習題7答案下載地址

 

習題8答案下載地址

 

===============================================================================




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