Blog Personal.

Conceptos Básicos, Feedback, Futuro

Trazado de Rayos vía Voxel, una «pequeña» explicación.

Debido a la polémica que parece que ha aparecido en el blog acerca del Trazado de Rayos vía voxeles en comparación con el Trazado de Rayos via triángulos he decidido buscar algo de informacion sobre el tema para ponerme al día y he dado con una entrada de un blog escrita en 2008 y precisamente dedicado al trazado de rayos donde compara una solución con la otra, pensad que dicha esta entrada se hizo mucho hace más de una década y lo que hace es comparar ambas técnicas en un entorno donde el hardware de intersección no existía y tampoco se había publicado el paper del Sparse Voxel Octree Global Illumination (SVOGI), simplemente la entrada habla de cuales son las ventajas de cada perspectiva.

Podeís encontrar el original aquí.

Los Octrees se pueden utilizar para acelerar el trazado de rayos y almacenar la geometría en un formato comprimido al mismo tiempo

Cita de un desarrollador de videojuegos (Rare) sobre el voxel octree:

Almacenar los datos en un Octree es de lejos más eficiente que almacenarlos utilizando texturas y polígonos (es básicamente compresión gratís para los datos de polígonos y texturas). Es principalmente «cool» debido a que paras de atraversarlo cuando el tamaño del pixel es más grande que la celula proyctada. Así que no necesitas tener todos tus datos en memoria, peor puedes hacer streaming de este bajo demanda. Esto significa que la cantidad de datos realmente es ilimitada o al menos los limites están en lo que puedan producir los artistas. Solo necesitas un grupo fijo de voxeles cargados para ver una escena y esto no cambia independientemente de lo grande que es la escena. El número de voxeles requerido es proporcional a la cantidad de pixeles en pantalla. ¡Esto es así independientemente la cantidad de datos que estés renderizando! Esto no es verdad para la rasterización a no ser que tengas una mágica visibilidad por pixel y un esquema de nivel de detalle que te permita recortar la cantidad de pixeles y vértices en el proceso, lo cual es imposible de conseguir en la práctica. Además que el Ray Casting te da automáticamente la información de la geometría que necesita ser cargada del disco. Así que es un «perfecto» sistema de streaming donde con la rasterización sería muy difícil cargar una escena de manera incremental dependiendo de lo que es visible (¡debido a que necesitas cargar la escena antes de saber lo que es visible!).

Si quieres modelar a un nivel de detalle de micrometro, adelante, no se va a cargar en memoria hasta que alguien haga un zoom lo suficientemente cercano para verlo. Los voxeles que no son interseccionados pueden ser echados fuera de la memoria. Por supuesto necesitas algún tipo de cache y echar fuera las cosas dependiendo de la utilización reciente de las mismas, pero desde que es jerarquico tu puedes cargar nuevos niveles en la jerarquia solo cuando se impacta sobre ellos.

.

Bueno, si estais confundidos os voy a explicar algunos puntos.

Para empezar un Octree como dice su nombre es una Estructura de Datos en Arbol donde cada subnivel de la jerarquia tiene 8 nodos de tal manera que la cantidad de voxeles del Octree serade 8n, tened en cuenta que el primer nivel es el 0 donde el Octree solo tendra un nodo, el segundo nivel es 81 donde tendremos unos 9 nodos en total (1+8), el tercer nivel es 82 donde tendremos unos 73 nodos (1+8+64) y así sucesivamente.

Lo podemos utilizar para almacenar la posicion de la geometria de la escena, lo cual es necesario para cualquier técnica de trazado de rayos, hay diferentes tipos de estructuras como los llamados BVH, KD-Trees, no solo esta el Octree. Pero con un poco de imaginación se puede ver el motivo por el cual el Octree es una estructura de datos que se puede utilizar con los voxeles donde voxel es el acronimo como habréis adivinado de Volume Pixels, ya que podemos hacer que cada voxel corresponda a un nodo.

.En la Voxelización de una escena tenemos dos posibilidades:

  • Dividir de manera regular toda la escena de tal manera que tengamos una cantidad fija de voxeles.
  • Voxelizar la escena según la geometría.

