Skip to content

EXT_meshopt_compression: accessor reads use wrong byte length / stride for accessors sharing a bufferView#821

Open
camnewnham wants to merge 1 commit into
atteneder:openupmfrom
camnewnham:fix/meshopt-strided-animation-bytestride
Open

EXT_meshopt_compression: accessor reads use wrong byte length / stride for accessors sharing a bufferView#821
camnewnham wants to merge 1 commit into
atteneder:openupmfrom
camnewnham:fix/meshopt-strided-animation-bytestride

Conversation

@camnewnham

@camnewnham camnewnham commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Affected: 6.19.0 (com.atteneder.gltfast / com.unity.cloud.gltfast)

Summary

Two defects in the EXT_meshopt_compression branches of GltfImportBase's accessor readers break glTFs where multiple accessors share a single meshopt-compressed bufferView — e.g. glTF-Transform exports that pack animation sampler outputs together. Both stem from the meshopt branches diverging from the existing non-meshopt semantics in the same file.

Note: Bug 1 is only a crash with ENABLE_UNITY_COLLECTIONS_CHECKS. It doesn't crash in a player build -- though in combination with Bug 2 it causes corrupt animations.

Bug 1 — crash: wrong byte length in GetAccessorData<T>

The meshopt branch passes count (an element count) as the byte length to
GetSubArray:

return new ReadOnlyNativeArray<byte>(fullSlice).GetSubArray(offset, count).Reinterpret<T>();

For a VEC3/FLOAT accessor with count = 3 at a non-zero offset this slices 3 bytes,
and Reinterpret<float3>() throws:

InvalidOperationException: Types System.Byte (array length 3) and Unity.Mathematics.float3
cannot be aliased due to size constraints. The size of the types and lengths involved must line up.

The length must be count * sizeof(T), matching the assertion right above it (GltfImport.cs#L2164) and the non-meshopt path (GltfImport.cs#L2223).

Fix: GltfImport.cs#L2166

Bug 2 — silent corruption: wrong stride in GetStridedAccessorData<T>

The meshopt branch passes the outer bufferView.byteStride, which is undefined (-1) for non-vertex bufferViews such as animation sampler outputs. The decoded meshopt data is packed at EXT_meshopt_compression.byteStride. With stride 0,
UnsafeUtility.ReadArrayElementWithStride returns element 0 for every index — e.g. all translation keyframes collapse to the first value (no crash, wrong result). GetBufferView already reads the extension stride (GltfImport.cs#L2127), and the non-meshopt GetStridedAccessorData falls back to sizeof(T) (GltfImport.cs#L2240).

Fix: GltfImport.cs#L2185-L2189

Reproduction

A GLB using EXT_meshopt_compression + KHR_mesh_quantization with an animated translation track (e.g. a glTF-Transform v4.3.0 export). Bug 1 fails the load; with Bug 1 fixed, Bug 2 zeroes the translation animation.

Here's a sample file that demonstrates this condition (and loads correctly with this PR). Drag + drop for editor-time loading is sufficient.

meshopt_animation_buffer_repro.zip

AI Disclosure

AI was used in diagnosing this issue and drafting this PR. I have verified the results manually (and visually) and provided the files for reproduction above.

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