Skip to content

[feat] Add support for rotated coordinate systems and coordinate system SPZ extension#82

Open
raymondyfei wants to merge 38 commits intomainfrom
yfei/rotation_support_public
Open

[feat] Add support for rotated coordinate systems and coordinate system SPZ extension#82
raymondyfei wants to merge 38 commits intomainfrom
yfei/rotation_support_public

Conversation

@raymondyfei
Copy link
Copy Markdown
Collaborator

@raymondyfei raymondyfei commented May 6, 2026

This PR adds support for rotated coordinate systems. In particular, we have:

Y-up / Z-up coordinate system conversion
SPZ previously only supported 8 Y-up coordinate systems (e.g. RUB for Three.js, RDF for PLY, LUF for glTF, RUF for Unity). This PR adds support for 8 Z-up coordinate systems (e.g. RBU, LFD) used by DCC tools such as Blender, 3ds Max, AutoCAD, Rhino, Unreal Engine, and other Adobe internal tools. Converting between Y-up and Z-up applies a 90-degree rotation about the X-axis: including correctly rotating spherical-harmonic coefficients via the Wigner D-matrices for bands l=1–4, in addition to any axis sign flips.

SPZ_ADOBE_coordinate_system extension (0xADBE0003)
A new SPZ extension that embeds the storage coordinate system in the file is added. When present, packGaussians converts to the extension's coordinate system instead of the default RUB, and unpackGaussians uses it as the source frame, enabling lossless round-trips without relying on the caller to track the storage orientation.

All 16 coordinate systems are exposed with consistent ordering, correct handedness labels, and matching documentation across the C++, Python, and Emscripten APIs.

We also added more unit tests for this new feature. We have:
test_coordinate_system.py — enum values, PackOptions/UnpackOptions mutability, Y-up and Z-up convert_coordinates, SPZ/PLY round-trips with Y-up and Z-up from_coord/to_coord
test_spherical_harmonics.py — degree-1 SH flip under Y-up/Z-up conversion, orthogonality and 4-cycle tests for bands l=2–4
Extension tests — SPZ_ADOBE_coordinate_system overrides pack/unpack destination, UNSPECIFIED extension falls back to RUB, Z-up storage round-trips

In addition, we extend the CI coverage to the Emscripten build of this library, as well as to the SPZ extensions.

Raymond Fei and others added 30 commits August 22, 2025 10:44
* remove sh min-max scaling

* move extensions to a separate folder

* move emscripten extensions into a separate folder

* move extended pack option handlers into separate file

* add extension support notifier

* move bindings also to the extensions folder

* move extra pack options also to extensions

* clean up emscripten bindings

* fix tests

* use CMAKE_CXX_STANDARD value if set

* fix SH epsilons in tests

* move quantization into core

* add comments about quantization

* clean up pack options binding

---------

Co-authored-by: Raymond Fei <yfei@Raymonds-MacBook-Pro.local>
Co-authored-by: angudavi <angudavi@adobe.com>
* modify the code according to comments

* minor fix

* refactor extensions

* fix comments

* fix tests
Comment thread src/python/spz/spz.cc
- RDF: Standard PLY file format (right-handed, Y-down, Z-forward)
- RUB: Three.js coordinate system (right-handed, Y-up, Z-backward)
- LUF: glTF/GLB format (left-handed, Y-up, Z-forward)
- LUF: glTF/GLB format (right-handed, Y-up, Z-forward)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GLTF is right-handed, which is explicitly written in its doc: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#coordinate-system-and-units
Also it has L- vs. R- compared with Unity below, which is left-handed.

Comment thread src/python/spz/spz.cc
.value("LUF", spz::CoordinateSystem::LUF, "Left Up Front - left-handed, Y-up, Z-forward (GLB format)")
.value("RUF", spz::CoordinateSystem::RUF, "Right Up Front - right-handed, Y-up, Z-forward (Unity)")
.value("LUF", spz::CoordinateSystem::LUF, "Left Up Front - right-handed, Y-up, Z-forward (GLB format)")
.value("RUF", spz::CoordinateSystem::RUF, "Right Up Front - left-handed, Y-up, Z-forward (Unity)")
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be consistent with the docstrings above, where Unity is left-handed, and GLTF/GLB is right-handed.

@gugu23456789
Copy link
Copy Markdown

Congrats on the progress! This is a major cross-cutting change affecting both extension governance and coordinate handling across the ecosystem.

As maintainer of neutral SPZ ecosystem tooling (spz_gatekeeper and spz2glb), I have two clarifying questions to align future compliance rules:

  1. Will the coordinate system rotation logic remain within the dedicated SPZ_ADOBE_coordinate_system extension (Type 0xADBE0003), or is it expected to eventually move into the base specification?
  2. For spz_gatekeeper's compliance validation: if a v4 file contains rotated SH coefficients, should the presence of this extension be mandatory, or can rotation be applied without the extension in some cases?

Thanks again for driving the SPZ ecosystem forward.

@raymondyfei
Copy link
Copy Markdown
Collaborator Author

raymondyfei commented May 6, 2026

  1. Will the coordinate system rotation logic remain within the dedicated SPZ_ADOBE_coordinate_system extension (Type 0xADBE0003), or is it expected to eventually move into the base specification?

The rotation logic and code itself are in the base implementation. We only put the tag about the orientation of the asset in the extension to record the asset's native orientation.

For spz_gatekeeper's compliance validation: if a v4 file contains rotated SH coefficients, should the presence of this extension be mandatory, or can rotation be applied without the extension in some cases?

No, it's not mandatory. The rotated SH coefficients are baked into assets. That's the purpose of the rotation logic. A rotated asset has no difference from the original one in the sense of formatting, other than that the geometry (including the position, quaternion, SH coefficients) itself is rotated.

We provide a native tool to rotate the asset in the base implementation. Only the orientation tag is in the extension.

@gugu23456789
Copy link
Copy Markdown

  1. Will the coordinate system rotation logic remain within the dedicated SPZ_ADOBE_coordinate_system extension (Type 0xADBE0003), or is it expected to eventually move into the base specification?

The rotation logic and code itself are in the base implementation. We only put the tag about the orientation of the asset in the extension to record the asset's native orientation.

For spz_gatekeeper's compliance validation: if a v4 file contains rotated SH coefficients, should the presence of this extension be mandatory, or can rotation be applied without the extension in some cases?

No, it's not mandatory. The rotated SH coefficients are baked into assets. That's the purpose of the rotation logic. A rotated asset has no difference from the original one in the sense of formatting, other than that the geometry (including the position, quaternion, SH coefficients) itself is rotated.

We provide a native tool to rotate the asset in the base implementation. Only the orientation tag is in the extension.

Thanks for the clear and detailed clarification! This will help us accurately align the compliance validation rules of spz_gatekeeper with the official SPZ specification. Looking forward to the final landing of this update.

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.

3 participants