Passer directement au contenu principal

Tutoriel sur la conversion de l'espace de travail des périphériques

Ce tutoriel estRetour d'information tactile de baseIl s'agit d'une extension du tutoriel qui utilise les propriétés et les méthodes de transformation spatiale pour Inverse3 Nous allons vous expliquer comment ajuster la position, la rotation et la mise à l'échelle d'un élément.

Introduction​

Après avoir configuré une scène avec un retour de force de base, vous remarquerez peut-être que, même lorsque vous déplacez, redimensionnez ou faites pivoterHaptic Origin ou Haptic Controller, ces modifications ne se répercutent pas comme prévu sur le retour de force. Le retour de force correspond toujours à une sphère invisible située à l'avant de l'appareil et n'est donc pas affecté par ces transformations.

Exemple où la conversion de l'espace de travail n'est pas prise en compte

Cette incohérence est due au fait que le calcul de la force utilise les coordonnées réelles du curseur de l'appareil, qui n'ont pas été transformées. Pour y remédier, il convient d'utiliserla matrice de transformation mise en cacheetsûre pour les threadsfournie par le composant«Inverse3 Controller », afin de pouvoir appliquer la transformation dans l'espace mondial au calcul du retour de force.

Mise en place de la scène​

Commencez par la scène du tutoriel sur le retour haptique de baseet assurez-vous que la configuration dela main dominantede la manetteInverse3 correspond bien à celle de votre appareil. Faites pivoterla manette Haptic Controller de manière à ce que le logo « Haply » soit tourné vers la caméra, puis ajustez si nécessaire l'échelle de Haptic Origin afin d'élargir la plage de déplacement du curseur ou d'ajuster sa position.

Inverse3 Configuration pour droitiers

Conversion de l'espace de travail (système de coordonnées à droite)

Modifications apportées au script de rétroaction de la force​

À partir du tutoriel sur le retour de force de base SphereForceFeedback.cs Copiez le script, puisOnDeviceStateChanged Veuillez apporter les modifications suivantes dans la fonction de rappel.

  • device.CursorLocalPosition を device.CursorPosition par.
  • device.CursorLocalVelocity を device.CursorVelocity par.
  • device.CursorSetLocalForce(force) を device.CursorSetForce(force) par.
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​

Inverse3 Passez en mode « Play » tout en maintenant le curseur enfoncé. Comme dans l'exemple précédent, essayez de toucher la sphère. Vous devriez pouvoir ressentir un retour haptique précis, reflétant les transformations appliquées à «Haptic Origin » et « Haptic Controller ».

Le curseur agrandi entrant en contact avec la sphère

Fichier source​

Vous pouvez importer la scène complète de cet exemple ainsi que les fichiers associés à partir de l'exemple « Tutorials » disponible dans le Package Manager de Unity.

Cette scène d'exemple contient 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);
}
}
}