Marching Voxels





Tras hacer mi Trabajo de Final de Grado me quedé con las ganas de probar más cosas con los vóxeles; me parecen una herramienta capaz de dotar a los videojuegos de ciertas mecánicas muy especiales. Por ello decidí ponerme con este proyecto






Marching Cubes

Marching Cubes es un algoritmo de renderizado volumétrico que permite visualizar densidades de una manera muy eficiente y relativamente sencilla. Se analiza de manera secuencial la densidad tomando 8 puntos (los vértices de un cubo). En función de los valores de esos puntos y si están por debajo o por encima del nivel de superficie, generamos unos triángulos en función de una look-up table de 256 casos pregenerada. Así, podemos analizar cada cubo de manera totalmente aislada, lo que es idóneo para acelerar el algoritmo en la GPU usando un Compute Shader.

La densidad

La densidad es la información que usamos para construir nuestro volumen. Es básicamente una nube de puntos ordenada en el espacio, con una resolución idéntica para cada eje.
Es, de hecho, un campo. Puede contener informaciones tales como el viento, el campo eléctrico, gravedad, presencia de materia, etc. En base a esa información se renderiza la malla del volumen, y dicha información puede ser modificada en tiempo real con, por ejemplo, un Compute Shader.

La imagen de la izquierda es la densidad con la información de un campo escalar de Simplex Noise con valores entre 0 (negro) y 1 (blanco).

GridSize

Este valor nos habla de cuánta resolución en cada eje tiene nuestra densidad. Al ser por fuerza un sistema discreto, cuanta más resolución tenga, más exacta será la malla que se generará a partir de ella. El coste aumenta exponencialmente, con coste tanto temporal como espacial O(N^3).

Arriba podemos ver la densidad renderizada con una resolución de 8 por eje, abajo la resolución es de 32 por eje.

SurfaceLevel

Este valor entre 0 y 1 permite ajustar a qué nivel de la densidad se renderiza la malla. Los puntos donde el valor de densidad sea menor que el SurfaceLevel estarán dentro de la malla; donde sea mayor, estarán fuera de la malla.

En la imagen superior, el valor es 0.066; en la inferior, 0.238.

SmoothRendering

Por defecto la herramienta genera la malla con el método de triángulos independientes, lo que genera un efecto de superficie plana. Además, la estructura de triángulos independientes es sustancialmente más costosa de almacenar en la memoria. Si se activa la opción SmoothRendering, la malla generada tendrá una estructura de vértices compartidos de un solo grupo, con la normal interpolada entre los triángulos independientes que compartían dicho vértice, lo que hará que el motor de renderizado de Unity interpole la normal para cada triángulo, dando este aspecto de redondez. Sin embargo, el método de generación de vértices compartidos es bastante costoso computacionalmente, por lo que no se recomienda su uso en tiempo real, al menos cuando el número de triángulos es muy grande.

La imagen de la izquierda muestra una comparación entre ambos tipos de estructura.

CloseBorders

Ofrece la posibilidad de dejar abierta o cerrada la malla que se encuentra en la frontera de la densidad, más allá de la cual no hay información sobre el valor de la misma en cada punto del espacio. No supone un impacto en el consumo apreciable, más allá de la adición de unos triángulos extra al modelo cuando está activada.

A la izquierda, la imagen superior y la inferior solo se diferencian en que la de arriba tiene la opción de Close border activada. Se puede apreciar en la de abajo como ciertas partes no se renderizan por ser caras interiores, ya que el shader no renderiza a ambos lados.

Demostración

Renderizado de Simplex Noise 3D

VoxelRendering-SimplexNoise.mp4

Renderizado de geometría

VoxelRendering-Sphere.mp4