2013-02-11 12 views
5

questa è la mia prima domanda, tuttavia sono un lurker da molto tempo. Lo dividerò in due parti, una parte che spiega cosa sto facendo e perché penso che questa sia la strada da seguire, la seconda è la vera domanda che non riesco a risolvere da sola.Miglioramento del rendering delle prestazioni DrawingContext Geometria (poligoni e polilinee)

Cosa sto facendo? Attualmente sto sviluppando un framework per il rendering di funzionalità bidimensionali che devono essere visualizzate in tempo reale. Puoi pensare ad un'applicazione come Google Maps nel tuo browser, tuttavia il framework è pensato per rendere tutti i tipi di dati geografici (non solo i dati raster allineati agli assi, come quelli di Google Tiles).

Il framework deve essere integrato nel prodotto più recente (della società), un'applicazione WPF per desktop e laptop.

Pertanto ho scelto WPF per il rendering effettivo della geometria solo; Visibilità e Occlusione L'abbattimento avviene da solo così come la gestione degli input (selezione del mouse), lo spostamento della fotocamera, ecc.

Essendo un'applicazione in tempo reale, è necessario ottenere almeno 30 FPS. Il framework si comporta in modo adeguato durante il rendering delle immagini: riesco a disegnare diverse migliaia di bitmap per fotogramma senza problemi, tuttavia i dati poligonali si rivelano essere un grosso problema.

La domanda attuale sto rendendo la mia buona dose di polilinee e poligoni dati utilizzando WPF, in particolare utilizzando DrawingContext e StreamGeometry. La mia comprensione finora è che questo è il modo di andare per se ho bisogno di prestazioni. Tuttavia non sono in grado di ottenere i risultati che mi aspettavo da questo.

Questo è come mi riempio lo StreamGeometry con i dati reali:

using (StreamGeometryContext ctx = Geometry.Open()) 
{ 
     foreach (var segment in segments) 
    { 
     var first = ToWpf(segment[0]); 
     ctx.BeginFigure(first, false, false); 

     // Skip the first point, obviously 
     List<Point> points = segment.Skip(1).Select(ToWpf).ToList(); 
     ctx.PolyLineTo(points, true, false); 
    } 
} 
    Geometry.Freeze(); 

Ed è così che ne traggo la mia geometria:

_dc.PushTransform(_mercatorToView); 
_dc.DrawGeometry(null, _pen, polyline); 
_dc.Pop(); 

Come prova, ho caricato forme ESRI da OpenStreetMap nel mio applicazione per testare le sue prestazioni, tuttavia non sono affatto soddisfatto: I miei dati di test sono composti da ~ 3500 segmenti di linea con un totale di ~ 20k linee.

Mappare ciascun segmento sul proprio StreamGeometry è stato estremamente negativo, ma mi aspettavo che lo fosse già: il rendering impiega circa 14 secondi.

Ho quindi provato a riempire più segmenti nello stesso streamGeometry, utilizzando più cifre: 80 StreamGeometry, il rendering richiede circa 50ms.

Tuttavia non riesco a ottenere risultati migliori di questo. Aumentare la quantità di linee a circa 100k rende la mia applicazione quasi inutilizzabile: il rendering richiede più di 100 ms. Che altro posso fare oltre a congelare sia la geometria che la penna durante il rendering dei dati vettoriali?

Sono al punto in cui preferirei utilizzare DirectX piuttosto che affidarmi a WPF perché lo facessi perché qualcosa sembra andare terribilmente male.

Modifica

per chiarire ulteriormente ciò che sto facendo: L'applicazione visualizza i dati geografici in tempo reale, molto molto simile a un programma come Google Maps nel browser: Tuttavia si suppone di visualizzare molto , molti più dati. Come forse saprai, Google Maps consente sia lo zoom che il panning, che richiede> 25 FPS affinché appaia come un'animazione fluente; niente di meno non si sente fluente.

* Spiacente ma non dovrei caricare un video di questo prima che il prodotto reale sia stato rilasciato. Potresti comunque immaginare qualcosa come Google Maps, comunque con tonnellate di dati vettoriali (poligoni e polilinee). *

Ci sono due soluzioni, una delle quali è molto spesso dichiarato:

cache disegni pesanti in una bitmap

L'attuazione sembra pò facile, tuttavia vedo qualche problema con questo approccio: Per implementare correttamente il panning, è necessario evitare disegnare il materiale pesante per ogni fotogramma e pertanto mi rimane la scelta di non aggiornare la bitmap memorizzata nella cache mentre si esegue il panning della fotocamera o di creare una bitmap che copra un'area ancora più grande rispetto al viewport, quindi ho solo bisogno di aggiornare e la bitmap memorizzata nella cache ogni tanto.

Il secondo "" problema " è relativo allo zoom. Tuttavia è più un artefatto visivo che un problema reale: poiché la bitmap memorizzata nella cache non può essere correttamente aggiornata a 30 FPS, devo evitare che anche durante lo zoom. Potrei davvero ridimensionare la bitmap durante lo zoom, creando solo una nuova bitmap quando lo zoom termina, tuttavia la larghezza delle polilinee sarebbe non con spessore costante, anche se dovrebbero.

Questo approccio sembra essere utilizzato da MapInfo, tuttavia non posso dire di esserne troppo affezionato. Tuttavia, sembra essere il più semplice da implementare.

Split geometria fino in diverse immagini di disegno

