Anleitung zur Anpassung des Arbeitsbereichs des Geräts
Dieses Tutorial knüpft an das Grundlegendes Tutorial zur Force-Feedback-Funktion indem gezeigt wird, wie man die Position, die Drehung und die Skalierung des Geräts anpasst Inverse3 mithilfe seiner Eigenschaften und Methoden zur räumlichen Transformation.
Einführung
Nachdem Sie die Szene für die grundlegende Haptik-Rückmeldung konfiguriert haben, stellen Sie möglicherweise fest, dass Anpassungen an „Haptic Origin“ oder „Haptic Controller“ (wie Verschieben, Skalieren oder Drehen) die haptische Rückmeldung nicht wie erwartet beeinflussen. Die Haptik-Rückmeldung entspricht immer einer unsichtbaren Kugel vor dem Gerät, die von diesen Transformationen nicht beeinflusst wird.

Diese Abweichung lässt sich dadurch erklären, dass bei den Kraftberechnungen die tatsächlichen, nicht transformierten Koordinaten des Cursors des Geräts verwendet werden. Um dieses Problem zu beheben, werden wir die zwischengespeicherten und thread-sicheren Transformationsmatrizen verwenden, die von der Komponente „Inverse3 -Controller“ bereitgestellt werden. Auf diese Weise können wir Weltraumtransformationen auf die Berechnungen der haptischen Rückmeldung anwenden.
Einrichtung der Szene
Beginnen Sie mit der Szene aus dem Tutorial „Grundlegende Force-Feedback-Funktionen“ und stellen Sie sicher, dass die Ausrichtung des „Inverse3 -Controllers“ mit der Ihres Geräts übereinstimmt. Drehen Sie den „Haptic-Controller“ so, dass das „ Haply “-Logo zur Kamera zeigt, und passen Sie dann den Maßstab von „Haptic Origin“ nach Bedarf an, um den Bewegungsbereich des Cursors zu vergrößern oder dessen Position zu ändern.


Änderungen am Skript für die Rückkopplung
Kopieren Sie das Skript SphereForceFeedback.cs Beziehen Sie sich auf das Tutorial zur grundlegenden Rückkopplung und nehmen Sie die folgenden Änderungen in der Rückruf-Funktion vor OnDeviceStateChanged :
- Ersetzen Sie
device.CursorLocalPositionpardevice.CursorPosition. - Ersetzen Sie
device.CursorLocalVelocitypardevice.CursorVelocity. - Ersetzen Sie
device.CursorSetLocalForce(force)pardevice.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);
}
Spielerlebnis
Halten Sie den Cursor auf „ Inverse3 “ und wechseln Sie in den Wiedergabemodus. Versuchen Sie, die Kugel wie im vorherigen Beispiel zu berühren. Sie sollten nun ein präzises haptisches Feedback spüren, das die auf „Haptic Origin“ und „Haptic Controller“ angewendeten Transformationen widerspiegelt.

Quelldateien
Die komplette Szene und die zu diesem Beispiel gehörenden Dateien können aus dem Beispiel „Tutorials“ im Unity Package Manager importiert werden.
Die Beispielszene enthält zusätzliche Skripte, mit denen sich der Haptic Controller und der Haptic Origin zur Laufzeit anpassen lassen.
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);
}
}
}