/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using UnityEngine;
///
/// Represents the Pose of the anchor. Enabling it will localize the anchor.
///
///
/// This component can be accessed from an that supports it by calling
/// from the anchor.
/// This component needs to be enabled before requesting its Pose. See and
///
///
///
///
///
public readonly partial struct OVRLocatable : IOVRAnchorComponent, IEquatable
{
///
/// Tracking space position and rotation of the anchor
///
///
/// Position and rotation are both nullable and
/// and might be null independently if one of them or both are invalid.
///
///
///
///
///
///
///
public readonly struct TrackingSpacePose
{
///
/// Position in tracking space of the anchor
///
///
/// Null if and when the position is invalid
///
///
///
///
public Vector3? Position { get; }
///
/// Rotation in tracking space of the Anchor
///
///
/// Null if and when the rotation is invalid
///
///
///
///
public Quaternion? Rotation { get; }
///
/// Indicates whether or not the position is currently tracked
///
public bool IsPositionTracked => _flags.IsPositionTracked();
///
/// Indicates whether or not the rotation is currently tracked
///
public bool IsRotationTracked => _flags.IsOrientationTracked();
private readonly OVRPlugin.SpaceLocationFlags _flags;
internal TrackingSpacePose(Vector3 position, Quaternion rotation, OVRPlugin.SpaceLocationFlags flags)
{
_flags = flags;
Position = _flags.IsPositionValid() ? position : default(Vector3?);
Rotation = _flags.IsOrientationValid() ? rotation : default(Quaternion?);
}
///
/// Computes the world space position of the anchor
///
/// A component that will be use to compute the transform to world space
///
/// The nullable position in world space which may be
/// null if and when is invalid or head pose is invalid.
///
///
///
///
/// If is null
public Vector3? ComputeWorldPosition(Camera camera)
{
if (camera == null) throw new ArgumentNullException(nameof(camera));
if (!Position.HasValue) return null;
var headPose = OVRPose.identity;
if (!OVRNodeStateProperties.GetNodeStatePropertyVector3(UnityEngine.XR.XRNode.Head,
NodeStatePropertyType.Position, OVRPlugin.Node.Head, OVRPlugin.Step.Render, out headPose.position))
return null;
if (!OVRNodeStateProperties.GetNodeStatePropertyQuaternion(UnityEngine.XR.XRNode.Head,
NodeStatePropertyType.Orientation, OVRPlugin.Node.Head, OVRPlugin.Step.Render,
out headPose.orientation))
return null;
headPose = headPose.Inverse();
var headTrackingPosition = headPose.position + headPose.orientation * Position.Value;
return camera.transform.localToWorldMatrix.MultiplyPoint(headTrackingPosition);
}
///
/// Computes the world space rotation of the anchor
///
/// A component that will be use to compute the transform to world space
///
/// The nullable rotation in world space which may be
/// null if and when is invalid or if head rotation is invalid.
///
///
///
///
/// If is null
public Quaternion? ComputeWorldRotation(Camera camera)
{
if (camera == null) throw new ArgumentNullException(nameof(camera));
if (!Rotation.HasValue) return null;
if (!OVRNodeStateProperties.GetNodeStatePropertyQuaternion(UnityEngine.XR.XRNode.Head,
NodeStatePropertyType.Orientation, OVRPlugin.Node.Head, OVRPlugin.Step.Render,
out var headPoseRotation))
return null;
headPoseRotation = Quaternion.Inverse(headPoseRotation);
var headTrackingOrientation = headPoseRotation * Rotation.Value;
return camera.transform.rotation * headTrackingOrientation;
}
}
///
/// Tries to get the representing the position and rotation of this anchor, treated as a scene anchor, in tracking space.
///
/// The out which will get filled in.
///
/// True if the request was successful, False otherwise.
///
///
/// Although the request may succeed and provide a valid , actual Position and Rotation provided
/// may not be valid and/or tracked, see for more information on how to use its data.
/// Scene anchors follow a different transform from the raw OpenXR data than spatial anchors'.
///
public bool TryGetSceneAnchorPose(out TrackingSpacePose pose)
{
if (!OVRPlugin.TryLocateSpace(Handle, OVRPlugin.GetTrackingOriginType(), out var posef, out var locationFlags))
{
pose = default;
return false;
}
// Transform from OpenXR Right-handed coordinate system
// to Unity Left-handed coordinate system with additional 180 rotation around +y
var position = posef.Position.FromFlippedZVector3f();
var rotation = new Quaternion(-posef.Orientation.z, posef.Orientation.w, -posef.Orientation.x,
posef.Orientation.y);
pose = new TrackingSpacePose(position, rotation, locationFlags);
return true;
}
///
/// Tries to get the representing the position and rotation of this anchor, treated as a spatial anchor, in tracking space.
///
/// The out which will get filled in.
///
/// True if the request was successful, False otherwise.
///
///
/// Although the request may succeed and provide a valid , actual position and rotation provided
/// may not be valid and/or tracked, see for more information on how to use its data.
/// Spatial anchors follow a different transform from the raw OpenXR data than scene anchors'.
///
public bool TryGetSpatialAnchorPose(out TrackingSpacePose pose)
{
if (!OVRPlugin.TryLocateSpace(Handle, OVRPlugin.GetTrackingOriginType(), out var posef, out var locationFlags))
{
pose = default;
return false;
}
// Transform from OpenXR Right-handed coordinate system
// to Unity Left-handed coordinate system
var position = posef.Position.FromFlippedZVector3f();
var rotation = posef.Orientation.FromFlippedZQuatf();
pose = new TrackingSpacePose(position, rotation, locationFlags);
return true;
}
}