Skip to content

[Merge with Minor version increment] Improve smoothing, lerp or interpolation of transform sync#299

Merged
from2001 merged 6 commits intodevelopfrom
improve/smoothness
Jan 26, 2026
Merged

[Merge with Minor version increment] Improve smoothing, lerp or interpolation of transform sync#299
from2001 merged 6 commits intodevelopfrom
improve/smoothness

Conversation

@from2001
Copy link
Collaborator

Improve smoothing, lerp or interpolation of transform sync

1. Renamed file: NetSyncTransformSmoother.cs → NetSyncTransformApplier.cs
2. Renamed class: NetSyncTransformSmoother → NetSyncTransformApplier
3. Updated NetSyncAvatar.cs:
  - _smoother → _transformApplier
4. Updated HumanPresenceManager.cs:
  - _smootherByClient → _applierByClient
  - smoother local variables → applier
  - Updated comment: "No smoothing" → "no interpolation"
5. Deleted: Old NetSyncTransformSmoother.cs and its .meta file
…hing

- Introduced TransformBinding struct for better organization of transform data.
- Updated initialization methods to support new smoothing settings and time estimation.
- Replaced immediate target application with snapshot-based updates for smoother transitions.
- Enhanced Tick method to apply transforms based on estimated server time and dynamic buffer multipliers.
- Modified AddSnapshot and Clear methods for better state management.
- Updated TransformSyncManager to include pose sequence in transmitted data.
- Changed physical rotation representation from Vector3 to Quaternion for consistency.
- Improved handling of pose flags in NetSyncAvatar for better state tracking.
- Adjusted UpdateHumanPresenceTransform to use Quaternion for rotation calculations.
@from2001
Copy link
Collaborator Author

@claude Review this PR.

@claude
Copy link
Contributor

claude bot commented Jan 24, 2026

Claude finished @from2001's task in 2m 6s —— View job


Code Review Complete ✓

Reviewing PR #299: Improve smoothing, lerp or interpolation of transform sync


Summary

This PR implements a major refactoring of the transform smoothing system, introducing snapshot interpolation with bounded extrapolation and adaptive smoothing. The changes affect both Python server and Unity client code, with significant improvements to time estimation and transform synchronization.

Overall Assessment: The implementation is well-architected and addresses the smoothness improvements effectively. However, there are several issues that should be addressed before merging.


Critical Issues

