Skip to content

fix: Match Cesium's oct encoding of vertex normals - #87

Open
kylebarron wants to merge 1 commit into
fix/vertex-normals-index-dtypefrom
fix/oct-encode-overflow
Open

kylebarron wants to merge 1 commit into
fix/vertex-normals-index-dtypefrom
fix/oct-encode-overflow

Conversation

@kylebarron

@kylebarron kylebarron commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Note

This PR was written by Claude (Claude Code), not by @kylebarron.

Fixes oct_encode flipping normals that have a component of exactly 1.0, and matches Cesium's encoding.

The bug

oct_encode mapped each component from [-1, 1] to [0, 255] with floor((v * 0.5 + 0.5) * 256). For a component of exactly 1.0 that gives 256, which wraps to 0 when cast to uint8. So a normal along +x encoded as [0, 128] and decoded as [-1, 0, 0], the opposite direction.

Fix

Use round((v * 0.5 + 0.5) * 255). That's Cesium's CesiumMath.toSNorm, which the function cites and which quantized-mesh-tile ports, and decoders divide by 255 to reverse it.

Behavior change

This changes the encoded bytes of most vertex normals by up to one unit. It fixes the overflow and also removes a small bias in every encoded normal. Decoded normals get closer to the true values. It's in the CHANGELOG.

Tests

New tests check that axis-aligned normals round-trip, and that the output exactly matches quantized-mesh-tile's octEncode on 1000 random unit vectors. Three tests fail without the fix and pass with it.

🤖 Written by Claude Code

`oct_encode` mapped each component from [-1, 1] to [0, 255] with
`floor((v * 0.5 + 0.5) * 256)`. For a component of exactly 1.0 that is 256,
which wraps to 0 when cast to uint8, so a normal along +x encoded as
`[0, 128]` and decoded as `[-1, 0, 0]`, the opposite direction.

Cesium's `toSNorm`, which the function cites and which quantized-mesh-tile
ports, uses `round((v * 0.5 + 0.5) * 255)`, and decoders divide by 255.
Use the same formula. Besides fixing the overflow, this removes a small
bias in every encoded normal. The new tests check axis-aligned normals
round-trip and that output matches quantized-mesh-tile's `octEncode`
exactly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kylebarron
kylebarron added this pull request to stack #91 October 5, 2026 21:52

This branch has not been deployed

No deployments
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