GetTrackingData(VRCPlayerApi.TrackingDataType.AvatarRoot) fails when not grounded
Shiro K
Based on this Canny, the new AvatarRoot TrackingDataType was introduced:
In FBT, it returns the root rotation independent from head rotation, as long a player stays somewhere. This works fine, as long the player is grounded, but it fails during falling, hovering or swimming (IsGrounded = false, no movement). In this case, the head rotation will be returned, which is unexpected.
Expected Behaviour:
PlayerApi.GetTrackingData(VRCPlayerApi.TrackingDataType.AvatarRoot) return the same rotation as it was before the IK changes with PlayerApi.GetRotation(), independent if the player is grounded or not.
Reproducing steps:
Enter the sailing world in FBT and jump from the boat:
Watch back to the boat and turn your head. The issue occours when you don't move.
Log In
Shiro K
I had this issue again in another world I did. But there, I am permanently grounded. This made me to take a closer look on this issue again.
It looks like PlayerApi.GetTrackingData(VRCPlayerApi.TrackingDataType.AvatarRoot) works fine in every situation, grounded or not. It's PlayerApi.TeleportTo() which causes the issue, when the avatar root rotation will be set as input for it (in VR FBT only).
I have a world, where this will be demonstrated (Bug Booth 2):
I am not sure, but I guess TeleportTo() internally resets the rotation offset between avatar root and the head related rotation. There should be a way to suppress this in the TeleportTo() method (additioinal parameter?).
Shiro K
To add some more context:
When players are sailing, the sailboat does not move - the world moves instead. But when a player jumps from the sailboat, he has to be moved away from sailboat to be realistic.
Short version of the code which runs on a GameObject which follows the player:
void Update() {
VRCPlayerApi.TrackingData avatarRoot = playerApi.GetTrackingData(VRCPlayerApi.TrackingDataType.AvatarRoot);
transform.position = avatarRoot.position;
transform.rotation = avatarRoot.rotation;
// Before IK changes
// transform.position = playerApi.GetPosition();
// transform.rotation = playerApi.GetRotation();
if (swim) {
// Move the transform away from sailboat depending on its velocity/turn
transform.RotateAround(sailboat.transform.position, Vector3.up, -sailboat.resultingTurn * Time.deltaTime);
transform.position -= sailboat.syncedVelocityLocal * accelerationFactor * Time.deltaTime;
// Teleport the player to the new location
playerApi.TeleportTo(transform.position, transform.rotation, VRC_SceneDescriptor.SpawnOrientation.Default, true);
}
}
In this example the
avatarRoot.rotation
does not return the correct root rotation, as long the player is not grounded. As result, the head rotation will be applied for TeleportTo(...)
, which causes the issue.