1. Add haptics on hover and select
Right/Left Hand Controllerを同時に選択して Haptic Impulse Player をアタッチ- 以下のように左右それぞれに
XRI (Right/Left)/Haptic Deviceを設定 
- 以下のように左右それぞれに
- 続いて Simple Haptic Feedback を Interactor にアタッチする
- 今回は左右の
Right/Left Ray Interactorにアタッチ 
Play Select Entered、Play Hover Enteredを有効化する
Durationはバイブレーションの継続時間
- 今回は左右の
Haptic Impulse Player
- Haptic Impulse Player | XR Interaction Toolkit | 3.4.0
- Simple Haptic Feedback | XR Interaction Toolkit | 3.4.0
Player が Haptic を再生する
- Audio と同じで、この Player が Output に対して Haptic を再生している
- Inspector からは見えないがコードとしては以下の感じになっている。
[SerializeField]
XRInputHapticImpulseProvider m_HapticOutput = new XRInputHapticImpulseProvider("Haptic");
public bool SendHapticImpulse(float amplitude, float duration, float frequency)
{
return m_HapticOutput.GetChannelGroup()?.GetChannel()?.SendHapticImpulse(amplitude * m_AmplitudeMultiplier, duration, frequency) ?? false;
}Feedback は XR Interactable 用
- Simple Haptic Feedbackは XR Interactable のイベントに自動でハプティクスを紐付けるコンポーネント。
- 以下のように、
InteractorとHaptic Impulse Playerを受け取る - 内部では、受け取った
Interactorの Select/Hover の Entered/Exited に自身のイベントを紐づけるような Observer/Subscriber の形になっている - よって、Interactor が
XR Interactableに対して Hover / Select のイベントが発火すると、Simple Haptic Feedbackにもその通知が来て、Player の再生が実行される。
出力は Input System 経由で行う
- 少し不思議な感じがするが、Input System の Input Action の一つとして出力デバイスが設定される
- 先ほど出てきた
XRInputHapticImpulseProviderがそれに該当する。- Class XRInputHapticImpulseProvider | XR Interaction Toolkit | 3.4.0
- これが
IXRHapticImpulseProviderを実装している
- これが
- 基本的には
SendHapticImpulseメソッドを実装する ScriptableObject
- Class XRInputHapticImpulseProvider | XR Interaction Toolkit | 3.4.0
- 呼び出しとしては以下のような流れ
SendHapticImpulse() 呼び出し
│
▼
InputAction からデバイスを解決
│
▼
IHapticDevice.SendHapticImpulse() ← Input System のインターフェース
│
▼
OpenXR Runtime / プラットフォームドライバー
│
▼
物理コントローラー
Haptic Impulse Player
│
└─ Haptic Output(XRHapticImpulseProvider型)
│
└─ XRInputHapticImpulseProvider(ScriptableObjectアセット)
│
└─ Haptic Action
└─ Input Action Asset
└─ XRI Right Hand/Haptic Device 等
- このチュートリアルでは、Input System の Action (Input Action Reference) として実装されているが、以下のように Create メニューからも作成可能となっている

- その場合は、Object として参照を渡す

- Input System でも同様に行えるのは、Input System がそもそも「入力を受け取るもの」ではなく、「デバイスとの双方向チャネル」であるから
- Input System 内部で、
IHapticDeviceがハプティックフィードバック対応デバイスとして認識されており、内部でデバイスを解決している - 便利!
- Input System 内部で、
2. Add audio on hover or select
Left/Right Hand ControllerにSimple Audio Feedbackを追加する- Interactor Source に
Right/Left Ray Interactorをセット - Play Select Entered の
Select Entered Clipに Audio フォルダの音源をセット- Play Hover Entered にセットしてもOK
- Interactor Source に
![]() | ![]() |
|---|---|
3. Add 3D audio from the fireplace
- Unity - Manual: Audio Source
- 対象は暖炉内の Particle (
Particle_Fire)

4. Add a reverb zone

5. Experiment with spatializer plugins
-
Meta XR Audio SDK | Integration | Unity Asset Store
-
Unity用Meta XR Audio SDKプラグイン - 前提条件と設定 | Meta Horizon OS Developers
-
Meta XR Audio SDK Unity Plugin | Meta Horizon OS Developers
- Meta XR Audio SDKをダウンロードしてください。
- Meta XR Audioプラグインを設定して、音声の空間化を行います。
- 「Meta XR Audio Source」スクリプトを使用して、空間化処理、音響特性、ゲインブースト、リバーブ送出量を調整できます。
- Room Acoustics スクリプトを使用するオーディオミキサーで、残響の生成方法を変更できます。
- 部屋の音響発生源の位置、部屋の大きさ、材質、および障害物設定を調整します。
ambisonic audioを再生します。
-
以下の Sample を導入します

- いくつか Scene のサンプルがあるのでそれを参考にする
![]() | ![]() |
|---|---|
![]() | ![]() |
- チュートリアル - VRとMRで音声を空間化する | Meta Horizon OS Developers
- このチュートリアルに倣うのが近道
7. Extension activities
1. Add realistic bouncing sounds
ボールの跳ねる音を追加。ここでは衝突する素材に応じて音を変えるのではなく、速度に応じて音の大きさを変えるまで。
[RequireComponent(typeof(AudioSource)), RequireComponent(typeof(SphereCollider)), RequireComponent(typeof(Rigidbody))]
public class BallBounce : MonoBehaviour
{
[SerializeField]
private AudioClip audioClip;
private float minVelocity = 0.5f; // この速度以下は音を鳴らさない
private float maxVelocity = 5f; // この速度で最大音量
private AudioSource audioSource;
private Rigidbody rb;
private void Awake()
{
audioSource = GetComponent<AudioSource>();
rb = GetComponent<Rigidbody>();
}
private void OnCollisionEnter(Collision other)
{
var volumeScale = Mathf.InverseLerp(minVelocity, maxVelocity, rb.linearVelocity.magnitude);
audioSource.PlayOneShot(audioClip, volumeScale);
}
}magnitudeの範囲をどのように0-1に収めるかはいくつか方法があると思いますが、ここでは単純な方法で。- UE5 だと MapRange みたいのを探してしまうので、
InverseLerpがなかなか出てこなかった。。
- UE5 だと MapRange みたいのを探してしまうので、
2. Add a speaker
レコードプレイヤーを置いて、そこから音を鳴らし、レコード盤を回す。
- ほとんど、暖炉のときの設定を真似ています。値は適当であまり妥当性はありません。

レコード盤を回すのは特に工夫もなく以下のようにしました。とりあえずそれっぽく回ります。
public class RecordPlayer : MonoBehaviour
{
[SerializeField] private GameObject record;
// Update is called once per frame
private void Update()
{
record.transform.Rotate(new Vector3(0, 30 * Time.deltaTime, 0));
}
}








