In partnership with

SnackOnAI Engineering | Senior AI Systems Researcher | Technical Deep Dive | November 13, 2026

The part that matters is quieter. The 2B model is the weaker product: Microsoft's own README tells you to skip text-to-3D, make an image first, and give that to the 1.2B image model instead. And going from 1.1B to 2B parameters improved the text model's scores by less than half a percent.

What made TRELLIS important wasn't scale. It was a representation, SLAT: a sparse set of occupied voxels, each carrying an 8-number feature, that one model can decode into three different 3D formats. Read the decoder code of this month's open 3D models and you'll find TRELLIS's choices almost line for line, down to "32 Gaussians per voxel, offset by tanh."

The promise: by the end you'll understand exactly how one image becomes a sparse voxel structure, then a structured latent, then a mesh or a splat in TRELLIS, why that template spread, and what you inherit if you deploy it today.

The fence: we read the TRELLIS repository (pipelines, samplers, all 12 model configs, the Gaussian and mesh decoders, the dataset toolkit) at 193e050 (October 27, 2026), and the CVPR 2025 paper for results, training compute and representation details. We didn't run the models. The Azure Foundry and NVIDIA model pages weren't fetched. TRELLIS's successor, TRELLIS.2 (December 2025, 4B, MIT), is covered only for context.

What It Actually Does

TRELLIS turns an image (or text) into a 3D asset in two generation stages and one decoding step. You choose the output format after generation.

Model

Params

Conditioning

Flow transformers (SS / SLAT)

TRELLIS-image-large

1.2B (incl. all VAEs)

DINOv2 ViT-L/14-reg, 518²

L: width 1,024, 24 blocks each

TRELLIS-text-base

342M

CLIP text

B: 768, 12 blocks

TRELLIS-text-large

1.1B

CLIP text

L: 1,024, 24 blocks

TRELLIS-text-xlarge

2.0B

CLIP text

XL: 1,280, 28 blocks

Released

December 2024 (image), March 2025 (text models, training code), MIT

Data

TRELLIS-500K: 500,777 assets, 95.9% from Objaverse-XL (Sketchfab 168,307 + GitHub 311,843), plus ABO, 3D-FUTURE and HSSD. Toys4k (3,229) held out for evaluation

Training (XL)

64 × A100 40 GB, 400K steps, batch 256

Outputs

3D Gaussians (32 per voxel), radiance field (CP rank 16, 8³ per voxel), mesh (FlexiCubes at 256³) → GLB

Hardware

NVIDIA GPU with ≥16 GB, Linux, tested on A100 and A6000

Speed

"about 10 seconds" per asset (paper, Figure 1)

Think of it as building with LEGO. First decide which studs on the baseplate get a brick, which gives you the shape. Then decide each brick's color and texture. Finally, render the result as a photo, a sculpture or a plastic model. TRELLIS does exactly those three things, in that order.

The Architecture, Unpacked

What to notice: the only thing shared across formats is SLAT, a few tens of thousands of positioned 8-number features. Each output format is just a different decoder trained on the same latent.

Four decisions define TRELLIS, ranked.

One: separate where from what. Stage one generates only occupancy, on a dense 16³ latent (8x smaller than the 64³ grid) where a plain transformer works. Stage two only fills in features where stage one put voxels. The paper reports an average of about 20K active voxels, so stage two works on ~8% of the grid.

Two: build the latent from 2D foundation features. During training, each asset is rendered from 150 views, each render is encoded by DINOv2, and every voxel averages the features of its projections. The VAE then compresses those 1,024-dim averages to 8 numbers per voxel. Rich appearance comes from a model that has seen billions of images, not from 3D data alone.

Three: one latent, many decoders. Gaussians, radiance fields and meshes each get their own sparse-transformer decoder. The mesh decoder upsamples each voxel to a 4³ block for a 256³ FlexiCubes grid.

Four: rectified flow with CFG on both stages. Plain Euler sampling with logit-normal timestep training. The demo defaults to 12 steps per stage, the paper's evaluation to 50.

The Code, Annotated

Snippet one: the two-stage handoff (excerpt from trellis/pipelines/trellis_image_to_3d.py, our comments marked # SnackOnAI:).

def sample_sparse_structure(self, cond, num_samples=1, sampler_params={}):
    flow_model = self.models['sparse_structure_flow_model']
    reso = flow_model.resolution                                   # SnackOnAI: 16, a dense 16³ latent
    noise = torch.randn(num_samples, flow_model.in_channels, reso, reso, reso).to(self.device)
    z_s = self.sparse_structure_sampler.sample(flow_model, noise, **cond, **sampler_params).samples
    decoder = self.models['sparse_structure_decoder']
    coords = torch.argwhere(decoder(z_s) > 0)[:, [0, 2, 3, 4]].int()   # ← THIS is the trick: the 3D-conv
    return coords                                                      #   decoder's logits > 0 become the
                                                                       #   sparse voxel list for stage two
def run(self, image, ..., formats=['mesh', 'gaussian', 'radiance_field']):
    cond = self.get_cond([image])
    coords = self.sample_sparse_structure(cond, num_samples, sparse_structure_sampler_params)
    slat = self.sample_slat(cond, coords, slat_sampler_params)    # SnackOnAI: noise only on occupied voxels
    return self.decode_slat(slat, formats)                         # SnackOnAI: decode to any subset of formats

The shape is fully decided before any appearance exists. Stage two can't add a missing handle or remove a floater. Most "TRELLIS got the geometry wrong" failures happen in the first 12 steps.

Snippet two: 32 Gaussians per voxel (excerpt from decoder_gs.py).

self.layout = {
    '_xyz': {'shape': (self.rep_config['num_gaussians'], 3), ...},   # SnackOnAI: num_gaussians = 32 (config)
    ...
}
if k == '_xyz':
    offset = x.feats[x.layout[i]][:, v['range'][0]:v['range'][1]].reshape(-1, *v['shape'])
    offset = offset * self.rep_config['lr'][k]
    if self.rep_config['perturb_offset']:
        offset = offset + self.offset_perturbation                 # SnackOnAI: fixed per-slot jitter, so the
                                                                   #   32 children don't start on top of each other
    offset = torch.tanh(offset) / self.resolution * 0.5 * self.rep_config['voxel_size']   # ← THIS is the trick:
    _xyz = xyz.unsqueeze(1) + offset                                                       #   Gaussians are
                                                                                           #   bounded to ~1.5 voxels

Compare this with Idol's decoder from our last issue: offset = torch.tanh(offset) * 0.5 * config['perturbe_size'] * offset_scale, with 32 Gaussians per anchor, a learned perturbation and a per-attribute lr table. The lineage is visible in the code.

Snippet three: multi-image conditioning without training (excerpt, same pipeline file).

if mode == 'stochastic':
    cond_indices = (np.arange(num_steps) % num_images).tolist()   # SnackOnAI: 12 steps, 3 views → 0,1,2,0,1,2…
    def _new_inference_model(self, model, x_t, t, cond, **kwargs):
        cond_idx = cond_indices.pop(0)
        cond_i = cond[cond_idx:cond_idx+1]                         # ← THIS is the trick: each denoising step
        return self._old_inference_model(model, x_t, t, cond=cond_i, **kwargs)   #   sees ONE view in rotation
elif mode == 'multidiffusion':
    ...
    pred = sum(preds) / len(preds)                                 # SnackOnAI: or average all views' velocities

A single-view model is made multi-view by alternating which photo guides each step. It's clever and free, but the README warns it "may not give the best results," and with more views than steps, some views are never seen at all.

Snippet four: our arithmetic (from the configs, the dataset table and the paper).

objaverse = 168_307 + 311_843
print(f"Objaverse-XL share of TRELLIS-500K: {objaverse / 500_777:.1%}")        # 95.9%
print(f"training renders: {500_777 * 150 / 1e6:.0f}M (150 views per asset)")   # ~75M Blender renders + DINOv2 passes
print("stage one: 64³ occupancy", 64**3, "cells → 16³ × 8 latent =", 16**3 * 8, "numbers (8x smaller)")
print("Gaussians: avg", 20_000 * 32, "| cap", 32_768 * 32)                      # 640,000 | 1,048,576
print("transformer passes, demo:", (12 + 12) * 2, "| paper eval:", (50 + 50) * 2)   # 48 | 200 (CFG doubles)
print(f"XL over L (text): CLIP +{26.70/26.60 - 1:.2%}, FD_dinov2 −{1 - 237.48/238.60:.2%}")   # +0.38%, −0.47%

The data pipeline costs far more than inference: about 75 million renders and DINOv2 passes just to build the training latents.

It In Action

Input: one product photo of a wooden chair, TrellisImageTo3DPipeline with microsoft/TRELLIS-image-large, demo defaults (seed 0, 12 + 12 steps, CFG 7.5 / 3.0), on an A100.

Step one, condition. rembg removes the background, then the object is cropped and resized to 518×518. DINOv2 ViT-L/14 with registers produces 37 × 37 patches + 1 CLS + 4 registers = 1,374 tokens × 1,024.

Step two, structure. 12 Euler steps with CFG run on a [8, 16, 16, 16] noise tensor: 4,096 tokens, 24 passes. The 3D-conv decoder upsamples to 64³, and cells with a positive logit become coordinates, typically around 20,000 voxels.

Step three, latent. 12 more CFG steps run on those voxels only, patched 2³ inside the transformer, giving 8 features per voxel.

Step four, decode and export. The Gaussian decoder produces about 640,000 Gaussians (32 per voxel). The mesh decoder runs FlexiCubes at 256³. to_glb simplifies the mesh by 95% and bakes a 1,024² texture from the Gaussians.

Output (numbers from the paper, the configs and our arithmetic):

Stage

Tokens or elements

Passes

Notes

Condition

1,374 DINOv2 tokens

1

518² input

Sparse structure

4,096 (16³)

24

CFG 7.5

SLAT

~20K voxels, patched 2³

24

CFG 3.0

Gaussians

~640K (cap 1,048,576)

1

32 per voxel

Mesh

256³ FlexiCubes

1

then simplify 95%, bake 1,024²

Total

48

"about 10 seconds"

Toys4k, image-to-3D (paper Table 2, lower FD is better)
 FD_dinov2   InstantMesh ██████████████████████████  264.36
             TRELLIS L   ███████                       67.21
 user study  TRELLIS chosen in 94.5% of image-to-3D trials (1,277 / 1,352)

On its own benchmark and user study, the image model wasn't close to the 2024 baselines. That gap, not the parameter count, is why TRELLIS became the reference point.

Why This Design Works (and what it trades away)

It works because sparsity matches 3D. Objects are surfaces, not volumes. With ~20K of 262,144 voxels active, stage two spends compute only where there's something to describe, and the 8-channel latent reconstructs at 32.74 dB PSNR (paper, Table 3).

It works because 2D features do the heavy lifting. Aggregating DINOv2 features from 150 renders gives every voxel a semantic, appearance-aware description before the VAE compresses it. The generator learns from a latent that already "looks like" something.

It works because formats are decoders, not models. Adding a new output format means training a decoder on frozen SLAT, not retraining the generator.

It trades away resolution. Everything lives on a 64³ grid. The mesh decoder reaches 256³ by subdividing voxels, but thin structures thinner than a voxel, fine text and sharp mechanical edges are limited by the grid. TRELLIS.2 moved to grids up to 1536³ to fix exactly this.

It trades away second chances. Stage two can't fix stage one. The occupancy decision is final.

It trades away material realism. Gaussians and the baked texture carry diffuse color only. There's no PBR (roughness, metalness), which TRELLIS.2 added.

It trades away easy deployment. Linux only, ≥16 GB of VRAM, and a CUDA build of spconv, kaolin, nvdiffrast, diffoctreerast, mip-splatting and flash-attn. The setup script exists because the dependency graph is the hard part.

Technical Moats

  • The data pipeline. 500K curated assets, aesthetic scoring, 150-view rendering and DINOv2 feature aggregation, about 75M renders in total. Microsoft released the toolkit and the asset list, but not the compute.

  • The custom renderers. diffoctreerast (a differentiable octree renderer built for TRELLIS), modified FlexiCubes with vertex attributes, and mip-splatting integration. Months of graphics engineering that most ML teams can't reproduce quickly.

  • First-mover status as the template. Sparse structure first, latent second, 32 Gaussians per local unit, tanh-bounded offsets: later open models adopted the recipe, which makes TRELLIS the baseline everyone compares against.

Insights

One: the "2 billion parameter" model is the one Microsoft tells you not to use. The 2.0B XL model is text-only. Against the 1.1B text-large model it improves CLIP score from 26.60 to 26.70 and FD_dinov2 from 238.60 to 237.48: under 0.5% for 80% more parameters. The README recommends generating an image with a text-to-image model and passing it to the 1.2B image model instead, because "text-conditioned models are less creative and detailed due to data limitations." Data, not parameters, was the limit, and the image path borrows its data from 2D generators.

Two: "MIT licensed" describes the weights and most code, not the asset you ship. The training set is 95.9% Objaverse-XL, whose Sketchfab and GitHub assets carry their own mixed licenses. The README also notes that key submodules (diffoctreerast, derived from Inria's rasterizer, and the modified FlexiCubes) carry their own licenses, and the mesh export path depends on NVIDIA's nvdiffrast and kaolin. For a game studio, read those licenses and settle the provenance question before a TRELLIS mesh reaches a shipped product.

Surprising Takeaway

The most influential number in open 3D generation might be 32. TRELLIS decodes 32 Gaussians per voxel, bounded by tanh around the voxel center, with a fixed perturbation per slot. TripoSplat and Idol, released 17 and 22 months later, decode 32 Gaussians per anchor with the same tanh-bounded, perturbed-offset pattern. TRELLIS's training cap of 32,768 voxels × 32 = 1,048,576 Gaussians is exactly Idol's advertised maximum. The field moved from fixed voxels to learned density, but it kept TRELLIS's decoder.

TL;DR For Engineers

  • TRELLIS is two rectified-flow transformers (a dense 16³ structure stage, then a sparse latent stage on ~20K voxels) plus three decoders: 32 Gaussians per voxel, a CP-rank-16 radiance field, and a 256³ FlexiCubes mesh.

  • Use TRELLIS-image-large (1.2B). The 2B text model is less than 0.5% better than the 1.1B one, and Microsoft recommends text → image → TRELLIS-image instead.

  • The demo runs 12 + 12 steps with CFG, 48 transformer passes, "about 10 s" on an A100. It needs ≥16 GB of VRAM, Linux, and several CUDA extensions.

  • Geometry is final after stage one, and resolution is bounded by the 64³ grid. Expect soft thin parts and no PBR materials.

  • Check Objaverse-XL provenance and the submodule licenses before commercial use, and look at TRELLIS.2 (4B, MIT, PBR, 1536³) for new projects.

Explain It Like I'm New

Making a 3D model of an object, for a game, a product page or a simulation, usually takes an artist hours. TRELLIS tries to do it from a single picture in about ten seconds.

The trick is splitting the job in two. First, the model decides the object's shape by filling in a coarse 3D grid of cubes, like deciding which spots on a LEGO baseplate get a brick. Then, only for the cubes that are filled, it decides what each one looks like, its color and surface detail, as a short list of numbers.

That second step produces a compact description of the object that isn't tied to any one 3D file format. Separate decoders can turn the same description into a mesh (the triangles games and 3D software use), a Gaussian splat (a cloud of soft blobs that renders realistically), or a radiance field (a format that is good for realistic lighting views).

To learn what objects look like, TRELLIS borrowed knowledge from an image model trained on enormous numbers of photos, then learned 3D structure from about half a million 3D models.

Its biggest legacy may be the recipe itself: newer 3D generators from other companies follow the same basic plan.

See It In Action

  • TRELLIS live demo, Microsoft on Hugging Face Spaces. Try image-to-3D. Upload a photo, adjust the two stages' steps and guidance, and download the GLB or Gaussians. The fastest way to see where stage one gets geometry wrong.

  • TRELLIS project page, Microsoft Research. Watch the results. Interactive comparisons, local editing and variant generation, plus the same asset decoded into all three formats.

  • TRELLIS.2 release coverage, ComfyUI Wiki. Read what changed. The 4B successor with O-Voxel, PBR materials and grids up to 1536³, the clearest view of TRELLIS's limits from the team itself.

Community Conversation

  • Jianfeng Xiang, Jiaolong Yang and co-authors (Microsoft Research, Tsinghua, USTC), the paper. The XL model was trained on 64 A100s for 400K steps. Their own user study preferred TRELLIS in 67.1% of text-to-3D and 94.5% of image-to-3D trials, a sign of how much stronger the image path is.

  • TRELLIS maintainers, README note on text-to-3D. The recommendation to route text through a text-to-image model first is an unusually candid admission that the text models are data-limited.

  • InpaintSLat authors, Inpainting Structured 3D Latents via Initial Noise Optimization. An example of SLAT becoming a platform: research now builds editing methods directly on TRELLIS's latent space rather than on raw meshes.

  • Speridlabs and VAST, Idol and TripoSplat. Their decoders replace TRELLIS's fixed voxel grid with learned octree density but keep its 32-Gaussians-per-unit decoding pattern, and both report TRELLIS as a baseline.

Conclusion: The Representation Outlived the Model

TRELLIS's image model was a large jump over 2024's baselines, and its text models taught an honest lesson about data limits. Its lasting contribution is SLAT: sparse structure first, local latents second, many decoders after. That recipe now underpins TRELLIS.2, TripoSplat and Idol. For a new production pipeline in late 2026, look at TRELLIS.2 for PBR and higher resolution. Use TRELLIS-image-large when you need the most-studied, most-compared open baseline, and read the asset and submodule licenses before anything you generate ships.

References

TRELLIS generates a sparse 64³ voxel structure, then an 8-number latent on each occupied voxel, and decodes that SLAT into Gaussians, radiance fields or meshes. Its image model outperformed 2024 baselines by a wide margin, while its 2B text model improved on the 1.1B one by under 0.5%. Its decoder design, 32 tanh-bounded Gaussians per voxel, lives on in TripoSplat and Idol.

Sponsored Ad If you enjoy practical AI insights, check out SnackOnAI and support the newsletter by subscribing, sharing, and exploring our sponsored ad—it helps us keep building and delivering value 🚀

Sales Owns Retention, Not Just Closed Deals

Pebl’s Chief Business Officer, Dutta Satadip, joins The GTM Garage to show how Pebl merged Operations and GTM under one leader, and how it aligned goals and incentives across the customer lifecycle.

You’ll also see how Pebl uses AI across that lifecycle and the stack behind prospecting, pipeline, and handoff to onboarding.

15 min conversation. 15 min open Q&A. For Seed to Series A teams.

Recommended for you

View all
caret-right