Questo approccio sembra per affrontare il problema in modo diverso. Non sono sicuro che questo approccio funzioni: dipende o meno dal modo in cui ho capito correttamente come dovrebbe funzionare WPF in quest'area. Invece di usare una DrawingVisual per tutte le cose che devono essere disegnate, dovrei usarne diverse, in modo che non tutti debbano essere RenderOpened(). Potrei semplicemente cambiare i parametri, ad esempio la matrice nell'esempio sopra, in modo da riflettere sia la panoramica della telecamera che lo spostamento. Tuttavia, vedo alcuni problemi con questo approccio: Panning della camera porterà inevitabilmente nuova geometria nel viewport, quindi avrei bisogno di eseguire qualcosa di simile rispetto al primo approccio, in realtà renderò roba che al momento non è visibile, ma potrebbe diventare visibile a causa dello spostamento della fotocamera; Disegnare tutto è fuori questione in quanto potrebbe richiedere ridicole quantità di tempo per una quantità piuttosto piccola di dati.

problema legato a entrambi gli approcci Un grosso problema che nessuno di questi approccio in grado di risolvere è che, anche se il complessiva frame-rate è stabile, hickups occasionali, sia quando l'aggiornamento delle bitmap nella cache (ok, questo doesn si applica se la bitmap memorizzata nella cache viene aggiornata solo quando la fotocamera non viene più spostata) o chiamando RenderOpen per disegnare il frammento visibile della geometria, sembra essere inevitabile.

I miei pensieri finora

Dal momento che questi sono gli unici due soluzioni ho mai vedere a questo problema (Ho fatto la mia parte equa di googling per più di un anno), Credo che l'unica soluzione in modo lontano è accettare hickups frame-rate anche sui più potenti GPU (che dovrebbe essere in grado di rasterizzare centinaia di milioni di primitive per secondo), un aggiornamento ritardato della finestra (nel caso in cui le bitmap vengono aggiornate solo quando la finestra non è spostato più a lungo) o non utilizzare affatto WPF e ricorrere direttamente a DirectX.

Sono molto contento per l'aiuto, però non posso dire che sono impressionato dalle prestazioni di rendering WPFs finora.

+0

fare le polilinee davvero cambiano su ogni fotogramma, in modo che essi devono essere ridisegnato? Altrimenti sarebbe sufficiente aggiornare la trasformazione di 'mercatorToView'. – Clemens

+0

Le polilinee possono cambiare ogni fotogramma, ma attualmente non lo fanno. Tuttavia, altre parti del mio disegno cambiano molto frequentemente, quindi sto ridisegnando tutto. Ti cosa che sia saggio per dividere il mio disegno in diverse DrawingContexts, ogni solo il rendering in caso di necessità, mentre in caso contrario solo l'aggiornamento dei parametri, ad esempio le matrici, ma non emissione di nuovi comandi di disegno? – Simon

+0

Si dovrebbe sempre provare a ridisegnare il minor numero di disegni possibile. Se solo pochi disegni cambiano con una frequenza molto più alta di molti altri, si perderebbe tempo con il ridisegnare spesso molti disegni non modificati. E nel tuo esempio di codice non si tratta solo di ridisegnare un oggetto StreamGeometry, ma anche di ricreare i dati della polilinea tramite chiamate frequenti al metodo 'ToWpf'. Anche questo richiede un po 'di tempo. – Clemens

risposta

2

Per migliorare le prestazioni di rendering 2D WPF, è possibile dare un'occhiata allo (per WPF> = 3.5) o alla classe BitmapCache (per WPF> = 4).

Le classi sono utilizzate per Cached Composition

Da MSDN:

Utilizzando le nuove classi BitmapCache e BitmapCacheBrush, è possibile memorizzare nella cache una parte complessa del albero visuale come bitmap e migliorare notevolmente il tempo di rendering . La bitmap rimane reattiva all'input dell'utente, come i clic del mouse, e puoi dipingerla su altri elementi come qualsiasi pennello.

+0

Than, voi per quei suggerimenti. Potrebbe essere possibile fare uso di caching quando si disegna un sacco di geometria, ma io non sono soddisfatto di questa opzione, perché non riesco a capire che cosa fa WPF, che ci vuole tanto tempo per rendere poche righe. Anche se si costruiscono i buffer vertex & indice sulla CPU (WRT di larghezza della penna) e caricarli su memoria video ogni fotogramma, che non dovrebbe prendere 50 ms per un semplice 20k line-segments.Edit Una volta che sono a casa, mi caricherà un video dell'applicazione, che dovrebbe anche chiarire perché non sono soddisfatto dell'utilizzo di una bitmap memorizzata nella cache. – Simon

+0

Klaus78, sei il mio sapore! Grazie mille.Sono stato combattuto con il rendering lento dei poligoni WPF (ne ho da 100.000 a milioni). Dopo il rendering, è così lento da scorrere, spostare e zoomare. Per non parlare del fatto che devo anche trascinare, ridimensionare, ruotare e inclinare l'oggetto. Ho provato a installare NVidia Quardro K2200 ma non è migliorato molto. Il motivo è che WPF utilizza solo GPU (il 20% della sua forza completa) durante OnRender. Quando pan, zoom, scroll, ecc, la GPU è 0%. Di BitmapCache l'UIElement che contiene questi poligoni, questo problema scompare. –

Problemi correlati