¿Cómo puedo reducir el impacto en el rendimiento de renderizar árboles?

24

Estoy haciendo un tipo de juego estilizado de baja poli. Tengo un terreno con un poco de agua y quiero muchos árboles; Tengo 10.000 árboles colocados en masa, por el momento. Cada árbol consta de no más de 200 triángulos, por lo que no son demasiado exigentes.

El principal problema es que hay lagos, y los lagos son bastante grandes. En realidad, no puedes ver ningún árbol al otro lado del lago, y eso se ve muy mal, especialmente cuando caminas allí y de repente aparecen árboles.

Para solucionar esto, tengo que aumentar la distancia del árbol para que puedas ver una cantidad decente de árboles al otro lado del lago, pero eso reduce el rendimiento a 40-50 fps, y todavía no hay casi nada más en el juego. Estoy usando una GTX 1080, si eso ayuda.

¿Qué puedo hacer para que mi juego funcione más rápido con más árboles?

señor-mate
fuente
IIRC, Silent Hill usó niebla para ocultar el corte en el plano de recorte lejano, lo que les permitió comenzar a cargar dinámicamente cosas más allá de donde se corta la niebla. Podrías beneficiarte de un cambio en la atmósfera del juego.
Cody
Los árboles lo atraen para mirar por la ventana, lo que reduce su rendimiento.
mbomb007
¿Has intentado ejecutar el generador de perfiles? Si es así, ¿dónde está el cuello de botella?
Mikael Högström
¿Estás haciendo algún tipo de sacrificio de frustum?
Krythic
¿Qué es el sacrificio de Frustum?
mr-matt

Respuestas:

43

Hay un par de cosas que puede hacer para aumentar el rendimiento del dibujo.

  1. Dijiste que estaban bastante lejos. Podría usar LOD para disminuir el conteo de vértices de esos árboles, y así disminuir el tiempo requerido para atravesar todos los vértices que se están dibujando. Aunque es muy probable que este no sea el problema en cuestión (GTX1080 con solo 10k árboles con 200 tris cada uno, números insignificantes para el gpu), todavía lo incluí. La valla publicitaria es una herramienta eficaz para el nivel más bajo de LOD, ya que es esencialmente un plano plano que siempre mira hacia la cámara con una imagen renderizada del árbol. Pierde la sensación de profundidad, por lo que es bueno para el nivel más bajo, ya que el jugador probablemente no notará la diferencia.

  2. ¿Ha habilitado el procesamiento por lotes ? El procesamiento por lotes dinámico generalmente se realiza automáticamente si el recuento de vértices de las mallas es bastante bajo. El procesamiento por lotes estático también se puede probar haciendo que los árboles estén estáticos marcando la casilla de verificación en el editor de la unidad en el objeto del juego principal. Esto no funciona bien con objetos animados. Necesita que los objetos tengan material compartido para que esto funcione.

  3. El procesamiento por lotes personalizado le permite controlar el renderizado generando los fragmentos usted mismo en lugar de dejar que Unity lo maneje, y también permite el procesamiento por lotes para mallas más grandes. Esto se hace fácilmente por Mesh.CombineMeshes . Esto tampoco funciona bien con objetos animados. Necesita que los objetos tengan material compartido para que esto funcione. Probablemente quieras dividir tu mundo en algún tipo de trozos y crear lotes a partir de ellos. La forma en que deberían generarse esos fragmentos depende realmente de cómo se mueve su cámara en el mundo.

  4. Habilite la creación de instancias en los sombreadores. La instancia permite que el motor dibuje múltiples objetos (con la misma malla) con solo una llamada de dibujo. Necesita que los objetos tengan malla compartida y sombreador compartido para que esto funcione. El material puede variar, pero el sombreador debe admitir todas las diferentes propiedades variables.

    Para hacer que el motor cree mejores lotes de renderizado instanciado, probablemente desee agrupar las mismas mallas en la escena. También jugar con la cola de renderizado de material le dará buenos resultados si una malla tiene siempre el mismo material. Durante el desarrollo del juego móvil en el que estoy trabajando actualmente, utilicé esto para reducir las llamadas a más de la mitad en mi escena de prueba. Además, desde Unity 5.6, asegúrese de marcar la Enable Instancingcasilla de verificación en el material.

  5. Mantenga sus llamadas y sus llamadas SetPass bajas en general. Estas son las llamadas crudas para que su GPU dibuje cosas, y tienen una gran sobrecarga. La reducción de las llamadas de extracción (que es lo que está haciendo el procesamiento por lotes y la creación de instancias) aumentará el rendimiento general que puede proporcionar su CPU, ya que es necesario que espere mucho menos. Las llamadas SetPass son cambios en sus sombreadores actuales, por lo que si tiene muchos materiales diferentes, tendrá varias llamadas SetPass, lo que también hará que la CPU espere un poco.

  6. Si su escena es enorme y su tiempo de CPU pasa para revisar todos los objetos de la escena, intente reducir los objetos en la escena. Agrupe algunos árboles en lugar de colocarlos invidualmente y téngalos como un solo objeto. También asegúrese de no mover los árboles o los objetos principales, ya que eso hace que Unity descarte las transformaciones almacenadas en caché y recalcule todo el árbol de la escena.

  7. Si su escena es enorme y su tiempo de CPU todavía se dedica principalmente a Unity caminando por el árbol de la escena para hacer listas para renderizar todos los objetos, una cosa que podría hacer es no permitir que Unity se encargue del renderizado. Si tiene una mejor manera de rastrear objetos dibujables, puede usar CommandBuffer.DrawMeshInstanced o Graphics.DrawMeshInstanced para dibujarlos a mano. No voy a entrar en muchos detalles sobre esto, ya que es mucho más avanzado e implica sacrificio obedece a ti mismo y todo lo demás.

