VR4RoboticArm2/VR4RoboticArm/Library/PackageCache/com.meta.xr.sdk.interaction.ovr/Runtime/Sample/Scripts/PassThrough/MRPassThroughHandVisualize.cs
IonutMocanu d7aba243a2 Main
2025-09-08 11:04:02 +03:00

201 lines
7.3 KiB
C#

/*
* 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 Oculus.Interaction.Input;
using System.Collections.Generic;
using UnityEngine;
namespace Oculus.Interaction.Samples
{
/// <summary>
/// The MRPassThroughVisulaize is used when in MR passthrough is toggled on the hand will not have
/// an overlay of a 3d object hand overlaying the hand. When the hand overlaps a 3d object or a
/// canvas it will then apply 3d in game hand overlay over the hand so that details are not lost
/// or confused when interacting with 3d objects.
/// </summary>
public class MRPassThroughHandVisualize : MonoBehaviour
{
[SerializeField]
private List<Transform> _eyeAnchors;
[SerializeField]
private HandVisual _handVisual;
[Header("Raycast Properties")]
[SerializeField]
private LayerMask _layer;
[SerializeField]
private float _sphereRadius;
[SerializeField]
private float _castDistance;
[Header("Material Properties")]
[SerializeField]
private MaterialPropertyBlockEditor[] _handMaterialPropertyBlocks;
[SerializeField]
private float _opacity;
[SerializeField]
private float _outlineOpacity;
[SerializeField]
private float _animationSpeed;
private float _currentOpacity;
private float _currentOutlineOpacity;
private readonly int _opacityId = Shader.PropertyToID("_Opacity");
private readonly int _outlineOpacityId = Shader.PropertyToID("_OutlineOpacity");
private (Vector3, float) _palmTarget;
private readonly HandJointId[] _handJointTargets = new HandJointId[]
{
HandJointId.HandIndex2,
HandJointId.HandIndex3,
HandJointId.HandThumb2,
HandJointId.HandThumb3,
HandJointId.HandMiddle2,
HandJointId.HandMiddle3,
HandJointId.HandRing2,
HandJointId.HandRing3,
HandJointId.HandPinky2,
HandJointId.HandPinky3,
};
private Ray[] _eyeRays;
private bool _started = false;
private void Start()
{
this.BeginStart(ref _started);
this.AssertField(_handVisual, nameof(_handVisual));
this.AssertCollectionField(_handMaterialPropertyBlocks, nameof(_handMaterialPropertyBlocks));
this.EndStart(ref _started);
_eyeRays = new Ray[_eyeAnchors.Count];
_currentOpacity = _opacity;
_currentOutlineOpacity = _outlineOpacity;
var palmJoints = new List<Vector3>(){
_handVisual.GetJointPose(HandJointId.HandWristRoot, Space.World).position,
_handVisual.GetJointPose(HandJointId.HandThumb1, Space.World).position,
_handVisual.GetJointPose(HandJointId.HandIndex1, Space.World).position,
_handVisual.GetJointPose(HandJointId.HandMiddle1, Space.World).position,
_handVisual.GetJointPose(HandJointId.HandRing1, Space.World).position,
_handVisual.GetJointPose(HandJointId.HandPinky1, Space.World).position,
};
var palmCenter = Vector3.zero;
foreach (var origin in palmJoints)
{
palmCenter += origin;
}
palmCenter *= (1.0f / (float)palmJoints.Count);
var WristTransform = _handVisual.GetTransformByHandJointId(HandJointId.HandWristRoot);
var palmCenterWrist = WristTransform.InverseTransformPoint(palmCenter);
var maxDistance = 0.0f;
foreach (var origin in palmJoints)
{
maxDistance = Mathf.Max(maxDistance, Vector3.Distance(palmCenter, origin));
}
_palmTarget = (palmCenterWrist, maxDistance * 0.65f);
}
private bool SphereCast(Vector3 target, float radius)
{
for (int i = 0; i < _eyeAnchors.Count; i++)
{
var AnchorPosition = _eyeAnchors[i].position;
var AnchorDirection = (target - AnchorPosition).normalized;
_eyeRays[i] = new Ray(AnchorPosition, AnchorDirection);
}
foreach (var ray in _eyeRays)
{
if (Physics.SphereCast(ray, radius, _castDistance, _layer))
{
return true;
}
}
return false;
}
private bool SphereCastAllTargets()
{
var WristTransform = _handVisual.GetTransformByHandJointId(HandJointId.HandWristRoot);
var PalmCenter = WristTransform.TransformPoint(_palmTarget.Item1);
if (SphereCast(PalmCenter, _palmTarget.Item2))
{
return true;
}
foreach (var joint in _handJointTargets)
{
var pose = _handVisual.GetJointPose(joint, Space.World);
if (SphereCast(pose.position, _sphereRadius))
{
return true;
}
}
return false;
}
private void UpdateMaterialPropertyBlock(bool sphereCastHit)
{
var targetOpacity = sphereCastHit ? _opacity : 0.0f;
var targetOutlineOpacity = sphereCastHit ? _outlineOpacity : 0.0f;
var animParam = _animationSpeed * Time.deltaTime;
_currentOpacity = Mathf.Lerp(_currentOpacity, targetOpacity, animParam);
_currentOutlineOpacity = Mathf.Lerp(_currentOutlineOpacity, targetOutlineOpacity, animParam);
foreach (var handMaterialPropertyBlock in _handMaterialPropertyBlocks)
{
handMaterialPropertyBlock.MaterialPropertyBlock.SetFloat(_opacityId, _currentOpacity);
handMaterialPropertyBlock.MaterialPropertyBlock.SetFloat(_outlineOpacityId, _currentOutlineOpacity);
}
}
private void Update()
{
if (MRPassthrough.PassThrough.IsPassThroughOn)
{
if (_eyeAnchors == null || _handVisual == null)
{
return;
}
UpdateMaterialPropertyBlock(SphereCastAllTargets());
}
else
{
foreach (var handMaterialPropertyBlock in _handMaterialPropertyBlocks)
{
handMaterialPropertyBlock.MaterialPropertyBlock.SetFloat(_opacityId, _opacity);
handMaterialPropertyBlock.MaterialPropertyBlock.SetFloat(_outlineOpacityId, _outlineOpacity);
}
}
}
}
}