Skip to content

De dónde vienen los agujeros en las mallas generadas ​

Por Oleg Sidorkin, CTO y cofundador de Cinevva

La raíz del ala de un pájaro generado antes y después de la corrección: a la izquierda, una solapa gris con rendijas de color verde brillante; a la derecha, un pliegue limpio entre el ala y el cuerpo
Misma imagen, mismo generador, mismos ajustes. A la izquierda, lo que se publicaba hasta esta semana. A la derecha, lo que se publica ahora.

Generé un pájaro con TRELLIS.2, le hice el rigging y, en cuanto se reprodujo una animación, aparecieron agujeros bajo ambas alas. Eran rendijas brillantes a través de las cuales se podía ver directamente el interior del cuerpo. Primero culpamos al sistema de rigging, y sí tenía un problema propio, pero los agujeros ya estaban en la malla antes de que ningún hueso la tocara. Este artículo recoge la investigación que siguió: qué son realmente los agujeros, las nueve cosas que no los corrigieron, por qué y la única que sí funcionó. Incluyo los callejones sin salida a propósito. La mayoría son las soluciones obvias que cualquiera probaría, y cada una nos enseñó algo de lo que dependía la corrección final.

Primer paso: acordar qué es un agujero ​

Nuestro comprobador de mallas indicó que había cero aristas de contorno, y una prueba de paridad de rayos dijo que la superficie estaba cerrada. Así que le dije al equipo que la malla estaba limpia. No lo estaba, y la persona que había marcado las rendijas en rojo hizo bien en insistir. Una malla puede estar cerrada y aun así tener túneles. La única medida que los detecta es la característica de Euler, V menos E más F, que da el número de asas por componente conexa. El pájaro tenía 69. Todas las paredes de la exportación estaban duplicadas, de modo que una rendija en la pared exterior que conecta con la cavidad posterior es un asa, no una abertura, y nada que busque aristas abiertas llegará a detectarla.

Segunda lección, más vergonzosa: pasé un buen rato analizando píxeles oscuros en busca de agujeros, porque los agujeros son oscuros, hasta que me dijeron que mirara primero la imagen. Los agujeros eran brillantes. Eran rendijas por las que se veía la textura verde de la pared opuesta a través de un pliegue gris. Un algoritmo al que no has dirigido hacia lo correcto no te dice nada, y la forma más barata de dirigirlo es mirar.

Segundo paso: encontrar la etapa que los crea ​

TRELLIS.2 construye una malla en tres pasos. Un decodificador emite una superficie sin procesar a una resolución de 1024 al cubo. Una pasada de contorneado dual de banda estrecha la remalla. Un diezmador la reduce a cien mil caras y se hornea la textura. Volcamos la geometría después de cada paso y lanzamos el mismo conjunto de rayos a través de la raíz del ala en cada ocasión.

Todo empieza en la superficie sin procesar. Es una sopa de láminas abiertas: 266.242 bucles de contorno, la mayoría correspondientes a un único cuadrilátero ausente, y 65.371 aristas no múltiples. En la raíz del ala, un tercio de los rayos de prueba la atravesaron por completo. El rellenado de agujeros que se ejecuta a continuación no cierra casi nada: 144 caras de un total de cinco millones. El remallador trabaja con un campo de distancia sin signo porque no tiene alternativa. No dispone de un interior ni un exterior con los que trabajar, así que envuelve cada lámina con una fina envoltura desplazada. Por eso todas las paredes están duplicadas, separadas por unos cuatro vóxeles, y así es como cada franja porosa se convierte en un pliegue con una rendija. Después, el diezmado lo empeora, y además de forma aleatoria: la misma malla sin procesar, diezmada dos veces, produjo 69 y 107 túneles.

El pájaro con un mapa de calor de la densidad de aristas abiertas: el collar del cuello, las raíces de ambas alas, las caderas y las puntas de las plumas de la cola brillan; el cuerpo y la cabeza están limpios
Densidad de aristas abiertas en la extracción sin procesar. Solo se ilumina donde se unen las partes: el collar del cuello, las raíces de las alas, las caderas y las puntas de la cola. El cuerpo y la cabeza están limpios.

Ese mapa fue la primera pista de verdad. La porosidad no es aleatoria. Se concentra en todas las uniones entre partes y en ningún otro sitio.

Las cosas que no funcionaron ​

Las probamos más o menos en orden, empezando por las más obvias.

intentoresultado
resolución de 1536 en lugar de 1024peor en tres de los cinco modelos de prueba. Una mayor resolución capta más contactos finos, y cada uno es una unión nueva
la cadena de limpieza integradamás aristas no múltiples, no menos
rellenar todos los agujeros pequeños con MeshLibse rellenaron 266.000 bucles, pero la raíz del ala no cambió. La piel de esa zona nunca llegó a emitirse, así que no hay ningún bucle que rellenar
un remallado con signo a partir de un número de enrollamientofragmenta la malla en miles de componentes conexas. La salida sin procesar no tiene un interior al que asignar signo
una banda de contorneado más ancha, de 2 y 3 vóxelesmenos túneles en total, pero la rendija se ensancha en lugar de estrecharse. Los túneles pequeños se fusionan en otros grandes
cierre morfológico de la estructura de vóxelessolidifica la envoltura; después, el decodificador emite superficie dentro de cada vóxel interior: 4 veces más caras y 969 túneles
remallado global por vóxeles de la malla finalgénero 0 y rendija sellada. También suaviza todos los bordes de las plumas. Se rechazó nada más verlo, y con razón
sesgo del umbral de cruce del decodificadorlas aristas abiertas bajaron de 65.000 a 58.000. Ruido
completar los vóxeles vecinos ausentes560 casos en todo el pájaro. Ruido
Cuatro columnas: el pájaro original y tres versiones remalladas por vóxeles con radios crecientes; la raíz del ala, una ampliación de diez veces, una sección transversal, el pájaro completo y una vista desde abajo
El cierre global. La tercera columna sella la rendija y mantiene separados los dedos, pero también redondea todos los pliegues del pájaro. Así se ve una geometría «borrosa».

Vale la pena detenerse en el cierre global, porque es lo primero a lo que recurriría un modelador: aplicar un remallado por vóxeles con un tamaño apenas superior al hueco. Topológicamente, funciona. Pero también falsea el modelo. El generador produjo bordes de plumas nítidos y los estaríamos sacrificando a cambio de sellar la raíz del ala. Dos de los nueve intentos redujeron el número de túneles, y ambos se rechazaron en cuanto alguien miró el pájaro en lugar de la cifra.

Leer el código ​

Llegados a ese punto, la única opción honesta era dejar de tratar el decodificador como una caja negra y leer cómo se transforma su salida en una malla. TRELLIS.2 utiliza una representación llamada O-Voxel, y la extracción es breve. Cada vóxel activo contiene un vértice dual y tres logits, uno por cada arista de la cuadrícula que parte de su esquina, cada uno con el significado de «la superficie cruza esta arista». Un logit por encima de cero emite un cuadrilátero que conecta los cuatro vóxeles alrededor de esa arista. Si falta cualquiera de los cuatro, el cuadrilátero se descarta silenciosamente. Eso es todo. No hay ningún campo de signos, ninguna ocupación ni ningún concepto de interior o exterior en todo el modelo.

Modificamos el decodificador para volcar esos logits antes del umbral, usando el mismo pájaro, y los contamos.

Vecinos ausentes: 560 de 2,7 millones de vóxeles. Logits cercanos a cero: 8.600 de 8 millones. Ninguno de los dos es el problema. El problema aparece al observar las cuatro aristas alrededor de cada cara de la cuadrícula. Una superficie cerrada cruza el contorno de una cara un número par de veces. En 126.542 caras, el 2,3 % del total, los cuatro indicadores no concuerdan, y toda cara impar constituye por definición una arista abierta o no múltiple. Y discrepan con mucha seguridad. El indicador aislado de una cara con un solo cruce tiene un logit de +10, mientras que sus vecinos tienen -4. El coste mediano de invertir un indicador y restablecer la paridad es de 2,3 logits. No se trata de un umbral ligeramente desajustado. El modelo está seguro de una superficie que no puede cerrarse.

Tres columnas sobre un fondo oscuro: el pájaro exportado, la salida sin procesar del decodificador y una versión con el signo reparado. Con ampliaciones de diez y treinta veces, la unión del ala es una franja dentada y desgarrada en ambas versiones sin procesar
La salida sin procesar del decodificador en la raíz del ala; las zonas oscuras permiten ver a través. En la unión no faltan cuadriláteros. Es un peine.

Después medimos la propia franja, en el punto exacto de la superficie que nuestra cámara fija llevaba observando toda la semana. En un radio de doce vóxeles hay 2,1 veces más vóxeles activos de los que necesitaría una única lámina plana. En el pecho, como comparación, hay 1,2 veces más. La parte inferior del ala y el cuerpo son dos pieles que discurren dentro de una sola capa de vóxeles. La representación tiene un vértice por vóxel, por lo que no puede contener ambas. Durante el entrenamiento, la referencia para un vóxel de este tipo es un promedio por mínimos cuadrados de ambas pieles con indicadores de «cualquier cruce», algo que de por sí es incoherente, así que el modelo ha aprendido fielmente a emitir un peine en esa zona. El remallador envuelve el peine y lo convierte en una placa, y la placa tiene túneles.

El ancho de la franja se deduce de la geometría: aproximadamente un vóxel dividido por la tangente del ángulo de contacto. Dos superficies que se encuentran a noventa grados producen un pliegue de un vóxel y no causan problemas. Un ala pegada al cuerpo, pluma contra pluma, los dedos sobre el suelo: todos estos casos producen una franja de diez o quince vóxeles de ancho. Así se explica el mapa de porosidad.

