Einführung in das Force-Feedback
In diesem Tutorial simulieren wir die physikalischen Eigenschaften beim Kontakt mit statischen Objekten wie Kugeln und führen Sie durch den Prozess der Erstellung einer grundlegenden haptischen Simulation, die sowohl Steifigkeit als auch Dämpfung berücksichtigt. Am Ende dieses Tutorials haben Sie eine Simulation erstellt, mit der Sie die Anwesenheit der Kugel spüren können und deren Steifigkeits- und Dämpfungseigenschaften Sie für verschiedene haptische Erlebnisse anpassen können.
Einführung
Die zentrale Aufgabe dieses Tutorials besteht darin, eine Funktion zu entwickeln, mit der sich die Kräfte berechnen lassen, die beim Kontakt mit einer Kugel entstehen, die sowohl Steifigkeitals auch Dämpfungaufweist. In diesem Zusammenhang wirkt die Steifigkeit wie eine Feder: Je stärker die Kugel zusammengedrückt wird, desto größer ist die Kraft, die dabei entsteht. Die Dämpfung hingegen stellt einen Widerstand gegen die Bewegung des Objekts dar: Je schneller sich das Objekt bewegt, desto größer ist der Widerstand.
Szene-Einstellungen
Leitfaden für den EinstiegBeginnen Sie damit, das Haptic Rig wie dort beschrieben einzurichten, und Haptischer UrsprungPosition, Drehung und Skalierung jeweils (0, 0, 0)und (1, 1, 1)Bitte stellen Sie sicher, dass die Einstellung auf … gesetzt ist.
Anschließend mit den folgenden Eigenschaften SphereErstellen Sie eine Kugel mit dem Namen:
- Standort:
(0, 0, -0.1)(ca. 10 cm vor dem Gerät) - Maßstab:
(0.2, 0.2, 0.2)(entspricht einer Kugel mit einem Durchmesser von 20 cm)
Force-Feedback-Skript
Sphäre Auf das GameObject SphereForceFeedback.csFügen Sie ein neues C#-Skript mit dem Namen „“ hinzu.
Dieses Skript berechnet die Kraft, die beim Kontakt mit einer Kugel auf den Cursor „ Inverse3 “ wirkt, unter Berücksichtigung sowohl der Steifigkeit als auch der Dämpfung.
Initialisieren Sie das Skript mit den folgenden Eigenschaften:
[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;
Die Kraftberechnung darf nur dann erfolgen, wenn der Cursor in die Kugel eindringt; dadurch wird das Gefühl simuliert, ein reales Objekt mit definierter Steifigkeit und Dämpfung zu berühren.
Dafür zuständig ist ForceCalculation Es handelt sich um eine Methode, die sowohl die Position als auch die Geschwindigkeit des Cursors berücksichtigt:
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 Um in der Methode Szenendaten festzulegen, _ballPosition, _ballRadius, _cursorRadiusBitte initialisieren Sie:
private void SaveSceneData()
{
var t = transform;
_ballPosition = t.position;
_ballRadius = t.lossyScale.x / 2f;
_cursorRadius = inverse3.Cursor.Radius;
}
private void Awake()
{
SaveSceneData();
}
Um die Kraftrückmeldung während der Interaktion korrekt zu verarbeiten, OnEnable sowie OnDisable In den jeweiligen Methoden OnDeviceStateChanged Der Callback muss registriert und wieder aufgehoben werden:
protected void OnEnable()
{
inverse3.DeviceStateChanged += OnDeviceStateChanged;
}
protected void OnDisable()
{
inverse3.DeviceStateChanged -= OnDeviceStateChanged;
}
Spielerlebnis
Inverse3 Wechseln Sie mit dem Cursor im Play-Modus in den Interaktionsmodus und berühren Sie die Kugel. Sie sollten die Präsenz der Kugel spüren können. Über den Unity Inspector können Sie die Steifigkeit und die Dämpfungseigenschaften der Kugel anpassen und so eine realistische Interaktion mit dem virtuellen Objekt erleben.

Quelldatei
Alle Dateien, die zur gesamten Szene dieses Beispiels gehören, können aus den Tutorials-Beispielen im Unity Package Manager heruntergeladen werden.
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);
}
}
}