Skip to content

Add .3ds (Autodesk 3D Studio) file format support#8

Open
fsalexandre wants to merge 1 commit into
6wheel:mainfrom
fsalexandre:feature/3ds-support
Open

Add .3ds (Autodesk 3D Studio) file format support#8
fsalexandre wants to merge 1 commit into
6wheel:mainfrom
fsalexandre:feature/3ds-support

Conversation

@fsalexandre

Copy link
Copy Markdown

Summary

Adds support for loading Autodesk .3ds (3D Studio) models. trimesh 4.x
has no built-in .3ds loader, so this ships a from-scratch chunk parser
(tds_reader.py) plus a 3DS -> OBJ converter (tds_to_obj.py) — mirroring the
existing .kn5 path (convert to a temp OBJ, then reuse _load_obj_with_real_groups
so real per-object names become UI parts and UVs feed the AO bake). No new
dependencies.

Sample output

A real Proton Bus Citiport model (.3ds) rendered through Ortho:

citiport orthographic blueprint generated from a .3ds file

Implementation notes

  • Z-up → Y-up: 3DS is Z-up while the renderer is Y-up. tds_to_obj bakes a
    rotation (x,y,z) -> (x,z,-y) (−90° about X — a proper rotation, det +1, so
    triangle winding is preserved). This is scoped only to the 3DS path; no
    other format and no global AxisConfig is touched.
  • Robust against corrupt input: non-finite vertex coordinates and
    out-of-range face indices are validated before writing and raise a clean
    ModelLoadError instead of a NaN-blanked render or a raw IndexError.
  • Duplicate object names are disambiguated (probed against all emitted names)
    so parts don't silently merge.
  • Registered .3ds in SUPPORTED_EXTENSIONS (also enables .3ds inside zips),
    the upload accept filter, and the docs.

Tests

test_3ds.py — happy path (a hand-encoded 3DS as an independent oracle) plus
corrupt-input / duplicate-name robustness cases.

🤖 Generated with Claude Code

trimesh 4.x has no built-in .3ds loader, so this adds a from-scratch
chunk parser (tds_reader.py) and a 3DS->OBJ converter (tds_to_obj.py),
mirroring the existing .kn5 path: convert to a temporary OBJ, then reuse
_load_obj_with_real_groups so real per-object names become UI parts and
UVs feed the AO bake. No new dependencies.

- 3DS is Z-up; the renderer is Y-up. tds_to_obj bakes a Z-up -> Y-up
  rotation (x,y,z)->(x,z,-y) (-90deg about X, a proper rotation so face
  winding is preserved), scoped ONLY to the 3DS path — no other format
  or the global AxisConfig is touched.
- Corrupt/truncated input is validated before writing: non-finite
  vertex coordinates and out-of-range face indices raise a clean
  ModelLoadError instead of a NaN-blank render or a raw IndexError.
- Duplicate 3DS object names are disambiguated safely (probed against
  all emitted names) so parts don't silently merge.
- Registered .3ds in SUPPORTED_EXTENSIONS (also enables .3ds inside
  zips), the upload accept filter, and the docs.
- test_3ds.py: happy-path (hand-encoded 3DS) + corrupt-input/duplicate
  -name robustness.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant