WPF繪製深度不同顏色的3D模型填充圖和線框圖
摘要: 在機械測量過程中,測量的數據需要進行軟件處理。通常測量一個零件之後,需要重建零件的3D模型,便於觀察測量結果是否與所測工件一致。 重建的3D模型需要以填充圖和線框圖兩種方式切換顯示,其中填充圖的材質需要根 ...
在機械測量過程中,測量的數據需要進行軟件處理。通常測量一個零件之後,需要重建零件的3D模型,便於觀察測量結果是否與所測工件一致。 重建的3D模型需要以填充圖和線框圖兩種方式切換顯示,其中填充圖的材質需要根據不同深度進行着色,線框圖需要消隱(不能透視)。以圓柱爲例,如下圖: 由於WPF對DirectX進行了封裝,並構建出一套簡單的3D繪圖框架,因此我們可以快速的創建所需要的3D模型,便於像我這樣的對三維計算機圖形學不太瞭解的人進行開發。 關於WPF 3D繪圖的基礎,大家可以參考《Practical WPF Charts and Graphics》一書,裏面也講到一些3D顯示的計算機圖形學和數學基礎。 下面我們開始3D模型的構建。 在WPF中,我們可以按如下步驟進行操作: 1、創建一個Viewport3D對象來host 三維模型; 2、繼承ModelVisual3D或者ModelUIElement3D來定義3D對象; 3、指定3D場景中的光源,在WPF中光源也是一種ModelVisual3D; 4、創建一個相機來進行3D圖形到2D顯示器的映射。 根據工程中的經驗,我們考慮傳感器採集的數據是圓柱體工件的五個截面(實際可能更多或者更少),每個截面包含8192(或者更多)個點,並且是極座標格式數據。 這裏我們使用ModelVisual3D來定義三維物體。其中重要的是三角剖分和材質貼圖的部分。由於每一層數據點個數都是一致的,因此我們可以將圓柱體分成三個部分,上下底面和側面。參考《Practical WPF Charts and Graphics》,我們可以把圓柱的側面分成多個四邊形,每個四邊形分成兩個三角形,並將上下底面分成多個三角形(類似扇形)。 剖分方式大致如下圖: 由於數據點座標是極座標,每一層有不同的高度(即三維座標系中的Y),因此需要將極座標轉化爲三維座標系中的座標,即Point3D結構,座標系如下圖: 需要注意的是,我們繪製的3D模型是三個曲面構成,每個曲面沒有封閉,這樣看上去會在首尾相接處出現缺口,因此需要多加一些三角形將首尾進行縫合。未縫合的模型如下: 在三維模型創建結束之後,需要貼上材質,由於工程中需要體現出不同深度(即不同半徑 )的差別,需要使用漸變色進行呈現,類似Matlab中的效果 參考我轉載的一篇文章(http://blog.csdn.net/congduan/article/details/21092341),就可以得出基本思路:在計算模型的時候,根據不同的R值,生成一張RGB color的映射表,並將其作爲材質應用在3D模型上。 參考Codeproject上http://www.codeproject.com/KB/WPF/WPFChart3D.aspx這篇文章的源碼,其中的TextureMapping.cs文件便是進行材質顏色映射的類,可以根據需要將多種顏色改寫成2種顏色等等,做出適合自己的定製。當然,這個類使用了C#指針(unsafe關鍵字),需要在項目屬性生成一項中開啓不安全代碼支持。以下是我修改例子,做出的兩種顏色的漸變圖: 以下便是參考該文例子寫出的本文圓柱的代碼:
注意其中半徑都是歸一化之後才生成顏色值的。 最後將TextureMapping生成的材質貼到模型上。
====================================================================== 對於線框圖(WireFrame),WPF支持的不好,因爲WPF中沒有3D線段的類,好在微軟的人意識到了這一點,開發出開源的3D Tools for WPF(http://3dtools.codeplex.com/)作爲補充,其中就有ScreenSpaceLines3D類用於3D線段繪製。這樣前面的填充圖也可以加上輪廓了。 但是,問題又來了。繪製出的線框圖是下面這樣的: 由於沒有消隱,很多線段交叉重疊在一起,影響判斷。《Practical WPF Charts and Graphics》一文中的例子是這樣處理的,在前面填充圖的基礎上加上線框,但是填充的材質改成純白色,並將線框線條加粗。效果還是不錯的,如下: 但是我這樣試過之後,發現一些問題,偶爾線條會被填充白色的三角形遮擋住,爲了解決這個問題,我找到OpenGL的C#開源封裝庫,比如OpenTK和SharpGL,其中SharpGL中做如下處理之後會得到較好的效果:
效果: 可以SharpGL未能很好地利用GPU,將數據全部拷貝到內存中,導致內存暴漲,甚至有時候內存泄露。因此最後放棄了這個庫。而OpenTK並沒有WPF的控件,只能使用WindowsFormsHost來host WinForm的控件,不是很方便。 後來使用Helix 3D Toolkit,它將WPF和SharpDX進行了再次封裝,並提供了一些比較好的3D算法。並使用其中的MeshBuilder更方便地創建三角形和3D線段,最終出現本文開始的效果。 最後,重點提一下線框圖中的線段分佈的算法。 顯示線框圖的時候,會繪製一部分豎線,開始考慮的是均勻間隔繪製,但是豎線繪製多少,是一個需要仔細思考的問題。線段多了,損耗性能,線段少了,輪廓的還原度不會搞,尤其是一些凹槽和凸出的部分會因爲過於稀疏的線段無法顯示出來,如下圖的部分: 思考了很久,想到一種比較滿意的算法:計算每一層所有數據點的陡變程度,提取前100個(可以根據不同疏密需要的情況進行選取)陡變最大的點繪製豎線。 由於數據點是離散的,可以使用離散曲率刻畫點的陡變程度,離散曲率的計算公式如下:
|