2011-06-02 48 views
2

我正在尋找一種方法來提高我正在執行的某些繪圖的性能。目前它是我繪製的一個32x32的網格。使用以下代碼繪製到繪圖上下文在wpf中提高繪製平鋪位圖的性能

for (int x = startX; x < endX; x++) 
     { 
      for (int y = startY; y < endY; y++) 
      { 
       dg.Children.Add(
        new ImageDrawing(_mapTiles[GameWorldObject.GameMap[x, y].GraphicsTile.TileStartPoint], 
         new Rect(CountX * 8, CountY * 8, 8, 8) 
         )); 

       dg.Children.Add(
        new GeometryDrawing(
         null, 
         new Pen(
          new SolidColorBrush(
           Color.FromRgb(255, 0, 20)), .3), 
           new RectangleGeometry(
            new Rect(CountX * 8, CountY * 8, 8, 8) 
           ) 
          ) 
         ); 

       CountY++; 
      } 
      CountY = 0; 
      CountX++; 
     } 

     dc.DrawDrawing(dg); 

我正在繪製的圖像是一個CachedBitmap。即使使用CachedBitmap,每次我需要重畫Canvas時,仍然有大約半秒的延遲。

不確定是否有更高性能的方式來處理繪製到這個網格。最終我想擴大控制功能作爲一個小地圖,所以我需要牢記這一點。

此外,我以前試圖直接繪製每個位圖到繪圖上下文,但似乎有點慢。

+0

對於32x32網格,我發現你的方法很快,我可以使用WriteableBitmap發佈一個解決方案,該方法適用於像發佈的代碼中的8px方格那樣的小塊。 GameWorldObject.GameMap [x,y] .GraphicsTile.TileStartPoint'的代碼只是一個簡單的訪問嗎?它是一個32x32網格,8px大小的瓷磚表現緩慢? – Kris 2011-06-02 17:17:52

+0

_maptiles是一個包含所有可能位圖的字典。它是一個32x32的網格,我從原來的尺寸縮小了。瓷磚實際上是64x64。我想知道縮小單個圖像後是否會更快,而不是每個圖像縮小 – 2011-06-03 21:42:22

回答

1

我畫前加入DrawingGroup.Freeze(),它似乎幫助的表現。

0

如果它大部分是靜態的小地圖,請將其繪製到圖像中並繪製該圖像。或者你可以做一個大的圖像,在其中繪製整個地圖,並繪製當前可見部分。

編輯:也許this blog post值得一檢查,無論你是用軟件或硬件加速繪製它。

+0

這裏的問題是,這是一個編輯器,並且隨着事物的編輯,小地圖可能會改變。如果地圖不那麼大,那麼這將是一個可接受的解決方案。但是,地圖太大,無法繪製靜態圖像,只要有變化就更新。 – 2011-06-02 16:08:28

0

下面是一個使用WriteableBitmap的示例,其性能主要與整個地圖的大小有關,而您的原始方法更多地依賴於tile的數量。你可以改變它在瓷磚之間有一個alpha混合的邊界,但是在它們之間留下一個空隙會更容易和更高效。你不需要隨機化代碼的代碼,但你應該有一些髒標誌,所以你只能在位圖改變時重新繪製位圖。

你可能也想看看我的答案和其他question。這就是說你沒有那麼多的項目,32x32的使用你的方法對我來說並不慢。

<local:Map x:Name="map" /> 
<RepeatButton Click="Button_Click" Content="Change" /> 


private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    map.seed++; 
    map.InvalidateVisual(); 
} 


public class Map : FrameworkElement 
{ 
    private int[][] _mapTiles; 

    public Map() 
    { 
     _mapTiles = Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures", "*.jpg").Select(x => 
     { 
      var b = new BitmapImage(new Uri(x)); 
      var transform = new TransformedBitmap(b, new ScaleTransform((1.0/b.PixelWidth)*tileSize,(1.0/b.PixelHeight)*tileSize)); 
      var conv = new FormatConvertedBitmap(transform, PixelFormats.Pbgra32, null, 0); 
      int[] data = new int[tileSize * tileSize]; 
      conv.CopyPixels(data, tileSize * 4, 0); 
      return data; 
     }).ToArray(); 

     bmp = new WriteableBitmap(w * tileSize, h * tileSize, 96, 96, PixelFormats.Pbgra32, null); 
     destData = new int[bmp.PixelWidth * bmp.PixelHeight]; 
    } 

    const int w = 64, h = 64, tileSize = 8; 
    public int seed = 72141; 
    private int oldSeed = -1; 
    private WriteableBitmap bmp; 
    int[] destData; 

    protected override void OnRender(DrawingContext dc) 
    { 
     if(seed != oldSeed) 
     { 
      oldSeed = seed; 
      int startX = 0, endX = w; 
      int startY = 0, endY = h; 
      Random rnd = new Random(seed); 

      for(int x = startX; x < endX; x++) 
      { 
       for(int y = startY; y < endY; y++) 
       { 
        var tile = _mapTiles[rnd.Next(_mapTiles.Length)]; 
        var rect = new Int32Rect(x * tileSize, y * tileSize, tileSize, tileSize); 
        for(int sourceY = 0; sourceY < tileSize; sourceY++) 
        { 
         int destY = ((rect.Y + sourceY) * (w * tileSize)) + rect.X; 
         Array.Copy(tile, sourceY * tileSize, destData, destY, tileSize); 
        } 
       } 
      } 

      bmp.WritePixels(new Int32Rect(0, 0, w * tileSize, h * tileSize), destData, w * tileSize * 4, 0); 
     } 

     dc.DrawImage(bmp,new Rect(0,0,w*tileSize,h*tileSize)); 
    } 
} 
+0

是的,這可能不起作用。總體地圖只是很大。這就是我不得不平鋪地圖的原因。 – 2011-06-04 14:43:01

+0

對於200 x 200像素,每個8像素的網格,需要35毫秒的時間。使用64像素的8像素,它應該足夠快。您可以運行我發佈的代碼而不必更改它,以瞭解它如何爲您執行。 – Kris 2011-06-04 15:57:31

+0

嘗試更多沿着50,000x50,000瓷磚的行列,看看它的表現如何。這就是我的意思是有太多的瓷磚。你的位圖會碰到內存限制牆,而且第一次渲染會非常慢。這種方法的一些混合方法可能會起作用,但它會很慢並且很複雜。 – 2011-06-05 14:51:15