2010-02-23 4 views
12

Estoy trabajando en una aplicación similar a un juego que tiene hasta mil formas (elipsis y líneas) que cambian constantemente a 60 fps. Después de leer excellent article on rendering many moving shapes, implementé esto usando un descendiente personalizado de Canvas que reemplaza OnRender para hacer el dibujo a través de DrawingContext. El rendimiento es bastante razonable, aunque el uso de CPU se mantiene alto.Rendimiento de DrawingVisual frente a Canvas.OnRender para muchas formas en constante cambio

Sin embargo, el artículo sugiere que el enfoque más eficaz para constante movimiento formas es usar un montón de DrawingVisual casos en lugar de OnRender. Lamentablemente, aunque no explica por qué que debería ser más rápido para este escenario.

Cambiar la implementación de esta manera no es un esfuerzo pequeño, así que me gustaría entender las razones y si son aplicables a mí antes de decidir hacer el cambio. ¿Por qué podría el enfoque DrawingVisual dar como resultado un uso de CPU menor que el enfoque OnRender en este escenario?

+0

Romkyns, podría crear una versión simplificada con DrawingVisual y Canvas.OnRender() para que coincida con el rendimiento, antes de profundizar en grandes cambios. En cuanto a la respuesta, estoy totalmente de acuerdo con Charlie. – Anvaka

Respuesta

7

Pensé que Petzold explica en este párrafo;

Los trabajos de clase ScatterPlotVisual por creación de un objeto DrawingVisual para cada DataPoint. Cuando cambian las propiedades de un objeto DataPoint, la clase solo necesita alterar el DrawingVisual asociado con ese DataPoint.

que se basa en la explicación anterior ;

Siempre que los ItemsSource propiedad cambios, o se cambia la colección, o una propiedad de los objetos DataPoint en los cambios de recolección, ScatterPlotRender llama InvalidateVisual. Esto genera una llamada a OnRender, que dibuja el diagrama de dispersión completo .

¿Es esto lo que preguntas? Por cierto, this es un tutorial WPF de alto rendimiento bastante reciente, con muchas decenas de miles de puntos en esa trama, también se representa en 3D y también se anima (incluso utiliza la entrada del mouse para controlar algunas de las transformadas).

+2

Sí, parece que estaba confundido al no darme cuenta de que el enfoque 'DrawingVisual' solo se dice que es el" mejor "método para este escenario en particular, donde cambian muchos puntos, pero no todos. Cuando todo se mueve (que es el caso para mí) 'OnRender' suena como el mejor enfoque. Buen enlace, también, gracias. –

+0

Hay otro enfoque que considero que es el mejor rendimiento para mutar una aplicación con "muchas formas que cambian constantemente", que fue la pregunta del OP. Tu aplicación puede manipular un árbol de DrawingGroups. Solo debe llamar a RenderOpen/DrawDrawing una vez, al inicio de la aplicación, en la raíz de este árbol.A partir de ese momento, WPF nota todas las ediciones en el árbol y las actualizaciones de forma automática, incluidas las transformaciones e inserción/eliminación de elementos del grupo de dibujo profundamente anidados. Necesitará una estructura de datos que rastree/mantenga el estado del árbol. Ver mi comentario en http://stackoverflow.com/a/716469/147511. –

15

De Pro WPF en C# 2008:

El problema planteado por estas aplicaciones no es la complejidad de el arte, pero el gran número de elementos gráficos individuales. Incluso si reemplaza sus elementos de ruta con objetos de Geometría más livianos, la sobrecarga aún obstaculizará el rendimiento de la aplicación . La solución WPF para este tipo de situación es para usar el modelo de capa visual de nivel inferior . La idea básica es que defina cada elemento gráfico como un objeto visual , que es un ingrediente ligero extremadamente que tiene menos sobrecarga que un objeto Geometry o un objeto Path.

Lo que se reduce a es que cada una de esas líneas y elipses que está creando es una FrameworkElement separada; eso significa que no solo es compatible con las pruebas de impacto, sino también con el diseño, la entrada, el enfoque, los eventos, los estilos, el enlace de datos, los recursos y la animación. ¡Es un objeto bastante pesado para lo que estás tratando de hacer! El objeto Visual omite todo eso y lo hereda directamente del DependencyObject. Todavía proporciona soporte para pruebas de golpes, transformación de coordenadas y cálculos de cuadro delimitador, pero ninguna de las otras cosas que admiten las formas. Es mucho más liviano y probablemente mejore tu rendimiento inmensamente.

EDIT:

Ok, leí mal su pregunta la primera vez.

En el caso de que esté usando OnRender, realmente depende de cómo está creando las imágenes y mostrándolas. Si está usando un DrawingContext y agrega todos los elementos visuales a un solo elemento, esto no es diferente de usar el enfoque DrawingVisual. Si estuviera creando un elemento separado para cada Visual creado, entonces esto sería un problema. Me parece que estás haciendo las cosas bien.

+2

¡Muy buena respuesta! +1 de mi parte – Anvaka

+1

Espera, espera, ¡no estoy creando ningún FrameworkElements! :) Estoy usando 'OnRender' +' DrawingContext', así que a menos que DrawingContext cree un montón de FrameworkElements detrás de las escenas (lo cual dudo) este no es el caso. –

+0

Mi mal. Se agregó una edición. :) – Charlie

7

Todos en las respuestas se equivocaron. La pregunta es si renderizar figuras directamente en el contexto de dibujo es más rápido que crear DrawingVisual. La respuesta es obviamente sí'. Las funciones como DrawLine, DrawEllipse, DrawRectangle, etc. no crean ningún elemento UI. DrawingVisual es mucho más lento porque crea un elemento UI, aunque es liviano. La confusión en las respuestas se debe a que las personas simplemente copian/pegan el DrawingVisual tiene un mejor rendimiento que el enunciado de formas de UIElement distinto de MSDN.

+4

No estoy del todo seguro de que la respuesta sea tan obvia. En los casos en que la mayoría de las formas no se mueven, ¿no es el contexto del dibujo * más lento *? Redibuja todo, mientras que el enfoque DrawingVisual le permite al marco almacenar en caché y reutilizar los elementos dibujados anteriormente. ¿O no es así? –

+3

DrawingContext no vuelve a dibujar todo porque WPF tiene un modelo de dibujo retenido. DrawingVisual incluye una lógica que controla si se debe volver a dibujar o no Visual. Puede implementar la misma lógica en el método OnRender() y dibujar solo cuando sea necesario. WPF no invalidará su dibujo a 60 fps, OnRender() se invoca solo cuando llama a InvalidateVisual() o cuando WPF necesita invalidar su dibujo. – user275587

2

En mis pruebas sin embargo (animaciones de barrido), noto que no hay diferencia en la velocidad. Diría que usar un elemento host para muchas imágenes de dibujo es un poco más rápido. Este enfoque donde construyes tu árbol visual con muchas imágenes te da más control. Además, cuando quiera realizar una prueba de impacto compleja, el proceso de filtrado es más rápido porque puede omitir "ramas" completas de imágenes

Cuestiones relacionadas