影像處理---深入ManagedDirectX9(1)(轉)

post0發表於2007-08-12
影像處理---深入ManagedDirectX9(1)(轉)[@more@]

  Device類是DirectX裡的所有繪圖操作所必須的。可以把這個類假想為真實的圖形卡。場景裡所有其他圖形物件都依賴於device。你的計算機裡可以有一個到幾個device,在Mnaged DirctX3D裡,你可以控制任意多個device。

  Device共有三個建構函式,現在我們只討論其中的一個,但我們會在後邊的內容裡討論其他的。先來看看具有如下函式簽名的建構函式

  public Device(int adapter,DeviceType deviceType,Control renderWindow,CreateFlags behaviorFlags, PresentParameters[] presentationParameters);

  (建構函式的第二種過載類似於上邊這個,但它接受來自非託管(或者非windows form)的視窗控制程式碼作為renderWindow。而只接受一個IntPtr引數的過載是非託管com組建指向Idirect3Ddevice9的介面。當你的程式碼需要和非託管的程式協作時則應用它)

  好了,這些引數是什麼意思,以及我們怎樣來使用呢?呵呵,引數adapter表示我們將要使用哪個物理圖形卡。計算機裡的所有圖形卡都有一個唯一的介面卡識別符號(通常是0到你的圖形卡數量-1),預設的顯示卡總是表示為0 的圖形卡。

  下一個引數,DeviceType,告訴了DirectX3D你要建立那種型別的device。這裡最常用的值就是DeviceType.Hardware,表示你將建立一個硬體裝置。另一個選項是DeviceType.Reference,這種裝置允許你使用“參考光柵器”(reference rasterizer),所有的效果由DirectX3D執行時來實現,以很慢、很慢、很慢的速度執行^_^。應該僅在除錯時或測試你的顯示卡所不支援的特性時使用這個選項。

  (注意參考光柵器只包含在DirectX SDK裡,so DirectX執行時是不能使用這個特性的。最後一個為DeviceType.Software的值允許使用使用者自定義的軟體光柵器(custom software rasterizer)在不確定是否有這樣一個光柵器存在時,忽略這個選項吧^_^。)

  rendrWindow表示把裝置繫結到的視窗。因為windows form控制元件類都包含了一個視窗控制程式碼(windows handle),所以很容易把一個確定的類作為渲染視窗。可以使用form、panel或其他任意的控制元件作為這個引數的值。但現在,我們只用form。

  下一個引數用來描述裝置建立之後的行為。大部分CreateFlags列舉的成員都能組合起來使用,使裝置具有多種行為。但有一些flag是相互排斥的,我們稍後討論。我們現在只使用SoftwareVertexProcessing標誌。這個標誌適合於所有定點處理都用CPU計算的情況。應此,這自然比所有點都用GPU處理要慢,因為我們不確定你的顯示卡是否支援所有特性。So,安全第一,假設你的CPU能完成現在的任務。

  最後一個引數,它表示你的裝置把資料呈現到顯示器的方式。Presentation Parameter類的外觀都可以由這個類來控制。我們過後再來深入討論它的建構函式,現在,我們只關心“Windowed”成員和“SwapEffect”成員。

  Windowed成員是一個布林型別的值,決定裝置是全屏還是視窗模式。

  SwapEffect成員用於控制快取交換的行為。如果選擇了SwapEffect.Flip,執行時會建立額外的後備緩衝(back buffer),並且在顯示時複製front buffer。SwapEffect.Copy與Flip相似,但要求你把後備緩衝設為1。我們將要選擇的SwaoEffect.Discard,如果緩衝沒有準備好被顯示,則會丟棄緩衝中的內容(which simply discards the contents of the buffer if it isn’t ready to be presented)。

  學了這麼多,現在來建立一個裝置吧。回到程式碼上來,首先為我們的程式將建立一個device物件:

  (程式碼略,參見DirectX sdk Tutorial 1: Create a Device)

  現在讓我們來重寫Paint()函式:

  protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)

  {

  device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);

  device.Present();

  }

  我們使用Clear()方法把視窗填充為實心的顏色。它的第一個引數指定了我們要填充的物件;在例子裡,我們填充的即是目標視窗。稍後再來討論ClearFlags列舉的其它成員。第二個引數是我們所要填充的顏色。其他的兩個引數先暫時忽略。在device被填充之後,我們必須更新顯示:Present方法會為我們完成這個任務。這個方法也有幾個過載的型別;上邊使用的方法會顯示device的整個區域。同樣稍後再討論。

  看到有些枯燥了嗎,好吧,現在我們來真正繪製一些圖形

  三維圖形世界裡最基本的圖形就是三角形。使用足夠的三角,我們可以呈現出任何東西,甚是是平滑的曲面。沒有什麼比畫一個簡單的三角和更好的了。為了使過程儘可能的簡單,我們先避開“world space”以及各種變換(當然,我們馬上就會提到他們),使用螢幕座標來繪製一個簡單的三角。再繪製我們迷人的三角前,我們必須做2件事。1,我們需要一些資料結構來儲存三角的資訊。2,我們告訴device來繪製它。

  很幸運,DirectX已經有這樣的一個資料結構來儲存三角了。Direct3D名稱空間裡叫做CustomVertex的類可以用來儲存大多數Direct3D中用到的“頂點格式”資料結構(vertex format)。

  一個頂點格式結構把資料儲存為一種DirectX3D認識並且可以使用的格式。我們將討論很多這種結構,但先讓我們來看看即將用來建立三角的TransformedColored結構。這個結構告訴DirectX3D執行時我們的三角不需要進行左邊變換(比如旋轉或移動),因為我們已經指定了使用螢幕座標系。它也包含了每一個點(頂點)的顏色的資訊。回到重寫的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)

  陣列裡的每一個元素表示三角的一個頂點,所以我們建立了3個元素。然後我們使用新建立的Vector4結構為每一個成員呼叫SetPositin方法。變換過的頂點座標包含了在螢幕上x和y的座標(相對於螢幕的(0,0)點而言),當然也包括z座標和rhw成員(reciprocal of homogenous w三維齊次座標)。先忽略後邊兩個引數.Vector4結構(注:Vector4其實就是(x,y,z,w)經過變換後成為(x/w,y/w,z/w))是儲存這種資訊最方便的方式。然後我們設定了點的顏色。注意,我們使用了標準顏色的ToArgb方法。DirectX3D假設所接受的顏色為32為的int。

  既然我們已經有了資料就可以告訴DirectX我們需要繪製這個三角形,並且繪製它。在重寫的OnPaint裡新增如下程式碼

  device.BeginScene();

  device.VertexFormat = CustomVertex.TransformedColored.Format;

  device. DrawUserPrimitives (PrimitiveType.TriangleList,1,verts); 注意和sdk中的示例有區別

  device.EndScene();

  好了,這幾行程式碼是什麼意思呢?其實很簡單。BefinScene方法告訴DirectX3D我們即將繪製一些東西,為繪製做好準備。現在我們已經告訴了DirectX3D要繪製一些東西,接下來就必須告訴它畫什麼。這就是VertexFormat屬性的作用。它決定了DirectX3D執行時使用哪種“確定的功能管道”(fixed function pipline)格式。在我們的例子裡使用變換過的,著色過的頂點管道。

  不用擔心你現在不明白確定的功能管道是什麼意思,我們會很快來討論它。

  DrawUserPrimitives函式是真正發生繪圖的地方。So,他的引數是什麼意思呢?第一個引數是我們要繪製的初等幾何體的型別。有很多種可用的型別,but now,我們只是畫一系列的三角形。所以選擇了PrimitiveType.TriangleList型別。第二個引數是我們要繪製的三角形的數量。對於一個三角形的集合來說,這個值應該是你的頂點數量除以3。我們只畫一個三角,所以設為1。最後一個引數則是DirectX3D用來繪圖的資料。最後一個EndSence方法通知DirectX3D我們不再繪圖了。你必須再每次呼叫BeginSence之後都呼叫這個方法。

  如果現在編譯執行程式的話,你會發現但移動或重置視窗大小之後,並不會更新顯示。原因是當我們需要重繪整個視窗時,Windows並不會每一次都計算視窗的收縮情況。因此,你只是移除了顯示過的資料,當並沒有刪除已經顯示的內容。很幸運,有個簡單的方法解決這個問題,我們可以告訴Windows視窗總是需要被整個的重繪。在OnPaint的最後加上一下程式碼:

  this.Invalidate();

  呵呵,現在再來試試看,哦,看起來我們破壞了程式!現在只能顯示一片空白了,並且我們的三角看起來還在不停的閃爍,尤其是當你調整視窗大小的時候。我們都幹了些什麼呢?原來“聰明”的Windows總是嘗試在Invalidate()方法後來繪製當前的視窗(即空白的這個視窗)。在我們的OnPaint方法之外還存在其他的繪製過程!能容易的透過改變視窗的“style”屬性來解決。在建構函式里加上如下程式碼

  this.SetStyle(ControlStyles.AllPaintingInWmPaint | ConstolStyles.Opaque, true);

  哦~,好了,終於erying works as expected。我們所做的就是告訴Windows一切繪圖過程都在OnPaint裡完成。

  (第一部分完,下一步分我們將開始真正的3D之旅,使我們的三角形三維化

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-951652/,如需轉載,請註明出處,否則將追究法律責任。

相關文章