Metadata-Version: 2.2
Name: almeshopt
Version: 0.1.9
Summary: Meshoptimizer wrapper with cython
Requires-Python: <3.15,>=3.11
Requires-Dist: numpy>=2.0.1
Description-Content-Type: text/markdown

## almeshopt

`almeshopt` 是 [meshoptimizer](extern/meshoptimizer/) 的 Python 封装（Cython + CMake + scikit-build-core），提供面向 **NumPy** 的网格索引/顶点重排、渲染性能优化、压缩编解码、简化（LOD）、meshlet 构建等接口。

- **安装**：`pip install almeshopt`
- **导入**：`import almeshopt`
- **实现**：优先加载包内扩展模块 `almeshopt_avx2`（见 `src/almeshopt/__init__.py`）

> 说明：当前发布策略为 **只发布 AVX2 版 wheel**（构建时 `USE_AVX2=ON`）。源码中保留了非 AVX2 的扩展实现入口，但目前不发布对应 wheel。

---

## 快速开始

### 安装

```bash
pip install -U almeshopt numpy
```

### 典型用法：简化 + 顶点/索引重排

```python
import numpy as np
import almeshopt

# indices: (N*3,) uint32
# vertices: (V,3) float32，必须 C-contiguous
indices = np.array([0, 1, 2, 2, 3, 0], dtype=np.uint32)
vertices = np.array([[0,0,0],[1,0,0],[1,1,0],[0,1,0]], dtype=np.float32)

# 目标三角形数量（这里演示：减半）
new_indices, error = almeshopt.simplify(
    indices,
    vertices,
    target_count=len(indices)//2,
    target_error=1e-2,
)

# 进一步优化：顶点 fetch 重排（返回 new_indices, new_vertices）
opt_indices, opt_vertices = almeshopt.optimize_vertex_fetch(new_indices, vertices)
print(opt_indices.shape, opt_vertices.shape, error)
```

---

## API 参考（当前仓库实际封装的接口）

> 下列函数均来自扩展模块（`src/almeshopt/almeshopt.pyx` / `src/almeshopt/almeshopt_avx2.pyx`），导入统一使用 `import almeshopt`。
>
> 约定：`indices` 通常为 `np.uint32` 的一维数组（长度为三角形数 × 3）；`vertices` 通常为二维数组（例如 `(V, 3)` 的 `np.float32`）。多数接口要求数组为 **C-contiguous**。

### 1）重映射与索引生成
- **`generate_vertex_remap(indices, vertices)`** → `(remap, unique_count)`  
  根据 `indices` + `vertices` 生成顶点重映射表。
- **`remap_vertex_buffer(vertices, remap)`** → `new_vertices`
- **`remap_index_buffer(indices, remap)`** → `new_indices`
- **`generate_shadow_index_buffer(indices, vertices)`** → `shadow_indices`
- **`generate_adjacency_index_buffer(indices, vertices)`** → `adjacency_indices`（每个三角形 6 个索引）

### 2）渲染性能优化
- **`optimize_vertex_cache(indices, vertex_count)`** → `new_indices`
- **`optimize_vertex_cache_strip(indices, vertex_count)`** → `new_indices`
- **`optimize_overdraw(indices, vertices, threshold=1.05)`** → `new_indices`
- **`optimize_vertex_fetch(indices, vertices)`** → `(new_indices, new_vertices)`

### 3）压缩与解压（索引/顶点）
- **`encode_index_buffer(indices, vertex_count)`** → `bytes`
- **`decode_index_buffer(encoded_data, index_count)`** → `np.ndarray[np.uint32]`
- **`encode_vertex_buffer(vertices, level=2)`** → `bytes`  
  支持任意 C-contiguous 的 numpy 数组（例如 `float32/uint16/uint8`），`level` 越高压缩率越好但更慢。
- **`decode_vertex_buffer(encoded_data, vertex_count, vertex_stride, dtype=np.float32)`** → `np.ndarray`  
  `vertex_stride` 单位是 **字节**（例如 `uint16` 的 `XYZ0` padding，stride=8）。
- **`encode_filter_oct(data, bits=8)`** → `np.ndarray[np.uint8]`  
  Octahedral 编码（目前封装为返回字节数组；使用前请确保输入数据形状/stride符合预期）。

### 4）简化（LOD）
- **`simplify(indices, vertices, target_count, target_error=0.01, sloppy=False, vertex_lock=None)`** → `(new_indices, error)`
- **`simplify_with_attributes(indices, vertices, attributes, weights, target_count, target_error=0.01, vertex_lock=None)`** → `(new_indices, error)`
- **`simplify_points(vertices, target_count, colors=None, color_weight=1.0)`** → `indices`

### 5）空间排序
- **`spatial_sort_triangles(indices, vertices)`** → `new_indices`
- **`spatial_sort_remap(vertices)`** → `remap`

### 6）分析（统计指标）
- **`analyze_vertex_cache(indices, vertex_count, cache_size=16, warp_size=0, primgroup_size=0)`** → `dict`
- **`analyze_overdraw(indices, vertices)`** → `dict`

### 7）Meshlets（Mesh Shading）
- **`build_meshlets(indices, vertices, max_vertices=64, max_triangles=124, cone_weight=0.0)`** → `dict`  
  返回键：`meshlets`（Nx4）、`meshlet_vertices`、`meshlet_triangles`。
- **`compute_meshlet_bounds(meshlet_vertices, meshlet_triangles, vertices)`** → `dict`

### 8）Triangle Strip
- **`stripify(indices, vertex_count)`** → `strip_indices`

---

## 示例（仓库内 demos）

目录：[demos/](demos/)

- **点云压缩（带颜色）**：`demos/ply_compress.py` / `demos/ply_decompress.py`  
  主要展示 `encode_vertex_buffer` / `decode_vertex_buffer` 的用法（uint16 几何 + uint8 颜色）。
- **GLTF/GLB 简化（带 UV）**：`demos/mesh_simp_with_texture.py`  
  展示 `generate_vertex_remap`、`remap_*`、`simplify`、`optimize_vertex_fetch` 的组合使用。

---

## “地形切片 / Cesium Terrain”接口说明

你可能在仓库中看到了 `dem_to_cesium_terrain_*.plan.md` 之类的规划文档，但**当前仓库代码里并没有** `TerrainTiler` / `.terrain` 编码器等实现文件（例如 `terrain_tiler.py`、`quantized_mesh.*`、`terrain_mesher.*` 均不存在）。  
因此，本包当前对外 API **只包含 meshoptimizer 封装**（见上文 API 参考），不包含地形瓦片管线接口。

如果你希望把地形切片管线也纳入 `almeshopt` 并发布为 wheel，我们可以再按“规划文档 → 实际代码”补齐对应 C++/Cython/Python 层实现与测试。

---

## 构建与发布（维护者）

### 构建 wheel（Windows + Linux manylinux via Docker Desktop）
仓库提供 PowerShell 脚本，目录：[scripts/](scripts/)

- **一键构建并上传（默认 cp311/cp312/cp313/cp314；Windows+Linux）**

```powershell
.\scripts\release.ps1
```

- **只构建 Windows wheel**

```powershell
.\scripts\release.ps1 -Platform windows -SkipUpload
```

- **只构建 Linux manylinux x86_64（Docker Desktop）**

```powershell
.\scripts\release.ps1 -Platform linux -SkipUpload
```

### 上传到 PyPI
推荐使用环境变量 `PYPI_API_TOKEN`：

```powershell
$env:PYPI_API_TOKEN="pypi-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
.\scripts\upload_pypi.ps1 -SkipExisting
```

> 中文终端显示：脚本中已包含 `chcp 65001` + UTF-8 输出设置，并默认禁用 `twine` 进度条以避免 GBK 控制台编码问题。

---

## 常见问题（FAQ）

### 1）为什么 `pip install almeshopt` 但内部模块叫 `almeshopt_avx2`？
`almeshopt_avx2` 是包内部的扩展模块名；对用户而言 **安装名与导入名都始终是 `almeshopt`**。`almeshopt/__init__.py` 会优先加载 AVX2 扩展。

### 2）数组需要什么 dtype / shape？
不同接口对 dtype/shape 有要求；最通用的组合是：
- `indices`: `np.uint32`，形状 `(T*3,)`
- `vertices`: `np.float32`，形状 `(V,3)` 或拼接属性后的 `(V, k)`
并确保 `np.ascontiguousarray(...)`。
