2010-01-14 49 views
4

我有一個動態列表點,新點可以隨時添加。我想畫線以使用不同的顏色來連接它們。顏色是基於這些點的指數。這裏是代碼:使用GDI +使用不同顏色畫線的快速方法?

private List<Point> _points; 
    private static Pen pen1 = new Pen(Color.Red, 10); 
    private static Pen pen2 = new Pen(Color.Yellow, 10); 
    private static Pen pen3 = new Pen(Color.Blue, 10); 
    private static Pen pen4 = new Pen(Color.Green, 10); 

    private void Init() 
    { 
     // use fixed 80 for simpicity 
     _points = new List<Point>(80); 

     for (int i = 0; i < 80; i++) 
     { 
      _points.Add(new Point(30 + i * 10, 30)); 
     } 
    } 

    private void DrawLinesNormal(PaintEventArgs e) 
    { 
     for (int i = 0; i < _points.Count-1; i++) 
     { 
      if (i < 20) 
       e.Graphics.DrawLine(pen1, _points[i], _points[i + 1]); 
      else if (i < 40) 
       e.Graphics.DrawLine(pen2, _points[i], _points[i + 1]); 
      else if (i < 60) 
       e.Graphics.DrawLine(pen3, _points[i], _points[i + 1]); 
      else 
       e.Graphics.DrawLine(pen4, _points[i], _points[i + 1]); 
     } 
    } 

我發現這種方法是不夠快,當我有新的點高速進來。有什麼辦法可以讓它更快嗎?我做了一些研究,有人說使用GraphicsPath可能會更快,但是如何?

[更新]我收集了一些可能的優化:

  1. 使用GrahpicsPath,Original Question
  2. 更改圖形質量(如SmoothingMode/PixelOffsetMode ......),也叫setClip的指定只在必要地區渲染。

回答

1

這與使用System.Drawing時一樣快。使用Graphics.DrawLines()可能會看到一些收穫,但您需要以不同方式格式化數據,以便利用同一支筆一次繪製一堆線。我嚴重懷疑GraphicsPath會更快。

提高速度的一個可靠方法是降低輸出質量。設置Graphics.InterpolationModeInterpolationMode.LowGraphics.CompositingQualityCompositingQuality.HighSpeedGraphics.SmoothingModeSmoothingMode.HighSpeedGraphics.PixelOffsetModePixelOffsetMode.HighSpeedGraphics.CompositingModeCompositingMode.SourceCopy

我記得一次速度測試,有人將圖形與P/Invoke比較成GDI例程,並且對於更快的P/Invoke速度感到非常驚訝。你可能會檢查出來。我會看看我是否可以找到這種比較... 顯然這是爲Compact Framework,所以它可能不適用於PC。

另一種方式是使用Direct2D,如果你有合適的硬件,它可以比GDI更快。

5

如果不損失質量或改變爲更快的渲染器(GDI,OpenGL,DirectX),您將無法從該代碼中擠出更多的速度。但是GDI通常會快很多(可能是2倍),並且DirectX/OpenGL可以更快(可能是10倍),具體取決於您繪製的內容。

使用Path的想法是將許多(在您的示例中爲20行)批量轉換爲單個方法調用,而不是調用DrawLine 20次。如果您可以將傳入數據安排到繪圖例程的正確列表格式中,這將只對您有益。否則,您將不得不將這些點複製到正確的數據結構中,並且這會浪費您通過批處理路徑獲得的大量時間。在DrawPath的情況下,您可能必須從點數組中創建一個GraphicsPath,這可能不會節省時間。但是如果你必須不止一次地繪製相同的路徑,你可以緩存它,然後你可以看到一個淨效益。

如果將新點添加到列表中,但舊點不會被刪除(即,您總是隻是在顯示屏上添加新行),那麼您將能夠使用離屏位圖來存儲到目前爲止呈現的行。這樣,每次添加一個點時,都會繪製一個一行,而不是每次繪製所有80行。

這一切都取決於你想要做什麼。

+0

緩存舊點是一個好主意,但是,我可以簡單地更改已繪製線的顏色嗎?如果不是的話,我仍然必須每次繪製所有80行。 – 2010-01-14 08:18:29