A lo que se refería el desarrollador de Rare es al segundo caso, para ello tenemos que utilizar nuestra imaginación y colocarnos visualmente en la escena, la parte de la escena tridimensional que tengamos más cerca a nivel de cámara será aquella donde la información de los nodos que se cargará atravesando el mayor nivel de niveles de la jerarquia posibles. Los más alejados se cargaran solo unos pocos nodos de su jerarquía y los que no estén a la vista simplemente no se cargarán. Hay que tener en cuenta que el Octree no almacena la geometría del fotograma sino de toda la escena como si se tratase de una maqueta de la misma.

El truco es utilizar el Ray Casting para comprobar que geometría va a ser visible de tal manera que podamos descartar el resto. El Ray Casting nos permite hacer una comprobación acerca de la geometría que realmente va a ser visible y descartarla de entrada, Es decir, no nos ponemos a hacer el trazado de rayos de entrada sino que una vez tenemos la escena voxelizada utilizamos el Ray Casting para comprobar que partes son visibles y cuales no.

Pero para ello necesitamos tener la información de la geometría de la escena de antemano .Esto nos permite cargar solo la geometría que es visible en cada fotograma y descartar de entrada la que es completamente inútil sin necesidad de algoritmos de descarte complejos que han sido una pesadilla durante años en lo que a la rasterización se refiere y lo mejor es explicar un poco el contexto histórico.

A lo máximo que se ha llegado es aplicar dos cambios en las GPUs con tal de eliminar la geometría superflua tanto antes del rasterizado como después del rasterizado.

Para antes del rasterizado lo que se ha creado es un mecanismo que nos permite marcar cada triangulo o conjunto de triángulos con un bit y luego ese mecanismo los borra de la lista y no llegan jamás a la unidad de rasterizado, este mecanismo es nuevo de la actual generación pero manualmente ha de ser el desarrollador quien realice el algoritmo via shaders de detección de triangulos superfluos.

Para después del rasterizado, lo que se ha hecho es que antes de rasterizar se ordena la geometría de la escena según su posición en pantalla, esto permite descartar los fragmentos (poligonos ya rasterizados) que se encuentran opacados por otros. Esto es lo que se llama Middle Sort porque se ordena la geometria en la mitad del pipeline gráfico.

Esto es sumamente importante porque sin esto la rasterización es capaz de dar color y por tanto texturizar fragmentos que no son visibles y por tanto texturizar varios fragmentos por pixel en un proceso llamado overdraw y todo porque la geometria de la escena se ordena al final como método convencional.

Es por eso que se dice que la rasterización escala de manera normal con el número de pixeles mientras que el trazado de rayos lo hace de manera logarítmica con los mismos.

El trazado de rayos necesita tener la información de la geometría de la escena almacenada para realizar el recorrido del rayo, la rasterización no lo utiliza para nada. Al tener la información de la geometría de la escena cuando un rayo impacta sobre un objeto inmediatamente descarta todo lo que hay detrás de manera automática, haciendo paradojicamente en el que se llegue a un punto concreto donde la rasterización no resulta una ventaja sobre el trazado de rayos.

Pero claro, aún no hemos llegado a ese nivel de complejidad donde la rasterización es un handicap. ¿Y por qué no? Pues porque las unidades de rasterizado son de función fija y por tanto sacan una cantidad fija no solo de fragmentos sino en cuanto a la cantidad de fragmentos por pixel que por estándar es de 16 pixeles por fragmento como máximo y esa cifra no la podemos aumentar.

SistemaRaster UnitsClk x trianMhzMtriangles MPixeles
PlayStation 3125502754400
Xbox 360115005008000
Wii U115505508800
Xbox One21853170627296
PlayStation 421800160025600
Xbox One X411172468875008
PlayStation 4 Pro41911364458304
Xbox Series X4118257300116800
PlayStation 54122308920142720

Las cifras son la cantidad de pixeles que generan la unidad de rasterizado como máximo para que sean texturizados durante el proceso posterior y se apliquen los efectos de Pixel/Fragment Shaders, Dicho máximo es fijo y no se puede superar ni acelerar de ninguna manera, el problema es que como os explique en la entrada de Nanite el hecho de hacer la geometría más pequeña no aumenta la cantidad de triangulos rasterizados pero si que disminuye la cantidad de pixeles que se envían para texturizado.

