Skip to main content

High-performance OBJ merge and texture atlas pipeline

Project description

almeshmerge

High-performance OBJ merge and atlas generation library.

Build

chcp 65001 && uv build --wheel --out-dir dist

Local Build Matrix (Windows host + Docker Desktop)

Use this when you want to avoid GitHub Actions quota and build all wheels locally.

Target matrix:

  • Windows: cp311, cp312, cp313, cp314
  • Linux (manylinux via Docker): cp311, cp312, cp313, cp314

One-command build:

powershell -ExecutionPolicy Bypass -File .\scripts\build_local_wheels.ps1

The script will:

  • build Windows wheels with local Python 3.11~3.14
  • build Linux wheels with cibuildwheel in Docker
  • copy all wheels to a host folder like artifacts/wheelhouse/<timestamp>

Optional arguments:

# custom output folder on host
powershell -ExecutionPolicy Bypass -File .\scripts\build_local_wheels.ps1 -OutputDir "D:\wheel-output"

# build only Linux wheels
powershell -ExecutionPolicy Bypass -File .\scripts\build_local_wheels.ps1 -SkipWindows

# build only Windows wheels
powershell -ExecutionPolicy Bypass -File .\scripts\build_local_wheels.ps1 -SkipLinux

# build then upload from host (requires host-side PyPI credentials)
powershell -ExecutionPolicy Bypass -File .\scripts\build_local_wheels.ps1 -UploadToPyPI

If you prefer manual upload, run:

powershell -ExecutionPolicy Bypass -File .\scripts\upload_wheels.ps1 -WheelDir ".\artifacts\wheelhouse\<timestamp>"

CI Release (GitHub Actions)

  • Workflow: .github/workflows/release.yml
  • Trigger:
    • Push tag: v* (recommended, for example v0.1.29)
    • Manual run: workflow_dispatch
  • Build matrix:
    • OS: Linux (ubuntu-latest) and Windows (windows-latest)
    • Python: 3.11, 3.12, 3.13, 3.14 (wheel via cibuildwheel)
  • Publish:
    • Uses PyPI Trusted Publisher (OIDC), no API token required in repository secrets.
    • A pre-publish guard checks that tag version matches pyproject.toml version.

Recommended release commands:

git tag v0.1.29
git push github v0.1.29

If a run fails due to transient CI issues, rerun the failed jobs from the GitHub Actions UI or use workflow_dispatch.

Python API

from almeshmerge import merge_obj_to_atlas

result = merge_obj_to_atlas(
    input_objs=["a.obj", "b.obj"],
    output_dir="out",
    split_o=True,
    split_g=True,
    atlas_max_size=8192,
    atlas_padding=4,
    atlas_pow2=True,
    atlas_allow_rotate_90=True,
    atlas_max_count=0,
    spatial_cluster_radius=-1.0,
    atlas_target_utilization=0.92,
    uv_repeat_exclude_merge=True,
    simplify_ratio=0.8,
    vertex_key_mode="pos",  # default: keep topology vertex count stable
)
print(result)

Parameters

  • split_o: Whether to split by o objects.
  • split_g: Whether to split by g groups.
  • front_axis / up_axis: Input axis convention, defaults to Y-front and Z-up.
  • right_handed: Use right-handed axis transform.
  • atlas_max_size: Max atlas side length.
  • atlas_padding: Padding pixels between packed textures.
    • Default is 4.
    • For Blender viewport preview, 8 or higher is often safer if you see tile-edge bleed.
    • In Blender, prefer Image Texture Extension=Extend or Clip for atlas materials.
  • atlas_pow2: Force atlas width/height to powers of two.
  • atlas_allow_rotate_90: Allow 90-degree placement rotation.
  • atlas_max_count: Max number of generated atlases (0 means unlimited).
  • spatial_cluster_radius: Spatial clustering radius for unit-wise texture packing (<=0 disables clustering).
  • atlas_target_utilization: Target utilization threshold used to trigger extra packing refinement.
  • uv_repeat_exclude_merge: Exclude UV-repeat units from merge and keep them as original textures.
  • simplify_ratio: Mesh simplification ratio before export.
  • vertex_key_mode: Export dedup key mode. pos is default and keeps topology vertex count stable while writing split v/vt/vn indices; pos_uv ignores normal in dedup; full keeps position+UV+normal in a unified index.

Diagnostics for Atlas Stability

merge_obj_to_atlas() now returns extra diagnostics that help locate parameter-sensitive texture issues:

  • diagnostics.atlas_rot90_count / diagnostics.atlas_rot90_ratio
  • diagnostics.uv_edge_01_hits / diagnostics.uv_near_edge_hits
  • compose_diagnostics.crop_size_mismatch_count
  • compose_diagnostics.crop_size_mismatches (first 20 samples)

Interpretation:

  • crop_size_mismatch_count == 0 means C++ crop estimation and Python crop execution are consistent.
  • uv_edge_01_hits == 0 means remapped UVs do not collapse to exact 0/1 boundaries.
  • Large changes in atlas_rot90_ratio across parameter sets are expected and indicate different packing paths.

Regression Matrix (Recommended)

For Blender preview stability, run at least:

  • atlas_padding: 4, 8
  • atlas_max_size: 2048, 4096, 8192

Pass criteria:

  • No visible large-scale texture scramble in Blender.
  • compose_diagnostics.crop_size_mismatch_count == 0.
  • diagnostics.uv_edge_01_hits == 0.

 

本地构建

# 构建全部 8 个 wheel
.\scripts\build_local_wheels.ps1

# 只构建 Windows
.\scripts\build_local_wheels.ps1 -SkipLinux

# 只构建 Linux
.\scripts\build_local_wheels.ps1 -SkipWindows

# 上传(自动找最新构建目录)
.\scripts\upload_wheels.ps1

# 构建完直接上传
.\scripts\build_local_wheels.ps1 -UploadToPyPI

本地构建 Debug 版本

# 仅构建
.\scripts\build_debug_wheel.ps1

# 构建并上传
.\scripts\build_debug_wheel.ps1 -UploadToPyPI

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

almeshmerge-0.1.48-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (440.1 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

almeshmerge-0.1.48-cp313-cp313-win_amd64.whl (141.7 kB view details)

Uploaded CPython 3.13Windows x86-64

almeshmerge-0.1.48-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (440.1 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

almeshmerge-0.1.48-cp312-cp312-win_amd64.whl (142.5 kB view details)

Uploaded CPython 3.12Windows x86-64

almeshmerge-0.1.48-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (440.6 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

almeshmerge-0.1.48-cp311-cp311-win_amd64.whl (142.0 kB view details)

Uploaded CPython 3.11Windows x86-64

almeshmerge-0.1.48-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (440.5 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

File details

Details for the file almeshmerge-0.1.48-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for almeshmerge-0.1.48-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 f117b3012ca96919a7a0e85db89b925044bb56ff9ef15c197951f9db6e189beb
MD5 3d45c7e8ab6a5d31738ae6d99d8e0fe4
BLAKE2b-256 272bbc57ad398c4725494250c9e7fea9fcf816a870c6db0b1e8b0476f6ecba1a

See more details on using hashes here.

File details

Details for the file almeshmerge-0.1.48-cp313-cp313-win_amd64.whl.

File metadata

File hashes

Hashes for almeshmerge-0.1.48-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 514c80af3533be450d5f154f0cc8cc0506c5d83da6766fb8e0d2fa638089f202
MD5 5b790f09d0246e03129d6803e22b4f72
BLAKE2b-256 abe11ae88c8d230fbf331a4d693aa01f17eeee55e2d3fdab5c6b7ec6db9afcec

See more details on using hashes here.

File details

Details for the file almeshmerge-0.1.48-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for almeshmerge-0.1.48-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 099c587f944fd45446fb3ee780ebe40bebe0ddbd6a40a3b6afbe5d746a2e82d0
MD5 6f6a20af748de3ecef244ef7d0f347d6
BLAKE2b-256 b6ceb14b940c8886f02646eded5f3c31813dcfcbef50f3f863286031caf62fb5

See more details on using hashes here.

File details

Details for the file almeshmerge-0.1.48-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for almeshmerge-0.1.48-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 c9c0a1b795b63a63ae1daa057e470b403845d46a746f3814b2519af1beff43a2
MD5 729d94b3bf383aaabf9311fef8491108
BLAKE2b-256 629e1025311039c3604b0471b3cfd78e3fbf4f98750433adb3cfe1639353d2c6

See more details on using hashes here.

File details

Details for the file almeshmerge-0.1.48-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for almeshmerge-0.1.48-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 4429a4aeac3047410c56bba56d0947b1ba1efbe91ae4228592a4028d4fe24c26
MD5 32d70e057f8aff844fee7d801adf17e0
BLAKE2b-256 5acad82462b315de969c9f86d2a6b333f7ca844c6d60ab7743d95051635f50f4

See more details on using hashes here.

File details

Details for the file almeshmerge-0.1.48-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for almeshmerge-0.1.48-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 68a316b8b729503f39d8568a14789ae08ec9d0713cf3479dc0c01377d6c4b89b
MD5 19da6c8e3bd057425f78c18bc869e27a
BLAKE2b-256 ad3f2f1f4253e9726b95d4dedeb4e89fbad27a8edb156e038779de085ee939e8

See more details on using hashes here.

File details

Details for the file almeshmerge-0.1.48-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for almeshmerge-0.1.48-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 1af5ed148ebad3ed7d991744eee662dee6234fd86b853847e633e09b9117325a
MD5 5ceb4ac1fb8913492cc1bcf216bb7c3a
BLAKE2b-256 e47e60799104b04ba069173759b8c9b590a3f7829cd7bc6f6dd29852966b664a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page