Sí intenté la reparación basada en principios: inferir un signo de interior o exterior para cada esquina que explicara los indicadores de la mejor manera y, después, volver a derivarlos. No puede funcionar. El campo de signos solo existe en la envoltura de un vóxel emitida por el decodificador, y cualquier extensión fuera de esa envoltura se descontrola. Doce rondas duplicaron el número de vóxeles con basura.

Lo que haría un modelador ​

Un modelador nunca dejaría dos pieles separadas por una distancia mínima. Uniría el ala con el cuerpo y dejaría que hubiera un pliegue. El problema es que el cierre global hace eso en todas partes. Así que hay que hacerlo únicamente donde están las dos pieles.

El detector parte de una sola idea. Contar los vecinos activos de cada vóxel dentro de un radio de cuatro vóxeles. En una sola lámina, ese número es igual en todas partes y coincide con la mediana. Donde dos láminas comparten la misma capa, es aproximadamente el doble. Se marca todo lo que supere 1,5 veces la mediana, se expande el conjunto marcado un vóxel y se coloca un cubo unitario en cada posición. El espacio entre las pieles se vuelve sólido, la pasada de contorneado ve una única pared y ninguna otra parte del modelo se modifica.

Un recorte alrededor de la raíz del ala contorneado de tres formas: tal cual, con la zona de dos láminas rellenada con radio tres y con radio cuatro. Los puntos rojos marcan los vóxeles rellenados a lo largo de la costura. La costura dentada se convierte en un pliegue suave
Prueba de concepto en un recorte, antes de modificar el pipeline. El rojo marca los vóxeles rellenados. La costura dentada se convierte en un pliegue y las plumas de alrededor no se mueven.

Primero lo probamos en un recorte, usando MeshLib como sustituto del contorneado en la GPU. Cincuenta y tres componentes conexas y diecinueve asas se convirtieron en dos componentes y cinco asas. Después lo incorporamos al pipeline real, entre el decodificador y la exportación, y procesamos el mismo pájaro con el remallador y el horneado de texturas reales.

Cuatro columnas, primero con textura, después con geometría lisa y luego con una sección transversal: original, la misma salida del decodificador exportada tal cual y el relleno de dos láminas con radios tres y cuatro. La solapa gris y las rendijas verdes desaparecen en las dos últimas
El pipeline real. Las columnas uno y dos muestran la misma salida del decodificador con y sin un diezmado aleatorio. Las columnas tres y cuatro incluyen el relleno.
túnelesaristas no múltiplessolapa en la raíz del alaagujero en el lomo
tal cual79,5318presentepresente
relleno, radio 384,597desaparecidadesaparecido
relleno, radio 47238desaparecidadesaparecido

La solapa ha desaparecido. También ha desaparecido un segundo agujero en el lomo del pájaro, situado en la misma unión vista desde atrás, que ni siquiera estaba intentando corregir. Las plumas siguen separadas, los dedos siguen separados y la textura se hornea con normalidad porque los cubos quedan dentro de la envoltura, donde el volumen de atributos ya contiene datos. Añade seis segundos a un trabajo de cuatro minutos. Ahora está activado de forma predeterminada, con radio cuatro.

El pájaro completo de frente, de espaldas, desde abajo con textura y desde abajo con geometría lisa, en cuatro columnas: original, tal cual, relleno con radio tres y relleno con radio cuatro
El pájaro completo. El agujero blanco del lomo en las columnas uno y dos es la misma unión vista desde atrás. Todo lo que el generador hizo bien sigue presente en las columnas tres y cuatro.

Lo que esto no corrige y lo que nos revela ​

El número de túneles apenas cambió, y quiero explicar con sinceridad por qué. Los túneles restantes están en las puntas de las plumas y de los dedos, donde termina una parte fina y la pared duplicada se cierra al estrecharse. Son pequeños, no se ven y obedecen a un mecanismo distinto. El relleno se dirige a los contactos entre partes, que es donde estaban los agujeros visibles. La solución real está en una etapa anterior. Un decodificador que predijera signos por vértice en lugar de indicadores por arista sería coherente con la paridad por construcción, que es como funcionaba la generación anterior de este modelo y la razón por la que sus mallas eran estancas. Eso requiere un cambio en el entrenamiento, no es algo que podamos corregir durante la inferencia. Hasta entonces, de la fórmula de las franjas se desprenden dos consejos prácticos. Si estás generando un personaje, una pose en la que las extremidades estén separadas del cuerpo producirá una malla más limpia que otra en la que estén pegadas a él. Y si estás desarrollando sobre un generador como este, evalúa tus mallas con la característica de Euler y examina el resultado con tus propios ojos antes de confiar en una cifra. La cifra decía que estaba limpia. Se equivocó dos veces.

El decodificador instrumentado, los volcados de cada etapa, el análisis de paridad y el rellenado ya forman parte de nuestro pipeline, así que el próximo modelo que produzca agujeros recibirá el mismo tratamiento en cuestión de minutos, en lugar de una semana.