google-deepmind / google-deepmind/mujoco

msh2obj emits face indices for absent normals and texture coordinates

Open Beginner friendly
#3,594 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
15.2k
Forks
1.8k
Avg merge
10d 16h
Merged PRs (30d)
25

Description

### Intro

I'm reporting a mesh-interchange issue in the legacy MSH-to-OBJ conversion utility.

### My setup

- Reproduced with the MuJoCo 3.13.0 Python release on macOS arm64, Python 3.13.15, NumPy 2.5.3.
- The current `main` version of `python/mujoco/msh2obj.py` has the same behavior.
- No renderer or robot hardware is involved.

### What's happening? What did you expect?

The [documented MSH format](https://mujoco.readthedocs.io/en/stable/XMLreference.html#asset-mesh) allows normals and texture coordinates to be absent (`nnormal=0` and/or `ntexcoord=0`).

The converter always emits faces as `v/vt/vn`. With neither attribute present, its output has no `vt` or `vn` records but still contains:

```text
f 1/1/1 3/3/3 2/2/2
```

The expected face is:

```text
f 1 3 2
```

With only normals present the expected form is `v//vn`; with only texture coordinates it is `v/vt`. The current converter emits nonexistent attribute references in all three cases.

MuJoCo's own OBJ loader tolerates these absent attribute arrays, so merely loading the converted OBJ does not catch the output-format defect.

### Steps for reproduction

Create this complete tetrahedral MSH file:

```python
from pathlib import Path
import numpy as np

vertices = np.array(
[[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]],
dtype=np.float32,
)
faces = np.array(
[[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]],
dtype=np.int32,
)
with Path("tetra.msh").open("wb") as f:
for data in (np.array([4, 0, 0, 4], dtype=np.int32), vertices, faces):
data.tofile(f)
```

Then run:

```sh
python -m mujoco.msh2obj -i tetra.msh -o tetra.obj
```

Inspect `tetra.obj`: there are 4 vertex records, zero normal/texture-coordinate records, and faces referencing all three attributes.

### Minimal model

The generated MSH is loadable by:

```xml



```

### Investigation

A small fix and tests are ready: choose face syntax based on which attribute arrays are present. Tests write real MSH files for all four combinations and check exported syntax, attribute counts, and MSH/OBJ loading. Three new cases fail before the fix; all five tests, including the existing full-attribute roundtrip, pass afterward.

I checked the relevant format documentation and searched issues, discussions and PRs. Open #3493 changes header validation and does not modify face emission.

Contributor guide

Open the contributing guide

Research direction

Start with python/mujoco/msh2obj.py and reproduce the issue using the tetra.msh generator and `python -m mujoco.msh2obj -i tetra.msh -o tetra.obj`. Check the exported face syntax and attribute counts for all four normal/texture-coordinate combinations, then verify the existing full-attribute roundtrip still passes and that the generated MSH and OBJ files load.

Written by the indexing model from the issue text.

Assessment

Tech stack
numpy, python
Domain
cli, computer-graphics
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.