Tutoriel sur la transformation de l'espace de travail des appareils
Ce tutoriel développe le Force de base - Retour d'information en montrant comment ajuster la position, la rotation et la mise à l'échelle de l'image. Inverse3
en utilisant ses propriétés et méthodes de transformation de l'espace.
Introduction
Après avoir configuré la scène pour un retour de force de base, vous pouvez remarquer que les ajustements de l'origine haptique ou du contrôleur haptique, tels que ledéplacement, la mise à l'échelle ou la rotation, n'affectent pas le retour haptique comme prévu. Le retour d'information correspond toujours à une sphère invisible située devant l'appareil, qui n'est pas affectée par ces transformations.
Cette divergence est due au fait que les calculs de force utilisent les coordonnées réelles, non transformées, du curseur de l'appareil. Pour y remédier, nous utiliserons les matrices de transformation mises en cache à l'abri des threads fournies par le composant Inverse3 Controller, ce qui nous permettra d'appliquer les transformations de l'espace mondial aux calculs du retour haptique.
Configuration de la scène
Commencez par la scène du tutoriel Basic Force-Feedback, en vous assurant que la main du Inverse3 Controller correspond à votre appareil. Faites pivoter le contrôleur haptique de manière à ce que le logo Haply soit face à la caméra, et ajustez l'échelle de l'origine haptique comme vous le souhaitez pour améliorer la portée du curseur ou ajuster sa position.
Modifications du script de retour de force
Copier le SphereForceFeedback.cs
du didacticiel Basic Force-Feedback et effectuer les ajustements suivants dans le fichier OnDeviceStateChanged
rappel :
- Remplacer
device.CursorLocalPosition
avecdevice.CursorPosition
. - Remplacer
device.CursorLocalVelocity
avecdevice.CursorVelocity
. - Remplacer
device.CursorSetLocalForce(force)
avecdevice.CursorSetForce(force)
.
private void OnDeviceStateChanged(Inverse3 device) {
var force = ForceCalculation(device.CursorPosition, device.CursorVelocity,
_cursorRadius, _ballPosition, _ballRadius);
device.CursorSetForce(force);
}
Expérience de jeu
Maintenez le curseur Inverse3 et entrez dans le mode Play. Essayez de toucher la sphère comme dans l'exemple précédent. Vous devriez maintenant bénéficier d'un retour haptique précis qui reflète les transformations appliquées à l'origine haptique et au contrôleur haptique.
Fichiers sources
La scène complète et les fichiers associés de cet exemple peuvent être importés depuis l'échantillon Tutorials dans le Unity Package Manager.
La scène d'exemple comprend des scripts supplémentaires pour les réglages du contrôleur haptique et de l'origine haptique au cours de l'exécution.
SphereForceFeedback.cs
/*
* Copyright 2024 Haply Robotics Inc. All rights reserved.
*/
using Haply.Inverse.Unity;
using UnityEngine;
using UnityEngine.Serialization;
namespace Haply.Samples.Tutorials._3_DeviceSpaceTransform
{
public class SphereForceFeedback : MonoBehaviour
{
// must assign in inspector
public Inverse3 inverse3;
[Range(0, 800)]
// Stiffness of the force feedback.
public float stiffness = 300f;
[Range(0, 3)]
public float damping = 1f;
private Vector3 _ballPosition;
private float _ballRadius;
private float _cursorRadius;
/// <summary>
/// Stores the cursor and sphere transform data for access by the haptic thread.
/// </summary>
private void SaveSceneData()
{
var t = transform;
_ballPosition = t.position;
_ballRadius = t.lossyScale.x / 2f;
_cursorRadius = inverse3.Cursor.Model.transform.lossyScale.x / 2f;
}
/// <summary>
/// Saves the initial scene data cache.
/// </summary>
private void Awake()
{
SaveSceneData();
}
/// <summary>
/// Subscribes to the DeviceStateChanged event.
/// </summary>
private void OnEnable()
{
inverse3.DeviceStateChanged += OnDeviceStateChanged;
}
/// <summary>
/// Unsubscribes from the DeviceStateChanged event.
/// </summary>
private void OnDisable()
{
inverse3.DeviceStateChanged -= OnDeviceStateChanged;
}
/// <summary>
/// Calculates the force based on the cursor's position and another sphere position.
/// </summary>
/// <param name="cursorPosition">The position of the cursor.</param>
/// <param name="cursorVelocity">The velocity of the cursor.</param>
/// <param name="cursorRadius">The radius of the cursor.</param>
/// <param name="otherPosition">The position of the other sphere (e.g., ball).</param>
/// <param name="otherRadius">The radius of the other sphere.</param>
/// <returns>The calculated force vector.</returns>
private Vector3 ForceCalculation(Vector3 cursorPosition, Vector3 cursorVelocity, float cursorRadius,
Vector3 otherPosition, float otherRadius)
{
var force = Vector3.zero;
var distanceVector = cursorPosition - otherPosition;
var distance = distanceVector.magnitude;
var penetration = otherRadius + cursorRadius - distance;
if (penetration > 0)
{
// Normalize the distance vector to get the direction of the force
var normal = distanceVector.normalized;
// Calculate the force based on penetration
force = normal * penetration * stiffness;
// Apply damping based on the cursor velocity
force -= cursorVelocity * damping;
}
return force;
}
/// <summary>
/// Event handler that calculates and send the force to the device when the cursor's position changes.
/// </summary>
/// <param name="device">The Inverse3 device instance.</param>
private void OnDeviceStateChanged(Inverse3 device)
{
// Calculate the ball force. Using 'device.CursorPosition' instead of 'device.CursorLocalPosition'
// ensures the force calculation considers the device's offset and rotation in world space.
var force = ForceCalculation(device.CursorPosition, device.CursorVelocity,
_cursorRadius, _ballPosition, _ballRadius);
// Apply the calculated force to the cursor. Using 'device.CursorSetForce' instead of
// 'device.CursorSetLocalForce' ensures that the force vector is correctly converted
// from world space to the device's local space.
device.CursorSetForce(force);
}
}
}