Actualmente estoy trabajando en un juego y deseo tener un menú principal con la imagen de fondo.

Sin embargo, encontrar el método Graphics.DrawImage() muy lento. He hecho algunos de medición. Supongamos que MenuBackground es mi recurso de imagen con resolución de 800 x 1200 píxeles. Voy a dibujar en otro de 800 x 1200 de mapa de bits (I hacer todo a un búfer de mapa de bits en primer lugar, entonces yo escala y finalmente dibujar en la pantalla – que es lo que yo trato con la posibilidad de múltiples jugadores resoluciones. Pero no debe afectar de ninguna manera, ver el párrafo siguiente).

Lo he medido el siguiente código:

Stopwatch SW = new Stopwatch();
SW.Start();

//First let's render background image into original-sized bitmap:

OriginalRenderGraphics.DrawImage(Properties.Resources.MenuBackground,
   new Rectangle(0, 0, Globals.OriginalScreenWidth, Globals.OriginalScreenHeight));

SW.Stop();
System.Windows.Forms.MessageBox.Show(SW.ElapsedMilliseconds + " milliseconds");

El resultado es tranquilo me sorprende – la Stopwatch medidas algo entre 40 - 50 milliseconds. Y porque la imagen de fondo no es la única cosa para ser dibujado, todo el menú de toma alrededor de más de 100 ms para mostrar, lo que implica observable lag.

He tratado de atraer a los Gráficos del objeto dado por evento Paint, pero el resultado fue 30 - 40 milliseconds – no ha cambiado mucho.

Así, qué significa, que Graphics.DrawImage() es inservible para la elaboración de las imágenes más grandes? Si es así, ¿qué debo hacer para mejorar el rendimiento de mi juego?

  • Si por «inservibles» que significa «lento como un caracol en la melaza», entonces sí. Como otros han dicho, dar XNA una oportunidad. Se adhieren a 2D sprite de representación hasta que estamos acostumbrados a XNA framework, a continuación, mueva hacia el 3D si usted está tan inclinado.
  • Estoy upvoting que sólo por la analogía. 🙂

