Aller au contenu principal

Tutoriel sur la transformation de l'espace de travail des équipements

Ce tutoriel se trouve sur Retour de force de base En s'appuyant sur ce tutoriel, nous allons approfondir le sujet et montrer comment utiliser les propriétés et méthodes de transformation spatiale pour ajuster Inverse3 Position, rotation et mise à l'échelle de l'équipement.

Présentation​

Une fois que vous aurez créé un scénario pour le retour haptique de base, vous remarquerez peut-être que lorsque vous déplacez, redimensionnez ou faites pivoter l'« Haptic Origin » ou l'« Haptic Controller », le retour haptique ne change pas comme prévu. Le retour haptique correspond toujours à une sphère invisible située à l'avant de l'appareil et n'est pas affecté par ces transformations.

Échec de la transformation de l'espace de travail

Cette divergence s'explique par le fait que le calcul des forces utilise les coordonnées réelles, non transformées, du curseur de l'appareil. Pour résoudre ce problème, nous utiliserons la matrice de transformation mise en cacheet sécurisée au niveau des threadsfournie par le composant « Inverse3 Controller », afin d'appliquer la transformation de l'espace mondial au calcul du retour tactile.

Mise en scène​

Commencez par le scénario présenté dans le tutoriel « Notions de base sur le retour de force » et assurez-vous que la configuration des mains gauche et droite de la manetteInverse3 correspond à celle de votre appareil. Faites pivoter la manette Haptic Controllerde manière à ce que le logo « Haply » soit tourné vers la caméra, puis ajustez le zoom de Haptic Origin selon vos besoins pour agrandir la zone couverte par le curseur ou modifier sa position.

Inverse3 Réglages pour la main droite

Transformation de l'espace de travail de la main droite

Modification du script de retour de force​

Copié à partir du tutoriel sur le retour de force de base SphereForceFeedback.cs le script, puis dans OnDeviceStateChanged Les ajustements suivants ont été effectués lors de la révision :

  • Va device.CursorLocalPosition Remplacer par device.CursorPosition。
  • Va device.CursorLocalVelocity Remplacer par device.CursorVelocity。
  • Va device.CursorSetLocalForce(force) Remplacer par device.CursorSetForce(force)。
private void OnDeviceStateChanged(object sender, Inverse3EventArgs args)
{
var inverse3 = args.DeviceController;
var force = ForceCalculation(inverse3.CursorPosition, inverse3.CursorVelocity,
_cursorRadius, _ballPosition, _ballRadius);

inverse3.SetCursorForce(force);
}

Expérience de jeu​

Placez le curseur sur Inverse3 et passez en mode lecture. Comme dans l'exemple précédent, essayez de toucher la sphère. Vous devriez désormais pouvoir ressentir un retour tactile précis, qui reflète les transformations appliquées à Haptic Origin et à Haptic Controller.

Le curseur agrandi touche la sphère

Fichier source​

Le scénario complet de cet exemple ainsi que les fichiers associés peuvent être importés à partir de la section « Tutorials » du gestionnaire de paquets Unity.

Les exemples de scénarios comprennent des scripts supplémentaires permettant de régler le contrôleur haptique et l'origine haptique lors de l'exécution.

SphereForceFeedback.cs​

/*
* Copyright 2024 Haply Robotics Inc. All rights reserved.
*/

using Haply.Inverse.DeviceControllers;
using Haply.Inverse.DeviceData;
using UnityEngine;

namespace Haply.Samples.Tutorials._3_DeviceSpaceTransform
{
public class SphereForceFeedback : MonoBehaviour
{
// must assign in inspector
public Inverse3Controller 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.Radius;
}

/// <summary>
/// Saves the initial scene data cache.
/// </summary>
private void Awake()
{
inverse3 ??= FindFirstObjectByType<Inverse3Controller>();
inverse3.Ready.AddListener((device, args) => 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;
inverse3.Release();
}

/// <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="sender">The Inverse3 data object.</param>
/// <param name="args">The event arguments containing the device data.</param>
private void OnDeviceStateChanged(object sender, Inverse3EventArgs args)
{
var inverse3 = args.DeviceController;
// Calculate the ball force. Using 'device.Position' instead of 'device.LocalPosition'
// ensures the force calculation considers the device's offset and rotation in world space.
var force = ForceCalculation(inverse3.CursorPosition, inverse3.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.
inverse3.SetCursorForce(force);
}
}
}