Este es el motivo por el cual juegos con una sobreteselación acaban teniendo un rendimiento pésimo llegado a un punto determinado, pasa a haber una cantidad ingente de geometria que el rasterizador no puede convertir en fragmentos y cuando lo hace no puede generar los suficientes pixeles en total por ciclo de reloj y el nivel de utilización de los shaders se va por los suelos porque recibe menos pixeles a tratar en la siguiente étapa.

Por lo que mientras estemos atados a la unidad de rasterizado de función fija no vamos a llegar al punto de densidad de la geometría donde la rasterización deja de tener ventaja. La contrapartida es que los juegos no tienen mecanismos de rasterizado por software, quitarla significaría que el 100% de los juegos actuales que se fian de una unidad de rasterizado de función fija simplemente no funcionarían y en consecuencia todo se iría al garete al no poder reproducir los juegos aparecidos en el mercado.

Por lo que es el huevo y la gallina, se coloca la unidad de rasterizado para la compatibilidad hacía atrás, lo que al mismo tiempo que facilita el trabajo a los desarrolladores que no tienen que preocuparse por realizar un mecanismo de rasterización por software.

Por lo que la única manera es aumentar la densidad de la geometría y ahí llegamos una singularidad. Una vez que la densidad de la geometría es lo suficientemente grande y por tanto los poligonos pasan a ser micropoligonos al ser tan o más pequeños que un pixel.

¿Que diferencia hay entre un micropolígono y un voxel? Decidme,

Por lo que podemos almacenar la nube de micropoligonos/voxeles en una estructura de datos espacial (En este caso un Octree) y cargar solo aquello dentro del Octree que es necesario en cada fotograma.

Pero la explicación no esta completa, volvamos a la entrada del blog que estabamos comentando, que la cosa no ha terminado.

Los Voxels tienen algunos beneficios muy interesantes en comparación con los polígonos:

Veamos cuales son y algunos os sorprenderán si tenemos en cuenta la reciente demostración del Unreal Engine 5.

