Zum Hauptinhalt springen

Anleitung zur Transformation des Arbeitsraums von Geräten

Dieses Tutorial befindet sich unter Grundlegende Kraftrückmeldung Aufbauend auf dem Tutorial wird gezeigt, wie man mithilfe von Raumtransformationseigenschaften und -methoden Anpassungen vornimmt Inverse3 Position, Drehung und Skalierung des Objekts.

Einführung​

Nachdem Sie eine Szene für die grundlegende Kraftrückmeldung erstellt haben, werden Sie möglicherweise feststellen, dass sich die haptische Rückmeldung nicht wie erwartet ändert, wenn Sie den „Haptic Origin“ oder den „Haptic Controller“ verschieben, skalieren oder drehen. Die Rückmeldung bezieht sich weiterhin auf eine unsichtbare Kugel, die sich vor dem Gerät befindet, und wird von diesen Transformationen nicht beeinflusst.

Fehler bei der Arbeitsbereichsumsetzung

Der Grund für diese Abweichung liegt darin, dass bei der Kraftberechnung die tatsächlichen, untransformierten Koordinaten des Gerätekursors verwendet werden. Um dieses Problem zu beheben, werden wir dievon der „Inverse3 -Controller“-Komponente bereitgestellte , threadsichere Transformationsmatrix nutzen, um die Weltraumtransformation auf die Berechnung des haptischen Feedbacks anzuwenden.

Szeneneinstellungen​

Beginnen Sie mit der Szene aus dem Tutorial „Grundlagen der Kraftrückmeldung“ und stellen Sie sicher, dass die Einstellungen für die linke und rechte Hand des „Inverse3 -Controllers“ mit Ihrem Gerät übereinstimmen. Drehen Sie den Haptic-Controllerso, dass das „ Haply “-Logo zur Kamera zeigt, und passen Sie die Skalierung des „Haptic Origin“ nach Bedarf an, um den Cursorbereich zu vergrößern oder dessen Position anzupassen.

Inverse3 Einstellungen für die rechte Hand

Transformation des Arbeitsraums der rechten Hand

Änderungen am Skript für die Kraftrückmeldung​

Aus dem Tutorial zur grundlegenden Kraftrückmeldung kopiert SphereForceFeedback.cs Skript, und zwar in OnDeviceStateChanged Nehmen Sie im Rahmen des Callbacks folgende Anpassungen vor:

  • wird device.CursorLocalPosition Ersetzen durch device.CursorPosition。
  • wird device.CursorLocalVelocity Ersetzen durch device.CursorVelocity。
  • wird device.CursorSetLocalForce(force) Ersetzen durch 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);
}

Spielerlebnis​

Halten Sie den Cursor von „ Inverse3 “ gedrückt und wechseln Sie in den Wiedergabemodus. Versuchen Sie, wie im vorherigen Beispiel, die Kugel zu berühren. Nun sollten Sie ein präzises haptisches Feedback spüren, das die auf den „Haptic Origin“ und den „Haptic Controller“ angewendeten Transformationen widerspiegelt.

Der vergrößerte Cursor berührt die Kugel

Quelldatei​

Die vollständige Szene sowie die zugehörigen Dateien für dieses Beispiel können über den Unity-Paket-Manager aus den „Tutorials“-Beispielen importiert werden.

Das Beispielszenario enthält zusätzliche Skripte zur Anpassung des Haptic Controller und des Haptic Origin zur Laufzeit.

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