4 Comentarios

  1. 109

    Sí, es demasiado lento.

    Me encontré con este problema hace varios años, mientras que el desarrollo Paint.NET (desde el principio, en realidad, y fue bastante frustrante!). El rendimiento de la representación fue abismal, como siempre fue proporcional al tamaño del mapa de bits y no el tamaño de la zona que se les ha dicho a dibujar. Es decir, la tasa de fotogramas se fue hacia abajo, como el tamaño del mapa de bits subió, y la tasa de fotogramas nunca fue como el tamaño de la inválido/redibujar el área fue abajo cuando la aplicación de OnPaint() y llamando a los Gráficos.DrawImage(). Un pequeño mapa de bits, decir 800×600, siempre funcionó bien, pero las imágenes de mayor tamaño (por ejemplo, 2400×1800) fueron muy lentos. (Se puede suponer, por el párrafo anterior, de todos modos, que no hay nada extra que estaba pasando, tales como la escala con algunos caros ayuda de Este filtro, lo que habría afectado negativamente el rendimiento.)

    Es posible forzar WinForms en el uso de GDI en lugar de GDI+ y evitar incluso la creación de un Graphics objeto detrás de las escenas, en la que se le de la capa de otra representación de la caja de herramientas de la parte superior de que (por ejemplo, Direct2D). Sin embargo, no es simple. Puedo hacer esto en Paint.NET y usted puede ver lo que se requiere por el uso de algo como Reflector en la clase llamada GdiPaintControl en el SystemLayer DLL, pero por lo que estás haciendo me gustaría considerar un último recurso.

    Sin embargo, el tamaño de mapa de bits está utilizando (800×1200) debe aún trabajar ACEPTAR suficiente en GDI+, sin tener que recurrir a la avanzada de la interoperabilidad, a menos que usted está apuntando a algo tan bajo como 300 mhz Pentium II. Aquí hay algunos consejos que podrían ayudar:

    • Si usted está usando un mapa de bits opaco (no alpha/transparencia) en la llamada a Graphics.DrawImage(), y sobre todo si es de 32 bits del mapa de bits con un canal alfa (pero saber es opaco, o no le importa), a continuación, establezca Graphics.CompositingMode a CompositingMode.SourceCopy antes de llamar a DrawImage() (asegúrese de volver a establecer el valor original después de que, de otra manera regular dibujo de primitivas tendrá un aspecto muy feo). Este se salta una cantidad adicional de la mezcla de matemáticas por píxel.
    • Asegúrese de Graphics.InterpolationMode no es algo como InterpolationMode.HighQualityBicubic. El uso de NearestNeighbor será el más rápido, aunque si hay cualquier estiramiento, es posible que no se ven muy bien (a menos que sea estiramiento exactamente 2x, 3x, 4x, etc.) Bilinear es generalmente un buen compromiso. Nunca se debe usar cualquier cosa, pero NearestNeighbor si el tamaño del mapa de bits coincide con el área de dibujo, en píxeles.
    • Siempre dibujar en la Graphics objeto dado en OnPaint().
    • Siempre hacer su dibujo en OnPaint. Si usted necesita para volver a dibujar un área, llamada Invalidate(). Si usted necesita el dibujo a suceder ahora mismo, llame a Update() después de Invalidate(). Este es un enfoque razonable ya que los mensajes WM_PAINT (que se traduce en una llamada a OnPaint()) son de «baja prioridad» de los mensajes. Cualquier otro tipo de procesamiento por la ventana de administrador de hecho primero, y por lo tanto usted podría terminar con un montón de marco saltar y tirar de otra manera.
    • El uso de un System.Windows.Forms.Timer como un framerate/tick timer no funciona muy bien. Estas son implementadas usando Win32 del SetTimer y resultado en los mensajes WM_TIMER, los cuales redundan en la Timer.Tick caso planteado, y WM_TIMER es otro mensaje de prioridad baja que sólo se envían cuando el mensaje de la cola está vacía. Es mejor que use System.Threading.Timer y, a continuación, utilizando Control.Invoke() (para asegurarse de que usted está en el buen hilo!) y llamando a Control.Update().
    • En general, no utilice Control.CreateGraphics(). (corolario de ‘dibujar siempre en OnPaint()‘ y ‘utilizar siempre el Graphics dado a usted por OnPaint()‘)
    • Yo no recomendamos el uso de la Pintura de controlador de eventos. En su lugar, aplicar OnPaint() en la clase en la que está escrito que debe ser derivada a partir de Control. Derivada de otra clase, por ejemplo, PictureBox o UserControl, no se agrega ningún valor para usted o le agregue una sobrecarga adicional. (Por CIERTO PictureBox es a menudo mal entendido. Probablemente casi nunca quieren usar.)

    Espero que ayude.

    • usted se merece toneladas de upvotes.Para dibujar una cuadrícula de fondo es que hay alguna sugerencia ? TextureBrush parece rápido, pero no funciona cuando usted haya personalizado scalling con un factor de zoom al no coincidir
    • La mejor optimización de este post, para mí, fue el modo de interpolación. El cambio de Bilinear a NearestNeighbor el dibujo 8 veces más rápido.
    • Años más tarde todavía están ayudando a la gente con la pintura en winforms
    • Puede usted por favor aclarar tu último comentario, acerca de PictureBoxes? Por qué no deberían ser utilizados, y cómo están mal entendido?
    • PictureBox es la visualización de un Image, nada más. Si se pretende que la clase es sealed, su caso de uso debería ser más clara. Es incomprendido porque a menudo he visto el código donde se crea una nueva clase que se deriva de PictureBox y, a continuación, el autor anula OnPaint o lo que sea y no de representación personalizada. No hagas eso-sólo se derivan directamente de Control si usted desea hacer la representación personalizada. Y si lo que desea es mostrar un Image o Bitmap, uso PictureBox – pero no derivar una nueva clase a partir de ella. Pretender que el sellado.
  2. 3

    GDI+ no es probablemente la mejor opción para juegos. DirectX/XNA o OpenGL debe ser preferido, ya que utilizan cualquiera que sea la aceleración de gráficos es posible y es muy rápida.

  3. 3

    GDI+ no es un demonio de la velocidad, por cualquier medio. Cualquier grave manipulación de la imagen por lo general tiene que ir en el nativo lado de las cosas (pInvoke llamadas y/o la manipulación a través de un puntero obtenida llamando a LockBits.)

    Has mirado en XNA/DirectX/OpenGL?. Estos son los marcos diseñados para el desarrollo del juego y va a ser órdenes de magnitud más eficiente y flexible que el uso de un marco de interfaz de usuario como WinForms y WPF. Las bibliotecas ofrecen C# enlaces.

    Podría pInvoke en código nativo, usando funciones como BitBlt, pero hay una sobrecarga asociada con el cruce de la código administrado límite así.

    • Yo recomendaría OpenGL/DirectX demasiado. XNA no es realmente la MEJOR opción de por sí para una variedad de razones. La facilidad de uso, sí, pero a la larga es un poco de un handicap.
    • Tienes razón, son dignos de mención. DirectX es superior a OpenGL si no se preocupan acerca de la cruz-plataforma de apoyo. Puedes ampliar tu comentario » en el largo plazo [XNA] es un poco de un handicap». Probablemente tenga algunos agujeros en mis conocimientos como yo no soy un juego serio desarrollador, sólo un hobby mío.
    • XNA hace varios supuestos para su uso. Una de las serias limitaciones que puedo pensar es que varios rendertargets puede compartir un búfer de profundidad, haciendo escenarios comunes como forma eficiente de hacer la representación aplazada imposible. Ver aquí para más información (forums.create.msdn.com/forums/p/64179/397431.aspx)
    • También – no se ha definido un futuro en el Metro. No sé si será compatible fuera de proyectos como MonoGame (monogame.codeplex.com)
    • Gracias. Fui a la medida con el «Por lejos el mejor comentario. Yo pensaba que el uso de DirectX o OpenGL de C# puede ser incómodo, pero después de hacer algunas investigaciones parece que hay algunas buenas las interfaces de C# yo no era consciente de.
    • vale la pena señalar que, dado que esta fue publicado originalmente, XNA ha sido descontinuado. Aunque técnicamente es posible que el código de los juegos en ella todavía, es increíblemente difícil y no admitidos a conseguir incluso el entorno de desarrollo para instalar en las versiones más recientes de visual studio, ya que en su sabiduría, miraron para versiones específicas para apoyar con su instalador en lugar de «todas las versiones superiores a x», lo que significa 2017 trabaja con ella, pero se niega a instalar.

  4. 2

    Aunque esta es una antigua pregunta y WinForms es un antiguo Marco, me gustaría compartir lo que he descubierto por casualidad: el dibujo de un mapa de bits en una BufferedGraphics y la representación de que después de los gráficos contexto proporcionado por OnPaint es manera más rápido que el dibujo de mapa de bits directamente a OnPaint del contexto gráfico – al menos en mi Windows 10 máquina.

    Eso es sorprendente porque intuitivamente yo había asumido que sería un poco más lento para copiar los datos dos veces (y lo que he pensado que esto es por lo general sólo se justifica cuando uno quiere hacer el doble búfer manualmente). Pero, obviamente, hay algo más sofisticado, pasando con el objeto BufferedGraphics.

    Para crear un BufferedGraphics en el constructor del Control que albergará el mapa de bits (en mi caso, quería dibujar una vista de mapa de bits con una resolución de 1920×1080):

            using (Graphics graphics = CreateGraphics())
            {
                graphicsBuffer = BufferedGraphicsManager.Current.Allocate(graphics, new Rectangle(0,0,Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height));
            }

    y utilizarlo en OnPaint (mientras que en el vaciamiento OnPaintBackground)

        protected override void OnPaintBackground(PaintEventArgs e) {/* just rely on the bitmap to fill the screen */}
    
        protected override void OnPaint(PaintEventArgs e)
        {   
            Graphics g = graphicsBuffer.Graphics;
    
            g.DrawImage(someBitmap,0,0,bitmap.Width, bitmap.Height);
    
            graphicsBuffer.Render(e.Graphics);
        }

    lugar de ingenuamente la definición de

        protected override void OnPaintBackground(PaintEventArgs e) {/* just rely on the bitmap to fill the screen */}
    
        protected override void OnPaint(PaintEventArgs e)
        {   
            e.Graphics.DrawImage(someBitmap,0,0,bitmap.Width, bitmap.Height);
        }

    Ver las siguientes capturas de pantalla para una comparación de la resultante de evento MouseMove de la frecuencia (estoy implementando un muy simple boceto de mapa de bits de control). En la parte de arriba es la versión en la que el mapa de bits se dibuja directamente, en la parte inferior BufferedGraphics se utiliza. He movido el ratón a la misma velocidad en ambos casos.

    Es Gráficos.DrawImage demasiado lento para que las imágenes más grandes?

Dejar respuesta

Please enter your comment!
Please enter your name here