Es una representación volumétrica, por lo que puede modelar detalles y protuberancias muy finas, sin necesidad de mapeo de protuberancias (bump mapping(. Los efectos de partículas como el humo, el fuego y la espuma se pueden procesar de manera eficiente sin usar hacks. Algunos grandes estudios de efectos especiales de Hollywood también están utilizando voxels para representar el cabello, la piel y el césped.

Que es lo que hemos visto gracias en el UE5 gracias a Nanite.

id quiere usar voxeles para renderizar todo estático con geometría real sin usar mapas normales.

Pensad que esta entrada es de 2008, lo que hace que a uno se le arranque una sonrisa que se haya necesitado más de una década para algo que por aquel entonces se creía que estaba cercano.

Los voxeles pueden almacenar un color y un normal. Para el renderizador, las texturas y la geometría son esencialmente las mismas.

¿Os acordáis de lo que os comente en la entrada The Next-Next Gen? Básicamente… ¿Que ocurre cuando un polígono es tan pequeño como un pixel? Pues que el termino mapeo de texturas desaparece ya que solo necesitamos almacenar un valor de color para el objeto que es el color del micropolígono/voxel, tened en cuenta que en el texturizado lo que hacemos es mapear una matriz de pixeles (u,v) en un poligono, pero cuando el poligono mide un solo pixel pues… Es decir, al llegar a cierto nivel de densidad de la geometría no solamente esta deja de ser una ventaja sino que se rompe por completo el pipeline ya que solo necesitamos darle color al vertice/micropoligono/voxel y lo podemos hacer antes del rasterizado.

La posición del vóxel se define implícitamente por la estructura que lo sostiene (el octree). Aquí está la parte buena: esta estructura representa tanto las primitivas que necesitan ser intersectadas como la división espacial de estas primitivas. Por lo tanto, en contraste con el trazado de rayos triangulares que necesita una estructura de división espacial separada (kd-tree, BVH, …), los vóxeles se estructuran de inmediato en una cuadrícula o un octree (esto no significa que otras estructuras no puedan ser utilizadas también). Entonces, para el trazado de rayos por voxel, los octrees son perfectos.

Paradojidamente los fabricantes de hardware y Microsoft han optado por la solución BVH y la del trazado de rayos por triangulo como opción.

Los vóxeles son primitivas muy baratos para la intersección, mucho más baratas que los triángulos. Este es probablemente su mayor beneficio al elegir entre el trazado de rayos voxel y poligonales.

Pero el estándar que se quiere implementar es el otro… ¿Motivo? El motivo lo se, pero no nos desviemos del tema.

  • Un voxel octree permite una multiresolución muy natural. No hay necesidad de profundizar en el octree cuando el tamaño de un píxel es mayor que la celda subyacente, por lo que no tiene que mostrar detalles si no es necesario y no tiene datos que no son visibles de ninguna manera .
  • Los Voxeles son extremadamente adecuados para efectos locales (voxel ray casting). A diferencia de la rasterización de triángulos, no hay problemas con la transparencia, la refracción, … También hay grandes beneficios a nivel artístico: debido a que los vóxeles son volumétricos, puede lograr efectos como la erosión, el envejecimiento de los materiales, el desgaste simplemente cambiando el valor iso.
  • El Ray Casting por voxeles es menos sensible a la complejidad de la escena que el basado en triángulos.
  • En cuanto a ordenar de cara al nivel de detalle, digamos que se almacenan los diferentes modelos de cada objeto en los diferentes niveles del Octree dependiendo del nivel de detalle necesario.

Parece que son el Santo Grial, no obstante tienen una serie de handicaps que han pesado mucho pero que mucho más a la hora de darle importancia a una solución u otra.

Memoria. Los conjuntos de datos de los Voxeles son enormes en relación con los datos de polígonos. Pero esto no tiene por qué ser un problema, ya que todos los datos se pueden transmitir. Sin embargo, esto crea nuevos desafíos cuando el punto de vista cambia rápidamente y se deben transmitir muchos nuevos bloques de datos a la vez. Los conjuntos de Voxels tienen el beneficio sobre los polígonos en los que se pueden cargar los subconjuntos de voxel, lo que permite algún tipo de refinamiento progresivo. Otras soluciones posibles son: usar discos duros más rápidos o unidades de estado sólido para acelerar la transmisión, limitar el recorrido de profundidad durante el movimiento rápido de la cámara o enmascarar la transmisión con desenfoque de movimiento o posprocesamiento de profundidad de campo.

Cuando Tim Sweeney habla de las ventajas del SSD se refiere a esto, al hecho de que podemos tener el Octree almacenado en el SSD y solamente tomar los nodos del mismo que son necesarios en cada fotograma. Esta técnica no es totalmente eficiente con un Disco Duro convencional cuya velocidad de transferencia de los datos es baja.

Y con esto llegamos a la madre del cordero, el que ha hecho que este no sea el trazado de rayos estándar.

La animación de voxels requiere herramientas especializadas.

El trazado de rayos por voxeles va muy bien en escenas donde los objetos no tienen animaciones complejas, Es por eso que la mayoría de ejemplos que dan con este tipo de renderizado suelen ser tour muy bonitos de casas virtuales o simplemente aplican la voxelización sobre los objetos no animados del escenario y por tanto los que son 100% estáticos pero esto se complementa con el siguiente punto.

Desventajas del trazado de rayos en general: los objetos dinámicos requieren que el octree se actualice en tiempo real. .

¿Que es un objeto dinámico? Cualquier que cambie su forma (que no posición) de un fotograma a otro. Esto son:

  • Personajes con una animación compleja.
  • Objetos antes estáticos que son rotados o su forma es manipulada, po ejemplo si destruimos parte del escenario o movemos los objetos del mismo.

Uno de los motivos por los que años más tarde Epic descartaría el SVOGI del Unreal Engine 4 pese a su prometida utilización es que para un solo personaje en pantalla en una GeForce 680 tomaba la friolera de 5ms, imaginaos con varios personajes en pantalla y todo porque la GPU es sumamente lenta a la hora de construir el Octree. ¿Cual era la solución? Habían dos soluciones para los fabricantes de hardware.

  • Utilizar el presupuesto en transistores y puerta lógicas en una unidad de función fija que realice ese trabajo.
  • Descartarlo y buscar otros métodos que es lo que han hecho optando por el BVH.

¿Y por qué el BVH? Pues porque el mismo mecanismo interno de la GPU que ordena la geometría antes del rasterizado se puede utilizar para crear un arbol BVH con ella a través de una unidad de función fija. Ni Nvidia ni AMD han hablado de ella de manera oficial pero sabemos que esta ahí porque sin ella todo el experimento no funcionaría. ¿Y como lo se? Pues porque el sistema necesita generar el BVH a través de los triangulos y eso no lo hacen los Shaders.

¿Pero cual de ellos es mejor? Bueno, el motivo por el cual se ha implementado uno y no el otro es por los costes a nivel de hardware de implementar una u otro. No tiene nada que ver con cual es mejor sino en cual es más barato de implementar en ese sentido y tiene más idem en lo que a la aplicación en videojuegos se refiere con enomes cantidades de objetos móviles en pantalla.

Es más, los juegos con el Voxel Ray tracing lo aplican sobre objetos estáticos del escenario y no sobre los dinámicos.

Pe… pero Urian, que dices, si la Demo del Unreal Engine 5 utiliza Trazado de Rayos por Voxeles.

El problema es que pensáis que uno excluye al otro cuando ambos son combinables en una especie de planteamiento híbrido. Es decir. el UE5 puede estar utilizando ambos al mismo tiempo y sin problemas. En todo caso el motor se acabará adaptando al hardware que haya en el mercado como paso con el UE5 que recibió el recorte a última hora del SVOGI.

Esto es todo, tenéis el Discord y los comentarios de esta entrada para comentarla.

0 0 vote
Article Rating
7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Tokra_Kree

Muy interesante el post Urian. Parece ser que estamos en una nueva generación en la que se experimentará con varias soluciones para generar una iluminación realista en los videojuegos, y será interesante ver que técnicas se imponen al final.

Además me ha despertado mucha curiosidad como funciona esa unidad de función fija que crea el BVH en las nuevas gráficas, y que es una gran desconocida.

Set

– Solo aclarar términos errados, SVOGI es el nombre comercial del Cryengine de Crytek los creadores de crysis. En UE4 llego de la mano de Nvidia con el nombre de VXGI, se saco por falta de potencia de la PS4 y one, pero se volvio a incluir años mas tardes con el nombre de VXGI 2.0 que estaba mas pulido y tenia 50% o el doble de mas rendimiento que la primera version. – No tengo constancia y conocimiento que el voxel interpuesto en la geometria de problemas en objectos animados para la iluminación , tenia entendido que los juegos… Read more »

Klayf

Cuando se presentó el UE4 con la demo elemental en 2012 Sweeney dijo que usaba svogi y luego se quitó por falta de potencia , cuando se mostró la misma demo en ps4, ya no se usaba.
El vxgi de nvidia vino después de eso, en la misma página de nvidia dicen que la demo del ue4 usaba una tecnica similar a la de ellos cuando se mostró.

Set

A ok, recordaba que VXGI llego antes, pero creo tienes razon y llego después.

Klayf

Parece que nvidia venía trabajando en ello por lo menos desde 2011, hicieron algunas presentaciones y papers en esa época, pero el vgxi salió un tiempo después. En 2012 epic usó una solución similar según dicen ellos acá
https://www.geforce.com/hardware/technology/vxgi/technology

Fran

Hola Urian! Queria ponerte algo en el buzon de sugerencias pero no me sale para publicar en esa entrada. Te lo pongo por aqui, espero q no te importe 😉 Hace unos meses por un comentario que hice hablaste de jim keller, snowden, con unos post muy interesantes. Desmitificabas un poco a Jim Keller, no porque fuese malo sino porque los medios lo tienen como el «creador» cuadno es mas bien quien plasma los diseños. Y he visto esta notificia me he arcordado de aquello jajaja https://elchapuzasinformatico.com/2020/05/las-primeras-cpus-intel-core-disenadas-por-jim-keller-son-los-alder-lake-s-10nm/ Coñas aparte, que opinion tienes las nuevas arquitecturas con nucleos willow cove, golden… Read more »

Lalilulelo

La presencia de la aceleración por GPU para el raytracing a polígonos debe ser para la geometría dinámica… Pero también para los reflejos no especulares. La demo de raytracing de Cryengine hace los reflejos a 1/4 de resolución sin recurrir a hardware dedicado. Para la geometría estática lo mejor es voxelizar en el editor y guardar el octree precalculado. Las sombras duras mediante raytracing serían un desperdicio comparado con stencil lighting, y hay mejores maneras de trazar sombras. Sin ir más lejos en Doom 3 BFG retiraron el stencil Lighting de Doom 3 por ser «ineficiente» para la época. Aun… Read more »