En caso de que el procesamiento por lotes estático o dinámico no funcione correctamente (lo que puede ver al verificar el depurador de trama), debe asegurarse de que está utilizando material compartido y no está haciendo copias del material por accidente con la llamada meshRenderer.material. Llamar al .materialhará copias de sus materiales y dividirá el procesamiento por lotes. Usar en su .sharedMateriallugar.

Desde Unity 5.6 puede usar el Depurador de tramas para determinar por qué ciertas llamadas no se combinaron con las llamadas anteriores. Esto será realmente útil al tratar de reducir las llamadas de su juego.

La instancia tiene las siguientes ventajas sobre el procesamiento por lotes estático / dinámico / personalizado:

  • Utiliza menos memoria ya que la malla no tiene que duplicarse en la memoria
  • Puede usar múltiples materiales, solo se requiere sombreador compartido
  • Los objetos pueden ser animados.

Además, como inconveniente, es una característica bastante nueva en Unity y puede ser un poco inestable. Además, las GPU de dispositivos móviles o anteriores no son necesariamente compatibles con la creación de instancias.

Lasse
fuente
1. Sí, he probado LOD, y para mi sorpresa, en realidad lo empeoró. Tenía 3 variaciones de los árboles, cada una con un recuento de vértices ligeramente más bajo, y un plano plano con una imagen renderizada del árbol.
mr-matt
2. Todos mis árboles están marcados como estáticos. Por lo que sé, ¿eso permite el procesamiento por lotes? ¿Es eso correcto? Y cuando dices material compartido, ¿simplemente quieres decir que los árboles tienen el mismo material?
mr-matt
3. ¿Qué tipo de mejora de rendimiento haría realmente esto? ¿Vale la pena intentarlo?
mr-matt
1
2/3: En mi experiencia, Unity no hace un buen trabajo en el procesamiento por lotes dinámico y el procesamiento por lotes estático aumenta el tamaño de construcción, por lo que implementé el procesamiento por mí mismo e hice la malla combinando el tiempo de carga. Utilizando esta técnica, logré hacer 2500 llamadas de extracción para comprimir en aproximadamente 300 llamadas de extracción, lo que fue crucial para nuestro juego móvil donde las llamadas de extracción son importantes. Hizo un poco de vértices innecesarios para calcular (fuera de pantalla) pero valió la pena.
Lasse
2
tfw cuando lees una pregunta sobre el bajo rendimiento con árboles y no se pierde una sola palabra sobre cartelera
Num Lock
13

Ok, entonces el problema era simplemente que no estaba usando GI precomputado en tiempo real. Lo comprobé hace un momento, pero no tuvo un efecto inmediato, así que lo dejé y lo olvidé, y el tiempo de procesamiento de la iluminación también fue muy largo. Sin embargo, acaba de terminar de procesarlo, y mi palabra, mi fps ha aumentado 3 veces. ¡Así que por ahora, lo dejaré así y en el futuro me aseguraré de usar siempre GI en tiempo real de precomputadora!

Si todavía hay algo más que podría estar haciendo para mejorar aún más el rendimiento, hágamelo saber, ¡estaría muy agradecido!

señor-mate
fuente
2
Utilice la eliminación de oclusiones, también si su escena es grande; considere dividirla en trozos, por ejemplo, en muchos terrenos y cárguela y descárguela.
Candid Moon _Max_
Dado que parece haber resuelto su problema, probablemente debería aceptar esta respuesta.
Gnemlock