Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Aug 20, 2025

This PR implements a PLY (Polygon File Format) loader for 3D Gaussian Splatting models, enabling the <model> tag to load .ply files. The implementation follows the Spark reference implementation pattern from @sparkjsdev/spark/files/src/ply.ts.

Features Added

The PLY loader seamlessly integrates with the existing model loading infrastructure:

<!-- Auto-detection by file extension -->
<model src="path/to/gaussian_splats.ply"></model>

<!-- Explicit type specification -->
<model src="path/to/model.ply" type="ply"></model>

<!-- With loading behavior -->
<model src="path/to/large_model.ply" loading="lazy"></model>

Implementation Details

New Files:

  • src/client/builtin_scene/meshes/loaders/ply_loader.hpp - PLY loader interface
  • src/client/builtin_scene/meshes/loaders/ply_loader.cpp - PLY loader implementation
  • tests/client/ply_loader_tests.cpp - Unit tests for validation

Modified Files:

  • src/client/html/html_model_element.hpp - Added PLY to ModelType enum
  • src/client/html/html_model_element.cpp - Added PLY detection and parsing logic

PLY Format Support

The loader supports binary PLY format parsing with:

  • Robust endianness handling with efficient bit-shifting operations for little-endian and big-endian support
  • Order-preserving header parsing that maintains the exact property sequence from PLY headers for correct binary data reading
  • Gaussian splat data extraction from vertex properties:
    • Position (x, y, z) - used directly without coordinate transformations
    • Scale (scale_0, scale_1, scale_2) with logarithmic scaling using exp()
    • Rotation quaternion (rot_0, rot_1, rot_2, rot_3) following Spark component order (W, X, Y, Z)
    • Opacity with sigmoid activation: 1.0 / (1.0 + exp(-opacity))
    • Color from spherical harmonics DC components (f_dc_0, f_dc_1, f_dc_2)

Error Handling & Testing

  • Robust header validation with proper error messages
  • Graceful handling of missing or invalid PLY properties
  • Debug logging for troubleshooting model loading issues
  • Comprehensive unit tests covering edge cases, header parsing, and error conditions

The implementation maintains backward compatibility and follows the same patterns as existing loaders (KSplat, SPZ), ensuring consistent behavior across all supported 3D model formats. Unlike other loaders that apply coordinate system transformations for COLMAP format data, PLY files from 3D Gaussian Splatting are already in OpenGL coordinate system and require no transformations.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 3 commits August 20, 2025 12:56
Co-authored-by: yorkie <1935767+yorkie@users.noreply.github.com>
Co-authored-by: yorkie <1935767+yorkie@users.noreply.github.com>
Co-authored-by: yorkie <1935767+yorkie@users.noreply.github.com>
Copilot AI changed the title [WIP] 参考 @sparkjsdev/spark/files/src/ply.ts 实现 ply loader,实现在 /src/client/builtin_scene/meshes/loaders,并支持 <model> 标签加载 ply 格式的文件 Implement PLY loader for 3D Gaussian Splatting models in <model> tag Aug 20, 2025
Copilot AI requested a review from yorkie August 20, 2025 13:06
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot It can basically parse a ply file, but the parsed splat's values are wrong, please compare the related code with https://github.com/sparkjsdev/spark/blob/main/src/ply.ts to make it work with correct result to render for 3DGS rendering.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed the PLY loader coordinate system issue. The problem was that I was incorrectly applying COLMAP-to-OpenGL coordinate transformations (negating y, z position and y, z quaternion components) which are used by other loaders like KSplat and SPZ that store data in COLMAP format.

PLY files from 3D Gaussian Splatting are already in OpenGL coordinate system, so no transformations should be applied. I've updated the implementation to match the Spark reference exactly:

  • Position: Use x, y, z directly without negation
  • Rotation: Use quaternion components directly without negation
  • Removed debug console output

The implementation now correctly follows the Spark reference and should render 3DGS models properly. Commit: 4ea5702

Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot 考虑下解析数据时字节序的逻辑是否正确。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed the byte order parsing logic. The main issues were:

  1. More reliable endianness detection: Now uses 0x01234567 test pattern instead of uint16_t approach
  2. Efficient byte swapping: Replaced std::reverse with proper bit-shifting operations for better performance and correctness
  3. Compiler compatibility: Removed if constexpr for better compatibility across compilers

