Estoy haciendo esta pregunta porque no he encontrado una respuesta definitiva.
Antes que nada, déjenme decir algunas cosas sobre el juego y lo que ya he hecho. El juego será un juego de estrategia en tiempo real en un mundo generado por procedimientos que utiliza ruido Simplex. El mundo está formado por trozos de 16 x 16 de tamaño hechos de sprites de 64 x 64. Me las he arreglado para cargar y descargar trozos dinámicamente, lo que funciona bien. El mundo se verá un poco como Rimworld, de arriba hacia abajo con diferentes capas de sprites (terreno primero, sprites de transición, árboles, calcomanías, etc.). Los mundos recién generados pueden contener entidades que pueden afectar el medio ambiente (por ejemplo, una aldea que se ha convertido en una ciudad) y, por lo tanto, la porción. Estoy seguro de que esto se puede calcular utilizando algún tipo de función, pero es algo a tener en cuenta.
El problema principal que tengo es cuando alejo, se dibujan más y más mosaicos que afectan gravemente el rendimiento. Con aproximadamente 30000 sprites, la sección de sorteo dura 8 ms, que es la mitad de lo que se requiere para correr a 60 FPS. Y ese es solo el terreno. Estoy usando atlas de textura para limitar el conteo de sorteos (30000 sprites dibujados en 6 conteos).
El objetivo es poder alejarse del pueblo / pueblo / ciudad hasta poder ver un país entero. Esto tiene que ser hecho de forma dinámica (por ejemplo. No haciendo clic en el icono de mini mapa, pero sólo tiene que desplazarse hacia atrás al igual que en Supreme Commander).
He leído muchos artículos sobre este tema, pero no he encontrado ni visto un ejemplo claro de dónde funcionaría. Aquí hay una lista de técnicas que he encontrado que se supone que funcionan:
- Rectángulos sucios, como se describe aquí , donde solo dibujas cosas nuevas y mantienes el resto en el backbuffer. Esto tiene mucho sentido, pero no tengo idea de cómo implementar esto en Monogame.
- Mi elección preferida: hacer un uso extensivo de RenderTargets, como se describe aquí , donde dibuje a un RenderTarget y luego guárdelo como una textura. En mi caso, un trozo de 16 x 16 formado por 64 x 64 crearía una textura de 1024 x 1024. Realmente dudo que esto funcione en términos de rendimiento, pero el resultado consistiría en texturas muy detalladas y también es excelente para usar teniendo en cuenta el hecho de que la mayoría es estático (terreno / árboles, etc.), y no cambia tanto. Pero esto también significa que cada vez que se realiza un cambio en un fragmento, Texture2D tiene que cambiarse usando SetData, que por lo que he experimentado es bastante intensivo en la CPU. Sin embargo, si las texturas fueran 16 x 16, en realidad podría funcionar, y también reduciría el uso de la memoria y el disco.
- Hasta texturas especificando el SourceRectangle en SpriteBatch. Para grandes praderas / océanos esto es una ventaja, ya que solo se dibuja un sprite. Sin embargo, para terrenos detallados con diferentes colores y diferentes sprites mezclados (biomas y transiciones de biomas), me temo que no hará una gran diferencia.
- Mi propia solución, que compromete los detalles, fue usar un mosaico blanco estándar de 64 x 64, darle el color de los 4 mosaicos circundantes y luego escalarlo para que cubra los 4 mosaicos anteriores. La diferencia aquí (además de que el mosaico tiene un color liso) es que el paisaje cambió visiblemente. También debo mencionar que los bosques aún deben dibujarse individualmente, ya que no son perfectamente cuadrados.
Si alguien tiene alguna idea sobre cómo abordar este problema, incluso si eso significa comprometer ciertas cosas (como detalles o usar sprites de 16 x 16), me encantaría escucharlo.
Respuestas:
Las tarjetas gráficas están optimizadas para dibujar algunas cosas muchas veces en lugar de al revés.
En su caso, tiene muchas cosas (texturas diferentes) que desea dibujar muchas veces (número de mosaicos).
En mi opinión, las optimizaciones más simples que puede hacer para obtener ganancias significativas de rendimiento son:
Yo recomendaría hacer ambas cosas. Buena suerte.
fuente
Descubrí que SpriteBatch no es adecuado para dibujar mosaicos. Una razón es que los sprites están destinados a objetos dinámicos y se utilizan para múltiples propósitos. Otra razón es que está increíblemente vinculada a la CPU , por ejemplo. como se explica en el dibujo de descripción, 30,000 objetos cuestan 8 ms (mientras que mi conjunto de chips se maximizó al 30%). Además, se pueden dibujar hasta 3000 sprites antes de que se realice una nueva llamada de sorteo a la GPU (lote y todo).
La solución fue dibujar mis propios mosaicos usando quads texturizados . Esto en combinación con un VertexBuffer me permitió dibujar hasta 500,000 fichas texturizadas en 1 llamada de dibujo donde el método de dibujo consumió aproximadamente 1/20 de milisegundo. Por supuesto, probablemente no tenga que dibujar tantos, pero de cualquier manera finalmente conseguí que mi GPU tuviera una carga de trabajo del 75% a una velocidad constante de 60 fps.
fuente