+0

如果您的線條顏色少於256線,那麼您可以在8bpp位圖上使用調色板循環(因此您可以用獨特的顏色繪製每條線,然後只更新調色板以重新顯示顏色變化的線)。 – 2010-01-14 13:04:42

+0

或者,您可能只能重新渲染每幀中改變顏色的線條。請注意,這將導致他們透支所有其他線路,因此您可能會在它們重疊的地方出現不需要的「深度」故障(錯誤的線路出現在「前面」) - 但是您可能能夠避開它。如果您使用抗鋸齒渲染線條,它也可能會生成奇怪的顏色,因爲每條線將與其後面的顏色(包括同一線條的舊顏色)進行混合。但你可以嘗試一下,看看你對結果是否滿意...... – 2010-01-14 13:05:28

0

你可能想看看畫筆對象,這是真的,你就不會接近實時的性能得到了GDI +程序,但你可以很容易,只要保持一個體面的FPS作爲對象的幾何形狀和數量保持在合理範圍內。至於畫線,我不明白爲什麼不。

但是,如果你達到了你認爲最佳的點,那就是繪製線..你應該考慮一個不同的圖形堆棧,如果你喜歡.NET,但是在OpenGL等非託管API方面有問題和DirectX,使用WPF或Silverlight,它非常強大。

無論如何,您可以嘗試設置System.Drawing.Drawing2D.GraphicsPath,然後使用System.Drawing.Drawing2D.PathGradientBrush以這種方式應用顏色。這是一個單一的緩衝平局,如果你不能獲得足夠的表現。您必須完全採用GDI以外的其他方法+

+0

我不認爲你可以使用Brush來「填充」一行 – 2010-01-14 20:05:55

0

根本不是GDI(+),但解決此問題的完全不同的方法可能是使用一塊內存,將您的線條繪製到那裏,將其轉換到一個Bitmap對象來即時繪製需要顯示線條的位置。

當然,這取決於在快速的方式極端中選擇的內存中表示給定顏色的

  • 畫線和
  • 將其轉換成該Bitmap顯現。

不是在.NET Framework中,我想,但也許在第三方庫? Silverlight中沒有類似這樣的東西的bitmap writer? (還沒有進入Silverlight我自己,那麼多...)

至少它可能是一個開箱即用的方法來處理這個問題。希望能幫助到你。

+0

在.NET 2.0中沒有任何東西可以與GDI +很好地協作(你可以做到,但不會特別快)。但是,WPF或Silverlight,取決於您想要使用桌面還是Web方法,都可以。一個可寫的位圖http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx – 2010-01-14 07:48:14

+0

是不是我說的,約翰? ;-) – peSHIr 2010-01-14 08:08:15

+0

我可以使用雙緩衝區來繪製一個離屏圖像,然後繪製到圖形? – 2010-01-14 08:24:53

2

並不能真正幫助提高性能,但我把筆還到一個列表,並以這種方式編寫所有這行:

int ratio = _points.Count/_pens.Count; 

for (int i = 0; i < _points.Count - 1; i++) 
{ 
    e.Graphics.DrawLine(_pens[i/ratio], _points[i], _points[i + 1]); 
} 
0

我認爲你必須處理筆對象和電子商務。繪圖後的圖形對象。 還有一件事情,如果你在onPaint()裏面寫你的drawLine代碼會更好。

just override onPaint() method it support better drawing and fast too. 
+0

是的,我必須處理這些筆,但此代碼僅用於演示目的,所以我沒有寫。 - 我不認爲我需要處理e.Graphics對象,我沒有創建它,爲什麼我需要處理它? - 你能解釋爲什麼重寫OnPaint會更快嗎?你的意思是調用Paint事件的開銷? – 2010-01-15 19:38:11

1

太晚了,但可能有人仍然需要解決方案。

我已經創建,有着相近(但不是全/等於)GDI +語法,這在OpenTK經營的小型圖書館GLGDI +:http://code.google.com/p/glgdiplus/

我不知道有關的穩定性,它通過DrawString一些問題(有問題來自OpenTK的TextPrint)。但是如果你的實用程序需要性能提升(比如我的情況下的關卡編輯器),它可以是解決方案。