?? 9-1.txt
字號:
Device類是DirectX里的所有繪圖操作所必須的。可以把這個類假想為真實的圖形卡。場景里所有其他圖形對象都依賴于device。你的計算機里可以有一個到幾個device,在Mnaged DirctX3D里,你可以控制任意多個device。
Device共有三個構(gòu)造函數(shù),現(xiàn)在我們只討論其中的一個,但我們會在后邊的內(nèi)容里討論其他的。先來看看具有如下函數(shù)簽名的構(gòu)造函數(shù)
public Device(int adapter,DeviceType deviceType,Control renderWindow,CreateFlags behaviorFlags, PresentParameters[] presentationParameters);
(構(gòu)造函數(shù)的第二種重載類似于上邊這個,但它接受來自非托管(或者非windows form)的窗口句柄作為renderWindow。而只接受一個IntPtr參數(shù)的重載是非托管com組建指向Idirect3Ddevice9的接口。當(dāng)你的代碼需要和非托管的程序協(xié)作時則應(yīng)用它)
好了,這些參數(shù)是什么意思,以及我們怎樣來使用呢?呵呵,參數(shù)adapter表示我們將要使用哪個物理圖形卡。計算機里的所有圖形卡都有一個唯一的適配器標(biāo)識符(通常是0到你的圖形卡數(shù)量-1),默認(rèn)的顯卡總是表示為0 的圖形卡。
下一個參數(shù),DeviceType,告訴了DirectX3D你要創(chuàng)建那種類型的device。這里最常用的值就是DeviceType.Hardware,表示你將創(chuàng)建一個硬件設(shè)備。另一個選項是DeviceType.Reference,這種設(shè)備允許你使用“參考光柵器”(reference rasterizer),所有的效果由DirectX3D運行時來實現(xiàn),以很慢、很慢、很慢的速度運行^_^。應(yīng)該僅在調(diào)試時或測試你的顯卡所不支持的特性時使用這個選項。
(注意參考光柵器只包含在DirectX SDK里,so DirectX運行時是不能使用這個特性的。最后一個為DeviceType.Software的值允許使用用戶自定義的軟件光柵器(custom software rasterizer)在不確定是否有這樣一個光柵器存在時,忽略這個選項吧^_^。)
rendrWindow表示把設(shè)備綁定到的窗口。因為windows form控件類都包含了一個窗口句柄(windows handle),所以很容易把一個確定的類作為渲染窗口。可以使用form、panel或其他任意的控件作為這個參數(shù)的值。但現(xiàn)在,我們只用form。
下一個參數(shù)用來描述設(shè)備創(chuàng)建之后的行為。大部分CreateFlags枚舉的成員都能組合起來使用,使設(shè)備具有多種行為。但有一些flag是相互排斥的,我們稍后討論。我們現(xiàn)在只使用SoftwareVertexProcessing標(biāo)志。這個標(biāo)志適合于所有定點處理都用CPU計算的情況。應(yīng)此,這自然比所有點都用GPU處理要慢,因為我們不確定你的顯卡是否支持所有特性。So,安全第一,假設(shè)你的CPU能完成現(xiàn)在的任務(wù)。
最后一個參數(shù),它表示你的設(shè)備把數(shù)據(jù)呈現(xiàn)到顯示器的方式。Presentation Parameter類的外觀都可以由這個類來控制。我們過后再來深入討論它的構(gòu)造函數(shù),現(xiàn)在,我們只關(guān)心“Windowed”成員和“SwapEffect”成員。
Windowed成員是一個布爾類型的值,決定設(shè)備是全屏還是窗口模式。
SwapEffect成員用于控制緩存交換的行為。如果選擇了SwapEffect.Flip,運行時會創(chuàng)建額外的后備緩沖(back buffer),并且在顯示時拷貝front buffer。SwapEffect.Copy與Flip相似,但要求你把后備緩沖設(shè)為1。我們將要選擇的SwaoEffect.Discard,如果緩沖沒有準(zhǔn)備好被顯示,則會丟棄緩沖中的內(nèi)容(which simply discards the contents of the buffer if it isn’t ready to be presented)。
學(xué)了這么多,現(xiàn)在來創(chuàng)建一個設(shè)備吧。回到代碼上來,首先為我們的程序?qū)?chuàng)建一個device對象:
(代碼略,參見DirectX sdk Tutorial 1: Create a Device)
現(xiàn)在讓我們來重寫Paint()函數(shù):
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);
device.Present();
}
我們使用Clear()方法把窗口填充為實心的顏色。它的第一個參數(shù)指定了我們要填充的對象;在例子里,我們填充的即是目標(biāo)窗口。稍后再來討論ClearFlags枚舉的其它成員。第二個參數(shù)是我們所要填充的顏色。其他的兩個參數(shù)先暫時忽略。在device被填充之后,我們必須更新顯示:Present方法會為我們完成這個任務(wù)。這個方法也有幾個重載的類型;上邊使用的方法會顯示device的整個區(qū)域。同樣稍后再討論。
看到有些枯燥了嗎,好吧,現(xiàn)在我們來真正繪制一些圖形
三維圖形世界里最基本的圖形就是三角形。使用足夠的三角,我們可以呈現(xiàn)出任何東西,甚是是平滑的曲面。沒有什么比畫一個簡單的三角和更好的了。為了使過程盡可能的簡單,我們先避開“world space”以及各種變換(當(dāng)然,我們馬上就會提到他們),使用屏幕坐標(biāo)來繪制一個簡單的三角。再繪制我們迷人的三角前,我們必須做2件事。1,我們需要一些數(shù)據(jù)結(jié)構(gòu)來保存三角的信息。2,我們告訴device來繪制它。
很幸運,DirectX已經(jīng)有這樣的一個數(shù)據(jù)結(jié)構(gòu)來保存三角了。Direct3D名稱空間里叫做CustomVertex的類可以用來儲存大多數(shù)Direct3D中用到的“頂點格式”數(shù)據(jù)結(jié)構(gòu)(vertex format)。
一個頂點格式結(jié)構(gòu)把數(shù)據(jù)保存為一種DirectX3D認(rèn)識并且可以使用的格式。我們將討論很多這種結(jié)構(gòu),但先讓我們來看看即將用來創(chuàng)建三角的TransformedColored結(jié)構(gòu)。這個結(jié)構(gòu)告訴DirectX3D運行時我們的三角不需要進行左邊變換(比如旋轉(zhuǎn)或移動),因為我們已經(jīng)指定了使用屏幕坐標(biāo)系。它也包含了每一個點(頂點)的顏色的信息。回到重寫的OnPaint方法添加如下代碼:
CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[3];
Verts[0].SetPosition(new Vector4(this.Width/2.0f,50.0f,0.5f,1.0f);
Verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
Verts[1]`````````
Verts[2]`````````
(參見DirectX sdk Tutorial 2: Rendering Vertices)
數(shù)組里的每一個元素表示三角的一個頂點,所以我們創(chuàng)建了3個元素。然后我們使用新創(chuàng)建的Vector4結(jié)構(gòu)為每一個成員調(diào)用SetPositin方法。變換過的頂點坐標(biāo)包含了在屏幕上x和y的坐標(biāo)(相對于屏幕的(0,0)點而言),當(dāng)然也包括z坐標(biāo)和rhw成員(reciprocal of homogenous w三維齊次坐標(biāo))。先忽略后邊兩個參數(shù).Vector4結(jié)構(gòu)(注:Vector4其實就是(x,y,z,w)經(jīng)過變換后成為(x/w,y/w,z/w))是保存這種信息最方便的方式。然后我們設(shè)置了點的顏色。注意,我們使用了標(biāo)準(zhǔn)顏色的ToArgb方法。DirectX3D假設(shè)所接受的顏色為32為的int。
既然我們已經(jīng)有了數(shù)據(jù)就可以告訴DirectX我們需要繪制這個三角形,并且繪制它。在重寫的OnPaint里添加如下代碼
device.BeginScene();
device.VertexFormat = CustomVertex.TransformedColored.Format;
device. DrawUserPrimitives (PrimitiveType.TriangleList,1,verts); 注意和sdk中的示例有區(qū)別
device.EndScene();
好了,這幾行代碼是什么意思呢?其實很簡單。BefinScene方法告訴DirectX3D我們即將繪制一些東西,為繪制做好準(zhǔn)備。現(xiàn)在我們已經(jīng)告訴了DirectX3D要繪制一些東西,接下來就必須告訴它畫什么。這就是VertexFormat屬性的作用。它決定了DirectX3D運行時使用哪種“確定的功能管道”(fixed function pipline)格式。在我們的例子里使用變換過的,著色過的頂點管道。
不用擔(dān)心你現(xiàn)在不明白確定的功能管道是什么意思,我們會很快來討論它。
DrawUserPrimitives函數(shù)是真正發(fā)生繪圖的地方。So,他的參數(shù)是什么意思呢?第一個參數(shù)是我們要繪制的初等幾何體的類型。有很多種可用的類型,but now,我們只是畫一系列的三角形。所以選擇了PrimitiveType.TriangleList類型。第二個參數(shù)是我們要繪制的三角形的數(shù)量。對于一個三角形的集合來說,這個值應(yīng)該是你的頂點數(shù)量除以3。我們只畫一個三角,所以設(shè)為1。最后一個參數(shù)則是DirectX3D用來繪圖的數(shù)據(jù)。最后一個EndSence方法通知DirectX3D我們不再繪圖了。你必須再每次調(diào)用BeginSence之后都調(diào)用這個方法。
如果現(xiàn)在編譯運行程序的話,你會發(fā)現(xiàn)但移動或重置窗口大小之后,并不會更新顯示。原因是當(dāng)我們需要重繪整個窗口時,Windows并不會每一次都計算窗口的收縮情況。因此,你只是移除了顯示過的數(shù)據(jù),當(dāng)并沒有刪除已經(jīng)顯示的內(nèi)容。很幸運,有個簡單的方法解決這個問題,我們可以告訴Windows窗口總是需要被整個的重繪。在OnPaint的最后加上一下代碼:
this.Invalidate();
呵呵,現(xiàn)在再來試試看,哦,看起來我們破壞了程序!現(xiàn)在只能顯示一片空白了,并且我們的三角看起來還在不停的閃爍,尤其是當(dāng)你調(diào)整窗口大小的時候。我們都干了些什么呢?原來“聰明”的Windows總是嘗試在Invalidate()方法后來繪制當(dāng)前的窗口(即空白的這個窗口)。在我們的OnPaint方法之外還存在其他的繪制過程!能容易的通過改變窗口的“style”屬性來解決。在構(gòu)造函數(shù)里加上如下代碼
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ConstolStyles.Opaque, true);
哦~,好了,終于erying works as expected。我們所做的就是告訴Windows一切繪圖過程都在OnPaint里完成。
(第一部分完,下一步分我們將開始真正的3D之旅,使我們的三角形三維化)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -