日本語要約: NDMFパス実行時、isReadable == false のメッシュが Entries に含まれていると MeshSimplifier.SimplifyBatch が InvalidOperationException を投げ、例外がパスの外へ伝播してビルド全体が失敗します (VRChat SDK の "Preprocess Callback Failed" モーダル)。VRCFury でリターゲットされたメッシュにおいて断続的に発生しました。該当エントリを警告付きでスキップするか、読み取り可能なコピーを作成する対応をご検討いただけないでしょうか。
Environment
- Meshia.MeshSimplification 3.2.0 (VPM)
- Unity 2022.3.22f1, VRChat Avatars SDK 3.10.4, NDMF (Modular Avatar 1.17.1), VRCFury 1.1353.0
- Component: Meshia Cascading Avatar Mesh Simplifier, consumed at build time via the NDMF plugin
What happens
During an avatar build, if any renderer entry's mesh reports isReadable == false at the time the NDMF Optimizing pass runs, SimplifyBatch throws:
InvalidOperationException: Not allowed to access vertex data on mesh 'RETARGETED__Shats' at array index 18 (isReadable is false; Read/Write must be enabled in import settings)
at Meshia.MeshSimplification.MeshSimplifier.SimplifyBatch (...) MeshSimplifier.cs:146
at Meshia.MeshSimplification.Ndmf.Editor.NdmfPlugin+<>c.<Configure>b__2_1 (...) NdmfPlugin.cs:80
The exception escapes the "Simplify meshes" pass, NDMF's optimize hook reports failure, and the VRChat SDK aborts the build with a blocking "Preprocess Callback Failed" modal. One unlucky mesh therefore costs the user the entire upload rather than just that mesh's simplification.
Reproducibility notes
In our case the mesh was a VRCFury-retargeted clone (RETARGETED__*), and the failure was intermittent: the identical avatar built successfully three other times the same day with bit-identical triangle counts, so the clone's readability appears to be timing/ordering dependent within the build. A deterministic repro is any entry whose mesh has Read/Write disabled and no editor-side CPU copy when the pass runs.
This is a different trigger from #33 (entry invalidated by prior mesh deletion) but the same failure shape: entry state that changes between configuration and the Optimizing pass turns into a build-failing exception instead of a skip.
Suggestion
In the NDMF pass entry loop (NdmfPlugin.cs, where entry.IsValid(...) and entry.Enabled are already checked), treat a non-readable mesh as skippable: log a warning naming the renderer and continue, or fall back to simplifying a readable copy of the mesh. Skipping seems safest, since a runtime-created mesh whose CPU copy was discarded cannot be read at all.
For reference, we currently work around this downstream by checking every entry's shared mesh just before the pass and setting Enabled = false on non-readable ones, which restores the build; a fix in SimplifyBatch/NdmfPlugin would cover all consumers.
Thank you for the great tool!
日本語要約: NDMFパス実行時、
isReadable == falseのメッシュが Entries に含まれているとMeshSimplifier.SimplifyBatchがInvalidOperationExceptionを投げ、例外がパスの外へ伝播してビルド全体が失敗します (VRChat SDK の "Preprocess Callback Failed" モーダル)。VRCFury でリターゲットされたメッシュにおいて断続的に発生しました。該当エントリを警告付きでスキップするか、読み取り可能なコピーを作成する対応をご検討いただけないでしょうか。Environment
What happens
During an avatar build, if any renderer entry's mesh reports
isReadable == falseat the time the NDMF Optimizing pass runs,SimplifyBatchthrows:The exception escapes the "Simplify meshes" pass, NDMF's optimize hook reports failure, and the VRChat SDK aborts the build with a blocking "Preprocess Callback Failed" modal. One unlucky mesh therefore costs the user the entire upload rather than just that mesh's simplification.
Reproducibility notes
In our case the mesh was a VRCFury-retargeted clone (
RETARGETED__*), and the failure was intermittent: the identical avatar built successfully three other times the same day with bit-identical triangle counts, so the clone's readability appears to be timing/ordering dependent within the build. A deterministic repro is any entry whose mesh has Read/Write disabled and no editor-side CPU copy when the pass runs.This is a different trigger from #33 (entry invalidated by prior mesh deletion) but the same failure shape: entry state that changes between configuration and the Optimizing pass turns into a build-failing exception instead of a skip.
Suggestion
In the NDMF pass entry loop (NdmfPlugin.cs, where
entry.IsValid(...)andentry.Enabledare already checked), treat a non-readable mesh as skippable: log a warning naming the renderer and continue, or fall back to simplifying a readable copy of the mesh. Skipping seems safest, since a runtime-created mesh whose CPU copy was discarded cannot be read at all.For reference, we currently work around this downstream by checking every entry's shared mesh just before the pass and setting
Enabled = falseon non-readable ones, which restores the build; a fix inSimplifyBatch/NdmfPluginwould cover all consumers.Thank you for the great tool!