arkavo-org / arkavo-org/VRMMetalKit

Implement runtime VRM export functionality

Open
#68 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Swift
Stars
6
Forks
2
Avg merge
18h 51m
Merged PRs (30d)
26

Description

## Issue Description

VRMMetalKit currently only supports importing VRM files but lacks runtime export functionality. UniVRM (the reference implementation) supports both import and export, making this a feature gap.

## Current State

✅ **Implemented:**
- VRM 1.0 import
- VRM 0.x import (with fallback)
- VRMA animation import
- Complete model parsing and loading

❌ **Missing:**
- VRM 1.0 export
- VRM 0.x export
- Runtime model serialization
- glTF/GLB export with VRM extensions

## Use Cases

1. **Avatar Customization:** Export modified avatars after customization
2. **Format Conversion:** Convert between VRM versions (0.x ↔ 1.0)
3. **Model Processing:** Export processed models (optimized, retargeted, etc.)
4. **Content Creation:** Generate VRM files programmatically
5. **Migration Tools:** Export from other formats to VRM

## Implementation Requirements

### Core Export Functionality

```swift
// Proposed API
extension VRMModel {
/// Export VRM model to file
public func export(
to url: URL,
version: VRMSpecVersion = .v1_0,
options: VRMExportOptions = .default
) async throws

/// Export to Data for in-memory operations
public func exportData(
version: VRMSpecVersion = .v1_0,
options: VRMExportOptions = .default
) async throws -> Data
}

public struct VRMExportOptions {
var embedTextures: Bool = true
var compressTextures: Bool = false
var optimizeMeshes: Bool = false
var includeMetadata: Bool = true
var prettyPrintJSON: Bool = false

public static let default = VRMExportOptions()
}
```

### Components to Implement

1. **glTF Serialization**
- JSON structure generation
- Binary buffer packing
- GLB container format

2. **VRM Extension Serialization**
- VRMC_vrm extension (VRM 1.0)
- VRM extension (VRM 0.x fallback)
- Humanoid bone mapping
- Expression data
- SpringBone configuration
- First-person settings
- Metadata

3. **Asset Serialization**
- Mesh data export
- Texture encoding (PNG/JPEG)
- Material properties
- Animation data (VRMA)

4. **Validation**
- Pre-export validation
- Specification compliance checks
- Required field verification

## Reference Implementation

UniVRM export structure:
```csharp
// UniVRM/Packages/VRM10/Runtime/IO/
- Vrm10Exporter.cs
- Vrm10ExportSettings.cs
- Material exporters
- Texture exporters
```

## Suggested File Structure

```
Sources/VRMMetalKit/Exporter/
├── VRMExporter.swift # Main export coordinator
├── GLTFSerializer.swift # glTF JSON/binary serialization
├── VRMExtensionSerializer.swift # VRM extension data
├── MeshExporter.swift # Mesh data export
├── TextureExporter.swift # Texture encoding
├── MaterialExporter.swift # Material properties
└── VRMExportOptions.swift # Export configuration
```

## Implementation Phases

### Phase 1: Basic Export (MVP)
- [ ] glTF JSON serialization
- [ ] Binary buffer packing
- [ ] GLB container format
- [ ] Basic VRM 1.0 extension
- [ ] Mesh export
- [ ] Texture export (embedded)

### Phase 2: Complete VRM 1.0
- [ ] Full humanoid bone mapping
- [ ] Expression export
- [ ] SpringBone configuration
- [ ] First-person settings
- [ ] Metadata export
- [ ] Material properties

### Phase 3: Advanced Features
- [ ] VRM 0.x export (migration)
- [ ] Texture compression options
- [ ] Mesh optimization
- [ ] External texture references
- [ ] VRMA animation export

### Phase 4: Validation & Testing
- [ ] Pre-export validation
- [ ] Specification compliance checks
- [ ] Round-trip testing (import → export → import)
- [ ] Compatibility testing with other VRM tools

## Testing Strategy

```swift
// Test cases
func testBasicExport() async throws {
let model = try await VRMModel.load(from: testVRMURL, device: device)
let exportURL = temporaryDirectory.appendingPathComponent(exported.vrm)
try await model.export(to: exportURL)

// Verify exported file
let reimported = try await VRMModel.load(from: exportURL, device: device)
XCTAssertEqual(model.humanoidBones.count, reimported.humanoidBones.count)
}

func testRoundTrip() async throws {
// Import → Export → Import should preserve data
}

func testVersionConversion() async throws {
// VRM 1.0 → VRM 0.x conversion
}
```

## Acceptance Criteria

- [ ] Export VRM 1.0 files that can be imported by UniVRM
- [ ] Export VRM 1.0 files that can be imported by VRMMetalKit
- [ ] Preserve all model data (meshes, textures, bones, expressions)
- [ ] Pass VRM validator checks
- [ ] Documentation with examples
- [ ] Unit tests with >80% coverage
- [ ] Performance benchmarks

## Priority

**Medium** - Important for feature completeness but not blocking core functionality

## Estimated Effort

- Phase 1 (MVP): 2-3 weeks
- Phase 2 (Complete): 2-3 weeks
- Phase 3 (Advanced): 1-2 weeks
- Phase 4 (Testing): 1 week
- **Total:** 6-9 weeks

## Related Issues

- Depends on: None
- Blocks: Format conversion tools, avatar customization features
- Related: #66 (spec compliance)

## References

- VRM 1.0 Specification: https://github.com/vrm-c/vrm-specification
- glTF 2.0 Specification: https://registry.khronos.org/glTF/
- UniVRM Exporter: https://github.com/vrm-c/UniVRM/tree/master/Assets/VRM10/Runtime/IO

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the existing VRM import and model-parsing implementation, then compare it with the proposed Sources/VRMMetalKit/Exporter/ structure and the UniVRM exporter reference. The work is complete when VRM 1.0 export, GLB serialization, asset and extension handling, validation, round-trip tests, and the documented acceptance checks are implemented.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
computer-graphics
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.