Skip to content

Avatar sinks below the floor on first load (desktop mode) when eye height is below 1.61 m #802

@minetake01

Description

@minetake01

Describe the bug?

On desktop mode, loading an avatar whose eye height is shorter than the 1.61 m fallback causes the avatar root to be placed below the floor on every frame until manual full-body calibration is performed. The feet visually sink into the floor up to roughly knee depth.

The issue persists after the T-pose phase ends and continues throughout normal play.

Steps to Reproduce

  1. Launch BasisVR in desktop mode (no HMD connected).
  2. Load any avatar whose eye height is below 1.61 m (e.g. a small/short humanoid avatar).
  3. Observe the avatar immediately after loading — the feet sink into the floor.
  4. Confirm the sinking persists in normal play (T-pose phase over, IK active).
  5. Perform a full-body calibration (Settings → Calibration). Observe the avatar returns to the correct floor level.

The expected behavior

The avatar should stand with its feet on the floor immediately after loading, without requiring a manual full-body calibration.

Screenshots

Image

Build Info

Version: 2.0.1
Unity: 6000.4.5f1
Platform: WindowsEditor
Mode: Desktop
Build GUID: 00000000000000000000000000000000

Log Files

N/A

Additional Context

PlayerEyeHeight defaults to 1.61 m (BasisHeightDriver.cs L29) and is only updated by CapturePlayerHeight(), which is called during full-body calibration. On desktop mode there is no HMD to measure the real player height, so the value stays at 1.61 m.

DeviceScale is then computed as (BasisHeightDriver.cs L287–L290):

float avatarScaledMetric = SelectedUnScaledAvatarHeight * AppliedUpScale;  // e.g. 1.12
float playerMetric       = AdditionalPlayerHeight + SelectedUnScaledPlayerHeight; // 0 + 1.61
DeviceScale = avatarScaledMetric / playerMetric;  // → 0.696

BasisDesktopEye uses DeviceScale to project the simulated head position (BasisDesktopEye.cs L314–L316):

ScaledDeviceCoord.position = OffsetCoords.position
    + (OffsetCoords.rotation * (UnscaledDeviceCoord.position * deviceScale));

Unlike VR, the desktop UnscaledDeviceCoord is already sourced from the avatar's T-pose bone positions, not a real-world HMD measurement. Multiplying by DeviceScale < 1 pushes the simulated head below its correct height:

ScaledDeviceCoord.y = 1.12 × 0.696 = 0.78 m

DriveTpose() then places the avatar root at headPosWS − TposeLocalScaled.head (BasisLocalPlayer.cs L534–L536):

avatarRoot.y = 0.78 − 1.12 = −0.34 m  (34 cm below the floor)

This is applied every frame while CurrentlyTposing == true, and the incorrect DeviceScale carries over into the IK phase after T-pose ends.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions