WPF繪製深度不同顏色的3D模型填充圖和線框圖

WPF繪製深度不同顏色的3D模型填充圖和線框圖

2014-7-1 13:47| 發佈者: 牛途斬月| 查看: 166| 評論: 0

摘要: 在機械測量過程中,測量的數據需要進行軟件處理。通常測量一個零件之後,需要重建零件的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關鍵字),需要在項目屬性生成一項中開啓不安全代碼支持。以下是我修改例子,做出的兩種顏色的漸變圖:

以下便是參考該文例子寫出的本文圓柱的代碼:
  1. for (int i = 0; i < drawPointCount; i++)  
  2. {   
  3. for (int j = 0; j < PointCollectionList.Count; j++)  
  4. {  
  5. //從極座標構造笛卡爾座標系數據   
  6. points[i, j] = MathHelper.GetPosition(baseRadius +  
  7. ZoomContourValue * (PointCollectionList[j][i * interval].Y - fittedCircles[j].Radius) / (maxR - minR),  
  8. PointCollectionList[j][i * interval].X,  
  9. (j - halfPointCollectionCount) * h,  
  10. (Vector3D)Center);   
  11.   
  12. //根據表面半徑差值,生成RGB顏色紋理座標  
  13. double u = (PointCollectionList[j][i * interval].Y - minR) / (maxR - minR);  
  14. Color color = TextureMapping.PseudoColor(u);  
  15. Point mapPt = m_mapping.GetMappingPosition(color);  
  16. texcoords[i, j] = new Point(mapPt.X, mapPt.Y);  
  17. }  
  18. }  


注意其中半徑都是歸一化之後才生成顏色值的。
最後將TextureMapping生成的材質貼到模型上。
  1. //填充表面材質  
  2. surfaceModel = new GeometryModel3D(surfaceMeshBuilder.ToMesh(), m_mapping.m_material);  

======================================================================
對於線框圖(WireFrame),WPF支持的不好,因爲WPF中沒有3D線段的類,好在微軟的人意識到了這一點,開發出開源的3D Tools for WPF(http://3dtools.codeplex.com/)作爲補充,其中就有ScreenSpaceLines3D類用於3D線段繪製。這樣前面的填充圖也可以加上輪廓了。
但是,問題又來了。繪製出的線框圖是下面這樣的:

由於沒有消隱,很多線段交叉重疊在一起,影響判斷。《Practical WPF Charts and Graphics》一文中的例子是這樣處理的,在前面填充圖的基礎上加上線框,但是填充的材質改成純白色,並將線框線條加粗。效果還是不錯的,如下:

但是我這樣試過之後,發現一些問題,偶爾線條會被填充白色的三角形遮擋住,爲了解決這個問題,我找到OpenGL的C#開源封裝庫,比如OpenTK和SharpGL,其中SharpGL中做如下處理之後會得到較好的效果:
  1. //突出邊框,設置多邊形偏移  
  2. gl.Enable(OpenGL.GL_POLYGON_OFFSET_FILL);  
  3. gl.PolygonOffset(1.0f, 1.0f);  
  4. //開啓反走樣  
  5. gl.Enable(OpenGL.GL_BLEND);  
  6. gl.Enable(OpenGL.GL_LINE_SMOOTH);  
  7. gl.Enable(OpenGL.GL_POLYGON_SMOOTH);  
  8. gl.Hint(OpenGL.GL_POINT_SMOOTH_HINT, OpenGL.GL_NICEST); // Make round points, not square points  
  9. gl.Hint(OpenGL.GL_LINE_SMOOTH_HINT, OpenGL.GL_NICEST); // Antialias the lines  
  10. gl.BlendFunc(OpenGL.GL_SRC_ALPHA, OpenGL.GL_ONE_MINUS_SRC_ALPHA);  


效果:

可以SharpGL未能很好地利用GPU,將數據全部拷貝到內存中,導致內存暴漲,甚至有時候內存泄露。因此最後放棄了這個庫。而OpenTK並沒有WPF的控件,只能使用WindowsFormsHost來host WinForm的控件,不是很方便。
後來使用Helix 3D Toolkit,它將WPF和SharpDX進行了再次封裝,並提供了一些比較好的3D算法。並使用其中的MeshBuilder更方便地創建三角形和3D線段,最終出現本文開始的效果。

最後,重點提一下線框圖中的線段分佈的算法。
顯示線框圖的時候,會繪製一部分豎線,開始考慮的是均勻間隔繪製,但是豎線繪製多少,是一個需要仔細思考的問題。線段多了,損耗性能,線段少了,輪廓的還原度不會搞,尤其是一些凹槽和凸出的部分會因爲過於稀疏的線段無法顯示出來,如下圖的部分:

思考了很久,想到一種比較滿意的算法:計算每一層所有數據點的陡變程度,提取前100個(可以根據不同疏密需要的情況進行選取)陡變最大的點繪製豎線。
由於數據點是離散的,可以使用離散曲率刻畫點的陡變程度,離散曲率的計算公式如下:


參考論文《一種度量圖像像素陡變程度的方法》可以知道,這種連續曲線曲率直接離散化的結果並不是很好,並且該論文提出了一種更好的算法,具體算法大家可以去閱讀論文原文。公式如下:

有了這樣的評判標準,實現之後變成功將需要的輪廓比較完整地顯示了出來。由於數據點很多,計算公式也比較複雜,最好是放入後臺線程異步處理,避免UI線程阻塞。
最後,注意大量數據點會造成三角形過多(這裏會達到20W個左右),導致構建性能問題突出,最好在保證3D模型還原度高的情況下,進行稀疏處理,減少三角形數量。

發佈了2 篇原創文章 · 獲贊 40 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章