Where the holes in generated meshes come from
By Oleg Sidorkin, CTO and Co-Founder of Cinevva

I generated a bird with TRELLIS.2, rigged it, and saw bright slivers under both wings when the animation played. The rigger was the first suspect. It had a separate problem, and the holes were already present in the unrigged mesh. We traced them through the generation pipeline and tested nine repairs before finding a local fill that closed the visible gaps without smoothing away the feather detail.
Step one: agree on what a hole is
Our mesh checker reported zero boundary edges, and a ray-parity test said the surface was closed. The slivers were still visible in the marked-up image. A mesh can be closed and still have tunnels. We used the Euler characteristic, V minus E plus F, to estimate the number of handles per shell. The bird's initial count was 69. Every wall in the export was doubled, so a slit in the outer wall connecting to the cavity behind it forms a handle. A boundary-edge check misses that kind of defect.
The first image analysis also looked in the wrong place. It searched dark pixels for holes, while the visible defects were bright slivers of the far wall's green texture showing through a grey fold. Checking the image established which pixels the analysis needed to follow.
Step two: find the stage that makes them
TRELLIS.2 builds a mesh in three steps. A decoder emits a raw surface at 1024 cubed resolution. A narrow-band dual contouring pass remeshes it. A decimator brings it down to a hundred thousand faces and the texture is baked. We dumped the geometry after each step and shot the same bundle of rays through the wing root each time.
The gaps are already present in the raw surface. It's a soup of open sheets: 266,242 boundary loops, most of them single missing quads, and 65,371 non-manifold edges. At the wing root a third of the test rays went straight through. The hole-fill that runs next adds only 144 faces out of five million. The remesher works on an unsigned distance field. With no inside or outside to work with, it wraps a thin offset shell around every sheet. That produces doubled walls about four voxels apart and turns each porous stripe into a fold with a slit in it. Decimation can make the result worse, with variation between runs: the same raw mesh decimated twice gave 69 and 107 tunnels.

The concentrations around the wing roots and other junctions gave us specific areas to investigate.
The things that didn't work
We tried them roughly in order of how obvious they were.
| attempt | result |
|---|---|
| resolution 1536 instead of 1024 | worse on three of five test models. More resolution resolves more thin contacts, each one a new junction |
| the built-in cleanup ladder | increased the non-manifold edge count |
| filling every small hole with MeshLib | 266k loops filled, wing root unchanged. The skin there was never emitted, so there's no loop to fill |
| a signed remesh from a winding number | shatters the mesh into thousands of shells. The raw output has no interior to sign |
| a wider contouring band, 2 and 3 voxels | fewer tunnels overall; the slit widens as small tunnels merge into larger ones |
| morphological closing of the voxel structure | solidifies the shell, the decoder then emits surface inside every interior voxel, 4x the faces, 969 tunnels |
| global voxel remesh of the final mesh | genus 0 and the slit sealed; feather edges softened too much to use |
| biasing the decoder's crossing threshold | open edges fell from 65k to 58k; the visible defect remained |
| completing missing neighbour voxels | affected only 560 cases in the whole bird; the visible defect remained |

Global closing sealed the wing root at a voxel size just above the gap, and it also rounded off the crisp feather edges. We rejected that result because of the lost detail. The wider contouring band had reduced the tunnel count too, while making the visible slit wider. Both attempts showed why we needed to compare the rendered bird alongside the topology measurements.
Reading the code
We then read the code that turns the decoder's output into a mesh. TRELLIS.2 uses a representation called O-Voxel. Each active voxel holds one dual vertex and three logits, one per grid edge leaving its corner, each meaning "the surface crosses this edge." A logit above zero emits a quad connecting the four voxels around that edge. If any of the four is missing, the quad is dropped silently. This extraction uses crossing flags without an inside/outside sign field.
We patched the decoder to dump those logits before the threshold, on the same bird, and counted.
There were 560 missing-neighbour cases out of 2.7 million voxels, and 8,600 logits near zero out of 8 million. The repair attempts targeting those cases had left the wing-root defect in place. We next checked the four edges around each grid face. A closed surface crosses a face's boundary an even number of times. On 126,542 faces, 2.3% of them, the crossing flags had odd parity, producing open or non-manifold edges. Some inconsistent flags had large logit margins: the lone flag on a count-one face sat at +10 while its neighbours sat at -4. The median cost to flip one flag and restore parity was 2.3 logits. Correcting these inconsistencies would require changing predictions well away from the threshold.

We measured the stripe at the wing-root point used in the earlier comparisons. Within twelve voxels of it there are 2.1 times as many active voxels as a single flat sheet would need. On the chest, the ratio is 1.2. The wing's underside and the body are two skins running inside one voxel layer. The representation has one vertex per voxel, so it cannot hold both. During training, the ground truth for such a voxel is a least-squares average of both skins with "any crossing" flags. That can produce inconsistent targets, which helps explain the serrated output at the junction. The remesher wraps that output into a slab with tunnels.
The width of the stripe follows from the geometry: roughly one voxel divided by the tangent of the contact angle. A steep contact confines the overlap to a narrow crease. At shallow contacts, such as a wing lying against a body, overlapping feathers or toes against the ground, the stripe can extend ten or fifteen voxels. That gives an explanation for the concentrations in the porosity map.
We also tried inferring a per-corner inside/outside sign that best explains the flags, then re-deriving them. That attempt failed. The sign field only existed on the one-voxel shell the decoder emitted, and extending it off that shell introduced spurious geometry. Twelve rounds doubled the voxel count without repairing the junction.
Filling the contact region
Joining the wing to the body would replace the narrow gap with a crease. The global closing had already shown that this could seal the slit. To preserve the feather detail, we needed to restrict the fill to the region where the two skins run close together.
The detector counts each voxel's active neighbours within four voxels and uses the median count as a baseline for a single sheet. Where two sheets share the layer, the count is about double. We flag anything above 1.5 times the median, grow the flagged set by one voxel, and place a unit cube at each flagged voxel. The cubes fill the space between the skins so the contouring pass can produce one wall. The fill is confined to the flagged region.

We tested it on a crop first, with MeshLib standing in for the GPU contouring. Fifty-three shells and nineteen handles became two shells and five. Then we added it between the decoder and the export and ran the same bird through the production remesher and texture bake.

| tunnels | non-manifold edges | wing-root flap | hole on the back | |
|---|---|---|---|---|
| as is | 79.5 | 318 | present | present |
| fill, radius 3 | 84.5 | 97 | gone | gone |
| fill, radius 4 | 72 | 38 | gone | gone |
The fill removed the wing-root flap and a second visible hole at the same junction on the bird's back. In this test, the feathers and toes stayed separate, and the texture baked normally because the cubes sat inside the shell where the attribute volume already had data. The fill added six seconds to a four-minute job. It's on by default now, at radius four.

Remaining tunnels
The tunnel count barely moved. The remaining tunnels are at feather tips and toe tips, where a thin part ends and the doubled wall pinches shut. They are small and were not visible in these renders. The fill targets contacts between parts, where the visible holes occurred, and leaves the tip defects unresolved.
Addressing the inconsistent crossing flags would require an upstream change. A decoder that predicts per-corner signs would be parity-consistent by construction, as in the previous generation of this model. Changing the decoder's prediction target requires retraining. For the current generator, the contact geometry suggests that poses with limbs standing away from the body should reduce this source of porosity. Mesh checks also need to cover several kinds of defects: boundary edges, tunnels and visible gaps. In this investigation, the boundary-edge check missed the tunnels, and lower tunnel counts sometimes accompanied worse-looking geometry.
The instrumented decoder, stage dumps, parity analysis and local fill are now in our pipeline. We can use them to trace defects in future models and check whether the same repair applies.