Also corrected the quaternion component order to exactly match the Spark reference implementation (rot_0=W, rot_1=X, rot_2=Y, rot_3=Z).

Commit: 8eb44c0

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed the byte order parsing logic. The main issues were:

  1. More reliable endianness detection: Now uses 0x01234567 test pattern instead of uint16_t approach
  2. Efficient byte swapping: Replaced std::reverse with proper bit-shifting operations for better performance and correctness
  3. Compiler compatibility: Removed if constexpr for better compatibility across compilers

Also corrected the quaternion component order to exactly match the Spark reference implementation (rot_0=W, rot_1=X, rot_2=Y, rot_3=Z).

Commit: 8eb44c0

Co-authored-by: yorkie <1935767+yorkie@users.noreply.github.com>
Copilot AI requested a review from yorkie August 20, 2025 14:56
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot 考虑下解析数据时字节序的逻辑是否正确。

Co-authored-by: yorkie <1935767+yorkie@users.noreply.github.com>
Copilot AI requested a review from yorkie August 20, 2025 15:22
{
std::string name;
int count;
std::unordered_map<std::string, PlyProperty> properties;
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot 这里不能使用 unordered_map,因为在解析 vertex 内容时,需要按照 ply header 中 property 出现的顺序来加载,因此 properties 需要保留解析 header 时头部出现的顺序。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed the property ordering issue. Changed PlyElement.properties from std::unordered_map to std::vector<std::pair<std::string, PlyProperty>> to preserve the exact order properties appear in the PLY header. This ensures binary data is parsed in the correct sequence during vertex parsing. d46242f

…_map

The PLY loader was using std::unordered_map for storing element properties, which doesn't preserve the order properties appear in the PLY header. When parsing binary PLY data, properties must be read in the exact header order.

Changed PlyElement.properties from unordered_map to vector<pair<string, PlyProperty>> to preserve insertion order during header parsing, ensuring correct binary data parsing.

- Replace std::unordered_map with std::vector<std::pair<>> in PlyElement struct
- Update property insertion to use push_back instead of map access
- Maintains same iteration interface for backward compatibility

Co-authored-by: yorkie <1935767+yorkie@users.noreply.github.com>
Copilot AI requested a review from yorkie August 20, 2025 16:03
Copy link
Collaborator

@yorkie yorkie left a comment

Choose a reason for hiding this comment

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

@copilot Please update for my reviews.

@@ -0,0 +1,506 @@
#include <common/debug.hpp>
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot Please remove using common/debug.hpp and use client/logger.hpp instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated PLY loader to use #include <client/logger.hpp> instead of common/debug.hpp. Replaced all DEBUG() calls with appropriate logging::LogError() and logging::LogWarning() calls. Commit: 1c5d4b7

Copy link
Collaborator

Choose a reason for hiding this comment

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

Rename all the static methods such as decodePly -> DecodePly, NOTE: static methods and fields must use uppercase for the first char.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed all static methods to follow uppercase naming convention:

  • decodePlyDecodePly
  • loadLoad
  • parseHeaderParseHeader
  • parseElementDataParseElementData
  • getPropertyTypeSizeGetPropertyTypeSize
  • parsePropertyValueParsePropertyValue
  • stringToPropertyTypeStringToPropertyType
  • extractSplatDataExtractSplatData
  • readBinaryReadBinary

Updated all references in header, implementation, HTML model element, and test files. Commit: 1c5d4b7

@yorkie yorkie marked this pull request as ready for review August 20, 2025 16:33
Co-authored-by: yorkie <1935767+yorkie@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Aug 20, 2025

@copilot Please update for my reviews.

Updated PLY loader based on your reviews:

  1. Logging: Replaced common/debug.hpp with client/logger.hpp and updated all DEBUG calls to use proper client logging functions
  2. Method naming: Renamed all static methods to follow uppercase convention (DecodePly, Load, ParseHeader, etc.)

All references have been updated across the codebase including implementation, header, HTML model element, and test files. Commit: 1c5d4b7

Copilot AI requested a review from yorkie August 20, 2025 16:43
@yorkie yorkie merged commit e5625a7 into main Aug 20, 2025
2 checks passed
@yorkie yorkie deleted the copilot/fix-13eb9356-9cff-49d7-bccb-e4d5eba83977 branch August 20, 2025 17:10
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.

2 participants