[XNA] Austeridad geométrica en el render: Técnicas de culling

Un juego 3D incluye gran cantidad de modelos que sumados constituyen miles (o millones) de geometrías a renderizar. Dado que un juego tiene que ejecutarse en tiempo real, entre 30 y 60 fps, todo lo que hagamos debe ser óptimo, cualquier descuido o mala práctica puede convertir nuestro juego en una mala experiencia de usuario, y en definitiva en un fracaso técnico y comercial. Así pues, es clave optimizar el rendimiento.

Existen muchas técnicas para mejorar el rendimiento de un juego 3D. Quizá una de las más “directas” y fáciles de aplicar sea reducir el número de polígonos a procesar (que no siempre significa renderizar). Quiero decir que anque enviemos un montón de polígonos a la GPU, no necesariamente se van a renderizar todos, pero sí que esta perderá un montón de tiempo procesándolos (aplicando luz, aplicando Z buffers, etc). Así de sencillo. Lo bueno aquí es hacerlo sin que esto afecte a la calidad visual del juego en lo más mínimo. Sí, se puede hacer, con las distintas técnicas de culling de geometrías.

Existen múltiples técnicas de culling, vamos a conocer algunas de ellas.

 

Contribution culling

La técnica más fácil, implementada por defecto por la mayoría de engines 3D, y por supuesto también por XNA, consiste en no renderizar objetos que se encuentran tremendamente lejos, es decir, limitar el alcance de la cámara, o su “far clip”. Lo hemos hecho todos cientos de veces al inicializar una cámara con el método Matrix.CreatePrespectiveFieldOfView (de este tema ya hablé en un artículo anterior). Lo mismo pasaría con el “near clip”.

 

Backface culling

Consiste en NO renderizar los polígonos que no están orientados hacia la camara. Lo cierto es que la mayoría de engines 3D modernos como XNA, DirectX y OpenGL incorporan esta funcionalidad por defecto. Como comenta Jeff Weeks, la mitad de polígonos de un poliedro están de “espaldas” a la cámara, esto es, un 50% “directo” menos de polígonos a renderizar! En el artículo de Jeff podéis ver cómo funciona internamente esta técnica.

 

Frustum culling

En un post anterior escribí un ejemplo de funcionamiento de la optimización mediante Frustum Culling. Básicamente consiste en renderizar sólo los modelos que se encuentran dentro del frustum de la cámara. Con ello podemos tener un enorme mundo 3D en nuestro juego, pero sólo se renderizará aquella parte que sea visible por el jugador. Es una técnica muy fácil de utilizar, que creo que es imprescindible en cualquier juego 3D.

 

Occlusion culling

Consiste en no procesar los polígonos que se encuentran detrás de objetos opacos. Es decir, imaginemos que en nuestro juego el jugador está mirando a una pared, detrás de la cual (y dentro del frustum de la cámara), hay más objetos 3D. Si no hacemos nada, esos modelos 3D van a ser procesados igualmente por la GPU! Pues ahí es donde entran en escena los distintos algoritmos de Occlusion culling. Existen muchas formas de implementar esta idea, algunas de ellas con nombres verdaderamente fashion. De todos modos os recomiendo que antes que nada echéis un vistazo a este código, a veces unas líneas de código valen más que mil palabras, este se basa en la clase OcclusionQuery del XNA Framework. También es interesante la aplicación que el ejemplo hace del occlusion culling, que en este caso no la usa para optimizar el rendimiento. Ahí va el resumen de algunas técnicas de occlusion culling:

  • Portal rendering: Consiste en un sistema de occlusion culling basado en celdas conectadas por “portales”. Esto es, dividimos nuestro mundo 3D en celdas imaginarias o lógicas. Algunas de ellas se encuentran conectadas. Dicho esto, si tenemos las celdas 1, 2 y 3, sabemos que desde la 1 se ve la 2, y que desde la 2 se ve la 3, podemos saber que si el jugador se encuentra en la celda 1 no necesitamos renderizar la celda 3!
  • Potentially visible set (PVS): Podría decirse que es algo parecido al mecanismo anterior (al final que el objetivo es el mismo), sólo que los objetos potencialmente visibles / renderizables son calculados en tiempo de ejecución, lo cual puede suponer algo de tiempo de procesamiento. Un ejemplo de esto serían las rejillas de vóxels, de las que tengo un ejemplo en un artículo previo o los octrees.

 

En resumen, es interesante aplicar estas técnicas en nuestros juegos, y a ser posible hacerlo en una capa lógica distinta a la que pueda contener el gameplay, de forma que sea independiente de nuestro juego, facilitando la reutilización de este componente gráfico. Aplicando las técnicas de oclusión los juegos 3D deberían experimentar una notable mejora de rendimiento.

 

Para saber más:

Los libros que os recomiendo los he leído todos, y hablan del tema en mayor o en menor medida. Los enlaces han sido fuentes bibliográficas para este artículo.

3 comentarios en “[XNA] Austeridad geométrica en el render: Técnicas de culling”

  1. Un post muy interesante Jesús, esto nos viene a decir que “Lo difícil no es hacer juegos 3D, sino que estos vayan rápidos” y estas técnicas son las que marcan la diferencia entre desarrollos profesionales y no profesionales.

    Lo único que revisaría del post es donde has puesto “mayoría de engines 3D modernos como XNA, DirectX y OpenGL”, Engines 3D?

    Saludos crack.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *