WhyHosted APIs are convenient until they are the bottleneck
SimplexGen's Make 3D button ran on fal's hosted Pixal3D endpoint. It worked, but it had three costs we could not control: a fixed per-run price, queue waits that sometimes stretched past nine minutes at peak, and an opaque failure mode when the account or the reference image was rejected. Everything downstream (mesh repair, simplification, paint, the studio agent) was waiting on a black box.
The Pixal3D team released code and weights under MIT, with the improved TRELLIS.2 backbone. That makes self-hosting legitimate as well as possible, so we did it.
PackagingAn open Cog image
The result is github.com/lee101/pixal3dcog, a Cog package with the same input names as fal's endpoint so a caller can switch providers without re-mapping parameters. The build does the unglamorous parts once:
- Compiles the TRELLIS.2 native extensions (nvdiffrast, nvdiffrec renderutils, CuMesh, FlexGEMM, o-voxel) for sm_80, sm_86, sm_89 and sm_90, so one image runs on A10, 3090, A40, 4090, L40S, A100 and H100 workers.
- Installs prebuilt flash-attn 2 and natten wheels for torch 2.6 / CUDA 12.4.
- Bakes all weights into the image: the Pixal3D cascade, the DINOv3 conditioner, MoGe-2 for camera estimation, BiRefNet for matting and the NAF feature upsampler. A cold worker loads from local disk instead of pulling roughly 12GB from the Hub.
- Runs as a normal cog HTTP server on a dedicated pod, or as a RunPod serverless handler that calls the predictor in-process when
RUNPOD_ENDPOINT_IDis set.
Outputs go straight to S3-compatible storage (we use Cloudflare R2) and the worker returns a URL, which keeps multi-megabyte GLBs out of the job response. Without storage configured it returns the file or a base64 payload.
SpeedWhat actually made it faster
Most of the win is not clever: flash-attn 2 instead of SDPA, TF32 on, natten compiled for the actual worker architecture (the only prebuilt wheel carried Hopper kernels and silently died on a 4090), and models kept resident wherever the card allows. On 24 GB cards the three 1.3B-parameter flow models plus decoders already fill 19 GB before a single activation, so the pipeline stages them per step instead; that costs a few seconds of PCIe traffic per job and is what makes a 4090 viable at all.
| Setting | GPU | Generate | Export | Total |
|---|---|---|---|---|
| 1536 cascade, 2048 texture | RTX 4090 (serverless, low-VRAM staging) | 145 s | 34 s | 186 s |
| 1024 cascade, 2048 texture | RTX 4090 (serverless, low-VRAM staging) | 134 s | 22 s | 163 s |
Timings are from the worker's own clock (September 2026, one run each, matting and camera estimation included). A worker that has just started spends another 200 s loading the 26 GB of weights from the Hub and onto the card before its first job; workers stay warm for two minutes after a job. On a 24 GB card the cascade has to stage models per step, which is why 1024 and 1536 are so close; a 48 GB worker keeps everything resident and is the next thing we will measure.
ReliabilityA provider chain, not a provider
SimplexGen now tries the self-hosted endpoint first, then fal's hosted Pixal3D, then fal's Tripo v2.5, then a local TRELLIS.2 worker. A reference image that no provider can fetch stops the chain immediately with a clear message instead of retrying the same failure three times. Long queue waits no longer time out at the edge either: the browser submits an async job and polls, so a nine-minute queue is just slow, not broken.
POST https://api.runpod.ai/v2/<endpoint>/run
{"input": {"image_url": "https://.../reference.png",
"resolution": 1536, "texture_size": 2048,
"decimation_target": 500000, "remesh": true}}
-> {"glb_url": "https://.../pixal3d/d969f5c6....glb",
"seed": 7, "resolution": 1536, "gpu_seconds": 403.1, "setup_seconds": 212.6,
"timings": {"preprocess": 5.5, "camera": 1.6, "generate": 145.5, "export": 33.7, "total": 186.3}}
CostPer-second GPUs change the pricing
RunPod bills serverless workers per second and scales them to zero. A 24 GB Ada worker is priced at a small fraction of a cent per second, so the 186 s full-quality run above costs on the order of five to eight cents of GPU time, and a cold start roughly the same again; the hosted endpoint we replaced charges about thirty cents per model regardless. That gap is what lets us keep image-to-3D on every paid plan and price API access below the hosted alternatives while still paying for the fal fallback when our own workers are busy.
The same image is listed in the app.nz cog catalogue as pixal3d, so anyone can run it on their own account, on their own GPU pool, with the same inputs.
NextMulti-view conditioning
Pixal3D ships multi-view weights that condition the cascade on several photos of the same object. We are experimenting with generating those extra views from the single reference with an image-edit model before the 3D pass. Early results are promising for backs of objects the single view never sees, and we will publish numbers once it is stable.
