跳至主要内容
版本: 2.2.0

基本力和位置教程

本指南提供了一个施加力和可视化 Inverse3 光标移动的简单演示。 最后,Inverse3 将模拟被虚拟橡皮筋拴在起始位置的感觉,同时球形 GameObject 将显示光标的位置。

导言

快速入门指南》介绍了Inverse3对象、其功能以及产生恒力的方法。 我们这里的目的是模拟光标上的橡皮筋效应。橡皮筋的行为类似于弹簧,这意味着它的力受其两端点之间的刚度和距离的影响。 因此,我们的目标是设计一个函数,在给定位置和刚度的情况下,产生一个力,使光标抵制远离原点的移动。

场景设置

首先通过GameObjects 游戏对象 > Haply菜单创建一个触觉装配(单手)

力和位置组件

选择 触觉起源 游戏对象,并添加一个名为 ForceAndPosition.cs 并填充 ForceAndPosition 类,代码如下

[SerializeField]
private Inverse3 inverse3 = null;

[SerializeField, Range(0, 400)]
private float stiffness = 100;

private Vector3 _initialPosition = Vector3.zero;

private Vector3 ForceCalculation(in Vector3 position)
{
if (_initialPosition == Vector3.zero)
{
// Save the initial device effector position
_initialPosition = position;
}
// Return force opposing movement from the initial position
return (_initialPosition - position) * stiffness;
}

该段将刚度设置为 100 牛顿/米(N/m),模拟相对较软的弹簧。 它还引入了 _initialPosition,一个捕捉光标起始位置的向量。 光标 ForceCalculation 方法在第一次执行时记录初始位置,随后计算与光标移动相对应的力输出。

纳入 OnDeviceStateChanged 中的回调 OnEnableOnDisable 方法,详见 快速入门指南:

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

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

游戏玩法

按住 Inverse3 光标,启动 "播放 "模式,并尝试操纵该装置。您会发现光标移动会产生一个力。 光标离起始位置越远,这种力就越明显。

光标移动

源文件

本示例使用的最终场景和所有相关文件都可以从 Unity 软件包管理器中的教程示例中导入。

ForceAndPosition.cs

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

using Haply.Inverse.Unity;
using UnityEngine;

namespace Haply.Samples.Tutorials._1_ForceAndPosition
{
/// <summary>
/// Demonstrates the application of force to maintain the cursor at its initial position.
/// </summary>
public class ForceAndPosition : MonoBehaviour
{
// Must be assigned in inspector
public Inverse3 inverse3;

[Range(0, 400)]
// Stiffness of the force feedback.
public float stiffness = 100;

// Stores the initial position of the cursor.
private Vector3 _initialPosition = Vector3.zero;

/// <summary>
/// Subscribes to the DeviceStateChanged event when the component is enabled.
/// </summary>
protected void OnEnable()
{
inverse3.DeviceStateChanged += OnDeviceStateChanged;
}

/// <summary>
/// Unsubscribes from the DeviceStateChanged event and reset the force when the component is disabled.
/// </summary>
protected void OnDisable()
{
inverse3.DeviceStateChanged -= OnDeviceStateChanged;
}

/// <summary>
/// Calculates the force required to maintain the cursor at its initial position.
/// </summary>
/// <param name="position">The current position of the cursor.</param>
/// <returns>The calculated force vector.</returns>
private Vector3 ForceCalculation(in Vector3 position)
{
if (_initialPosition == Vector3.zero)
{
// save the first device effector position
_initialPosition = position;
}
// return opposite force to stay at initial position
return (_initialPosition - position) * stiffness;
}

/// <summary>
/// Event handler that calculates and send the force to the device when the cursor's position changes.
/// </summary>
/// <param name="device">The Inverse3 device instance.</param>
private void OnDeviceStateChanged(Inverse3 device)
{
// Calculate the force.
var force = ForceCalculation(device.CursorLocalPosition);

// Apply the force to the cursor.
inverse3.CursorSetLocalForce(force);
}
}
} // namespace Haply.Samples.Tutorials._1_ForceAndPosition