Estoy creando un juego XNA que requiere un gran espacio para los jugadores. Actualmente, el mapa de altura de prueba que estoy usando es 4096x4096, y se guarda como un BMP de 4 bits.
Lo que intento hacer es tomar ese enorme archivo de mapa de altura y representarlo en el juego. El problema con el que me encuentro es el hecho de que es ineficiente cargar todo el terreno en la memoria de una vez, ya que utilizará la mayoría de la memoria disponible.
Otro problema con el que me he encontrado es que no puedo representar todo el terreno en una sola primitiva debido a un límite rígido establecido dentro de XNA.
Dicho esto, he encontrado una serie de soluciones, todas las cuales he enumerado a continuación:
- Representación basada en la ubicación del usuario actual, básicamente dibujando un cuadrado alrededor del usuario sin importar su orientación dentro del mundo. Esto tampoco es exactamente lo que quería, porque todavía está generando espacio que el usuario no ve.
- Representación basada en la orientación y posición del usuario: encontré una fórmula para recuperar un triángulo que se supone que tiene los píxeles del mapa de altura que se deben representar, pero esto resultó ser muy difícil.
- Dividir el terreno en varios fragmentos y representar cuáles están más cerca del usuario: aún no es muy eficiente, ya que aún está creando fragmentos que la gente no verá. Y requiere mucho trabajo porque luego tengo que dividir mi mapa de altura en varias partes, y la escalabilidad se convierte en un gran problema.
Después de probar esas soluciones, no tengo ideas sobre qué hacer. He recibido algunas respuestas donde la gente me dice que haga estos algoritmos complejos, pero simplemente no tengo ni idea de cómo abordarlos.
Básicamente, estoy pidiendo una forma simple y directa de renderizar terrenos enormes en XNA con la máxima eficiencia.
Soy bastante nuevo en el desarrollo de juegos en general, pero estoy dispuesto a investigar si parece prometedor.
Actualización 1: Después de investigar el método de geoclipmapping, comencé a codificar con eso. Tengo todas las matemáticas hechas, y el juego se ejecuta. Sin embargo, es extremadamente ineficiente, lo que probablemente sea una mala codificación de mi parte. Se ejecuta a 2FPS y utiliza un núcleo completo de mi CPU. Voy a intentar mejorar el código, pero creo que necesitaré más ayuda, así que aquí hay un Pastebin del código para la clase de administrador de Terrain. Volveré a publicar con más resultados más adelante si alguna vez consigo que sea más eficiente.
Respuestas:
El enfoque de fragmentos suele ser lo que se usa. Rara vez es eficiente probar cada triángulo de cientos de miles para ver si debería renderizarlo. En cambio, la mayoría de los algoritmos de representación del terreno emplean una estructura de datos espaciales para representar dinámicamente las partes visibles del terreno.
Una estructura de datos fácil de implementar se llama quadtree . En resumen, para usar un árbol cuádruple, encontrará el frustum de visualización del jugador, se cruza con el nivel superior del árbol cuadriculado y para cualquier fragmento que sea parcialmente visible (es decir, los planos frustum se cruzan con el fragmento) se subdivide y prueba a todos los niños trozos, omitiendo los que están fuera del tronco. Esto dará una aproximación bastante cercana a la geometría visible real con solo unos pocos niveles de recursión.
Los renderizadores de terreno más avanzados usan un algoritmo para ajustar no solo la geometría visible sino también los detalles de esa geometría. Geomipmapping (y su geoclipmapping relativo) es relativamente popular en este momento por hacer eso, pero no es algo trivial de implementar.
editar: Aquí hay una descripción decente tanto del geoclipmapping como del sacrificio de frustum.
También tengo algunas dudas sobre si 4 bits para el mapa de altura son en realidad suficientes para producir un terreno agradable a menos que esté suavizando mucho el resultado.
fuente
Cualquier enfoque que requiera que haga trabajo por cuadro para cargar datos en la GPU será defectuoso.
Aquí hay un resumen de un enfoque que debería funcionar bien:
Debería dividir su terreno en trozos (bastante grandes), cargando esos trozos en búferes de vértices fijos (¡la profundidad de bits de su mapa de altura no importa!). Esos búferes de vértices simplemente se ubicarán en la memoria de la GPU, esperando ser renderizados. Tendrá que experimentar con un tamaño de fragmento apropiado, pero 128x128 es quizás un buen lugar para comenzar.
Para un terreno de 4096x4096, está un poco más allá del límite de lo que me sentiría cómodo cargando en la GPU de inmediato: es probable que sean unos cientos de MB de datos de vértice (aunque podría reducirlo a ~ 64MB si está inteligente). Por lo tanto, es posible que deba cargar y descargar las memorias intermedias de vértices de la GPU en segundo plano.
(Si implementa la carga en segundo plano de fragmentos, ¡esto debería ser extremadamente escalable!)
Una vez que tenga los datos de vértice en la GPU, es el momento adecuado para seleccionar la visibilidad por cada fragmento . No es necesario enviar el comando para representar un fragmento, si sabe que está detrás de la cámara.
¡Casi nunca deberías hacer sacrificios por triángulo en la CPU!
La GPU eliminará los triángulos que están fuera de la pantalla mucho más rápido de lo que nunca podrás.
Para obtener más información sobre el rendimiento, eche un vistazo a esta respuesta en el sitio de Game Dev.
fuente
No soy un experto en XNA de ninguna manera, así que corríjame si me equivoco, pero tenía la impresión de que realmente hay una optimización incorporada para situaciones como esta. Sé que puede establecer una distancia de renderizado y después de ese punto no representa nada, en su caso sería el terreno restante. Sin embargo, esto deja una ventaja bastante poco atractiva para su mundo renderizado, por lo que tendría que implementar algo como la niebla que tienen la mayoría de los juegos de mundo abierto.
fuente