VRC Parent Constraint: Rebake Offsets When Unfrozen treats position and rotation offsets differently. Is this intended?

Hi! When a VRC Parent Constraint with multiple sources is unfrozen (Freeze To World turned off) with Rebake Offsets When Unfrozen enabled, position offsets and rotation offsets seem to be recalculated with different rules. I couldn’t find this described anywhere, so I’d like to check whether it is intended.

What I observed

  • Position offsets: the difference between the frozen position and the position the constraint would produce with its current offsets is added to every source’s Parent Position Offset (converted into that source’s local space). If nothing moved while frozen, position offsets do not change.
  • Rotation offsets: every source’s Parent Rotation Offset is set to the value that would make that source alone reproduce the frozen rotation, even if nothing moved while frozen.
  • Both rules apply to sources with weight 0 as well.

In every case the target stays exactly where it was frozen, so the rebake itself works. My question is only about how the offsets are distributed across the sources.

Setup

  • Unity 2022.3.22f1, Edit mode. Freeze To World was toggled on and then off from the Inspector (also reproduced with an editor script using SerializedObject).
  • SDK 3.10.5 and SDK 3.7.0 give identical results.
  • Target at the origin. Locked, Is Active and Rebake Offsets When Unfrozen are on. All offsets and At Rest values start at 0.
  • S0 is always at the origin with rotation (0,0,0) and weight 1.
Case S1 position / rotation / weight While frozen Offsets after unfreeze
1 (1,0,0) / (0,90,0) / 0 nothing moved S1 rotation offset → (0,-90,0). Position offsets unchanged.
2 (1,0,0) / (0,0,0) / 0 S0 moved to (0,1,0) S0 and S1 position offsets → (0,-1,0)
3 (1,0,0) / (0,0,0) / 1 nothing moved No change (target stays at (0.5,0,0))
4 (0,0,0) / (0,90,0) / 1 nothing moved Rotation offsets → S0 (0,45,0), S1 (0,-45,0)
5 (1,0,0) / (0,90,0) / 0 S0 moved to (1,0,0) Position offsets → S0 (-1,0,0), S1 (0,0,-1). S1 rotation offset → (0,-90,0).

Case 1 suggests that a rotation offset set on a weight-0 source does not survive a freeze/unfreeze cycle, even when nothing moved, while its position offset does.

Questions

  1. Is it intended that position offsets are shifted by the delta, while rotation offsets are recalculated per source?
  2. Is it intended that sources with weight 0 are rebaked as well?
  3. Does the VRChat client use the same rebake rules as the SDK in the Editor?

If this is the intended behavior, it would help a lot to have these rules described on the Constraints page. It currently only says that “the constraint will recalculate its offset relative to its sources when it is unfrozen”.

I can share the editor script I used to reproduce this if that helps.

I’m not very sure about this but one possible workaround would be to disable the “Rebake Offsets When Unfrozen” and then manually set up the offsets, if your setup doesn’t really require rebaking. If you do need it, you could try separating the different states into separate Parent Constraints and switching between them, although that would need testing to avoid snapping or other unexpected behavior.