Aller directement au corps du texte

Tutoriel de base sur le retour de force

Ce tutoriel vous guide dans la création d'une simulation haptique de base qui reproduit les propriétés physiques lors du contact avec un objet statique, tel qu'une sphère, en tenant compte à la fois de la rigidité et de l'amortissement. À l'issue de ce tutoriel, vous disposerez d'une simulation permettant de percevoir la présence de la sphère et d'ajuster les paramètres de rigidité et d'amortissement afin de créer diverses expériences haptiques.

Présentation​

L'objectif principal de ce tutoriel est de développer une fonction permettant de calculer la force générée lors du contact avec une sphère présentant à la fois une rigidité et un amortissement. Dans ce contexte, la rigidité agit comme un ressort : plus la sphère est comprimée, plus la force générée est importante. L'amortissement, quant à lui, représente la résistance au mouvement de l'objet : plus celui-ci se déplace rapidement, plus la résistance est importante.

Paramètres de la scène​

Guide de démarrageCommencez par configurer le Haptic Rig comme indiqué ci-dessus, et Origine haptiquela position, la rotation et l'échelle, respectivement (0, 0, 0)et (1, 1, 1)Vérifiez que ce paramètre est bien activé.

Ensuite, un élément présentant les propriétés suivantes : SphereCréez une sphère portant le nom suivant :

  • Lieu : (0, 0, -0.1) (à environ 10 cm à l'avant de l'appareil)
  • Échelle : (0.2, 0.2, 0.2) (ce qui correspond à une sphère de 20 cm de diamètre)

Script de retour de force​

Sphère Sur le GameObject SphereForceFeedback.csAjoutez un nouveau script C# portant ce nom. Ce script calcule la force exercée sur le curseur « Inverse3 » lors d'un contact avec une sphère, en tenant compte à la fois de la rigidité et de l'amortissement. Initialisez le script avec les propriétés suivantes :

[SerializeField]
private Inverse3 inverse3;

[Range(0, 800)]
public float stiffness = 300f;
[Range(0, 3)]
public float damping = 1f;

private Vector3 _ballPosition;
private float _ballRadius;
private float _cursorRadius;

Le calcul des forces ne doit avoir lieu que lorsque le curseur pénètre dans la sphère, ce qui permet de simuler la sensation de toucher un objet réel doté d'une rigidité et d'un amortissement définis. Cette fonction est assurée par ForceCalculation Il s'agit d'une méthode qui prend en compte à la fois la position et la vitesse du curseur :

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;
}

private void OnDeviceStateChanged(object sender, Inverse3EventArgs args)
{
var inverse3 = args.DeviceController;
// Calculate the ball force
var force = ForceCalculation(inverse3.CursorLocalPosition, inverse3.CursorLocalVelocity,
_cursorRadius, _ballPosition, _ballRadius);

inverse3.SetCursorLocalForce(force);
}

Awake Pour configurer les données de scène dans une méthode _ballPosition, _ballRadius, _cursorRadiusVeuillez initialiser :

private void SaveSceneData()
{
var t = transform;
_ballPosition = t.position;
_ballRadius = t.lossyScale.x / 2f;

_cursorRadius = inverse3.Cursor.Radius;
}

private void Awake()
{
SaveSceneData();
}

Afin de gérer correctement le retour de force lors des interactions, OnEnable et OnDisable Dans chaque méthode, OnDeviceStateChanged Vous devez enregistrer et désenregistrer la fonction de rappel :

protected void OnEnable()
{
inverse3.DeviceStateChanged += OnDeviceStateChanged;
}

protected void OnDisable()
{
inverse3.DeviceStateChanged -= OnDeviceStateChanged;
}

Expérience de jeu​

Inverse3 Avec le curseur sélectionné, passez en mode « Play » et essayez de toucher la sphère. Vous devriez pouvoir ressentir la présence de la sphère. Vous pouvez modifier ses propriétés de rigidité et d'amortissement via l'Inspector de Unity, ce qui vous permettra de vivre une interaction réaliste avec cet objet virtuel.

Le curseur en contact avec la sphère

Fichier source​

Tous les fichiers relatifs à la scène complète de cet exemple peuvent être récupérés dans la section « Tutorials » du Gestionnaire de paquets Unity.

SphereForceFeedback.cs​

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

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

namespace Haply.Samples.Tutorials._2_BasicForceFeedback
{
public class SphereForceFeedback : MonoBehaviour
{
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 ??= FindObjectOfType<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
var force = ForceCalculation(inverse3.CursorLocalPosition, inverse3.CursorLocalVelocity,
_cursorRadius, _ballPosition, _ballRadius);

inverse3.SetCursorLocalForce(force);
}
}
}