1. Null Propagation Violation (Unity C# Code)

Location: NetSyncTransformApplier.cs:193-197

_physical?.Clear();
_head?.Clear();
_rightHand?.Clear();
_leftHand?.Clear();
_singleChannel?.Clear();

Issue: According to CLAUDE.md, null propagation operators (?.) should NEVER be used with types that could be UnityEngine.Object or derive from it. While PoseChannel is not a Unity object, this pattern is inconsistent with the codebase standards.

Recommendation: Use explicit null checks:

if (_physical != null) _physical.Clear();
if (_head != null) _head.Clear();
// ... etc

Fix this →


2. Potential Division by Zero Issues

Location: NetSyncSmoothing.cs:527-530 (EvaluateAdaptiveTau method)

var tSpeed = Mathf.Clamp01(linearSpeed / Mathf.Max(1e-3f, _settings.SpeedForTauMin));
var tAng = Mathf.Clamp01(angularSpeedDeg / Mathf.Max(1e-3f, _settings.AngularSpeedForTauMin));

Issue: While there's a guard with Mathf.Max(1e-3f, ...), if _settings.SpeedForTauMin or _settings.AngularSpeedForTauMin are configured to 0 in the settings, this becomes division by a very small number which could cause numerical instability.

Recommendation: Add validation in PoseChannelSettings to ensure these values are always positive, or add defensive checks when settings are assigned.


3. Missing Null Check in Binary Serializer

Location: BinarySerializer.cs:254

if (binding.Transform == null) return;

Good! This follows CLAUDE.md guidelines. However, there's an inconsistency:

Location: NetSyncAvatar.cs:305-312

The code checks for null with if (_head != null) which is correct, but the pattern could be more defensive throughout.


Major Issues

4. Thread Safety in Time Estimation

Location: NetSyncSmoothing.cs:98-110 (NetSyncTimeEstimator.OnRoomBroadcast)

Issue: The NetSyncTimeEstimator is accessed from both the network receive thread (via MessageProcessor) and the main Unity thread (via Tick in Update). There's no synchronization mechanism.

Concern: While the current usage pattern might be safe (write from one thread, read from another with primitive types), this could lead to race conditions if fields are added in the future.

Recommendation: Add comments documenting the threading model, or consider using volatile fields or simple locks for critical sections.


5. High-Resolution Clock Consistency

Location: NetSyncSmoothing.cs:12-23 (NetSyncClock)

Good Practice: Using Stopwatch.GetTimestamp() for high-resolution timing is excellent for network jitter estimation.

Concern: This is used in NetSyncAvatar.cs:180 but the conversion to seconds happens via a static calculation. Ensure this is consistent with the server's time representation.

Python Side: client_simulator.py:1068 uses time.perf_counter_ns() for timing budgets, which is good.


6. Resource Management in Python Client Simulator

Location: client_simulator.py:1454-1461 (socket registration)

Good Practice: The socket registration/unregistration pattern with tracked sockets is excellent for preventing file descriptor leaks.

Issue: The _cleanup_tracked_sockets method at line 1462 iterates over a set while potentially modifying it. While the code uses list(self._sockets) to create a copy, this is correct.


Minor Issues & Suggestions

7. Magic Numbers in Configuration

Location: NetSyncSmoothing.cs:330-356 (PoseChannelSettings and NetSyncSmoothingSettings)

Issue: Many magic numbers for timing constants:

  • MaxExtrapolationSeconds = 0.05
  • TauMinSeconds = 0.02f
  • BaseBufferMultiplier = 1.5

Recommendation: Add comments explaining the rationale for these values (e.g., "50ms extrapolation allows for 1-2 dropped packets at 30Hz").


8. Sequence Number Wrap-Around

Location: NetSyncSmoothing.cs:321-324 (SequenceLE)

private static bool SequenceLE(ushort a, ushort b)
{
    return (ushort)(a - b) >= 0x8000;
}

Good Practice: Proper handling of ushort wrap-around using the sequence number comparison pattern.

Suggestion: Add a comment explaining the algorithm for future maintainers.


9. Quaternion Normalization

Location: NetSyncSmoothing.cs:380-387 and NetSyncSmoothing.cs:521

Good Practice: The code normalizes quaternions after deserialization and after interpolation, which prevents accumulated numerical errors.


10. Python Type Hints

Location: binary_serializer.py throughout

Good Practice: Excellent use of type hints. The code uses modern Python typing:

def deserialize(data: bytes) -> tuple[int, dict[str, Any] | None, bytes]:

Suggestion: Consider adding -> None return type hints to functions that don't return values for completeness.


11. Error Handling in Deserialization

Location: binary_serializer.py:399-401

except Exception:
    # Error deserializing message - return None data
    return message_type, None, b""

Issue: Swallowing all exceptions silently could hide bugs during development.

Recommendation: Consider logging at DEBUG level or adding metrics for deserialization failures.


12. Battery Simulation Constants

Location: client_simulator.py:883-887

BATTERY_INITIAL_MIN = 50.0  # %
BATTERY_INITIAL_MAX = 100.0  # %
BATTERY_DRAIN_RATE = 10.0 / 60.0  # %-points lost per second (10%/min)
BATTERY_UPDATE_INTERVAL = 60.0  # Send battery updates every 60 seconds

Good Practice: Well-documented constants with clear units.


Architecture & Design Review

Positive Aspects

  1. Separation of Concerns: The new architecture cleanly separates:

    • NetSyncSmoothing.cs: Core smoothing algorithms and time estimation
    • NetSyncTransformApplier.cs: Application layer that binds smoothing to Unity transforms
    • This is a significant improvement over the monolithic NetSyncTransformSmoother.cs
  2. Snapshot Interpolation: The buffered snapshot approach (PoseSnapshotBuffer) is well-designed:

    • Handles out-of-order packets via sequence numbers
    • Supports bounded extrapolation for low-latency rendering
    • Clear state machine (Empty, HoldSingle, Interpolating, Extrapolating)
  3. Adaptive Smoothing: The two-phase smoothing approach is sophisticated:

    • Phase 1: Snapshot interpolation/extrapolation
    • Phase 2: Exponential smoothing with speed-adaptive tau
    • This should provide smooth motion at variable speeds
  4. Python Refactoring: The movement to using high-resolution clocks (time.perf_counter_ns()) improves timing accuracy in the simulator.

Areas for Improvement

  1. Documentation: While the code has some comments, key algorithms (sequence number comparison, adaptive tau calculation, buffer multiplier logic) need more explanation.

  2. Testing: No test files were modified in this PR. The smoothing algorithms would benefit from unit tests verifying:

    • Quaternion normalization edge cases
    • Sequence wrap-around behavior
    • Extrapolation bounds
    • Time estimation convergence
  3. Magic Number Configuration: Consider exposing more tuning parameters or documenting the tuning process for different network conditions.


Performance Considerations

Positive

  1. Zero-Allocation Transform Packaging: NetSyncAvatar.cs:55-85 implements excellent object pooling to avoid GC pressure:

    private ClientTransformData _tx;
    private TransformData _txPhysical;
    // ... reused every frame
  2. Efficient Message Draining: client_simulator.py:1070 implements time-budgeted message processing to avoid starvation.

Concerns

  1. Quaternion Operations: Multiple Quaternion.Normalize() calls per frame per transform. While necessary, this could add up with many remote avatars. Consider profiling.

  2. Buffer Size: PoseSnapshotBuffer defaults to 32 snapshots. At 120Hz, this is only 267ms of history. Ensure this is sufficient for the dynamic buffer multiplier logic.


Testing Recommendations

Before merging, please verify:

  1. Multi-client stress test: Run client_simulator.py with 50+ clients and verify smoothness
  2. Network jitter simulation: Test with artificial packet delay/loss
  3. Sequence wrap-around: Verify behavior when ushort sequence numbers wrap at 65535
  4. Edge cases:
    • Client joins with high latency
    • Sudden latency spike
    • Packet loss burst
    • Very low send rates (1-5Hz)

Code Quality Checklist

Per CLAUDE.md requirements:

Python Server

  • Run black src/ tests/ (formatting)
  • Run ruff check src/ tests/ (linting)
  • Run mypy src/ (type checking)
  • Run pytest (tests)

Unity Client

  • Verify compilation in Unity Editor
  • Test in demo scenes
  • Check console for errors/warnings

Conclusion

This PR represents a significant improvement to the transform synchronization system. The architecture is sound, and the implementation shows good understanding of networked VR challenges. However, the issues identified above (especially the null propagation violations and thread safety concerns) should be addressed before merging.

Recommended Actions:

  1. Fix null propagation operators per CLAUDE.md
  2. Add documentation for key algorithms
  3. Consider adding unit tests for smoothing logic
  4. Run full code quality pipeline before merge

Great work on improving the smoothness of the system! The snapshot interpolation with adaptive smoothing should provide much better user experience.


@from2001 from2001 changed the title Improve smoothing, lerp or interpolation of transform sync [Merge with Minor version increment] Improve smoothing, lerp or interpolation of transform sync Jan 25, 2026
@from2001 from2001 marked this pull request as ready for review January 26, 2026 11:26
@from2001 from2001 merged commit 75903cf into develop Jan 26, 2026
@from2001 from2001 deleted the improve/smoothness branch January 26, 2026 11:26
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