ソルバーの概要

ソルバーのメイン

ソルバーは、定義済みのアルゴリズムに従って、オブジェクトの位置と方向を計算する手段を容易にするコンポーネントです。 たとえば、ユーザーの視線入力レイキャストが現在ヒットしているサーフェスにオブジェクトを配置します。

さらに、コンポーネントの更新順序を Unity に指定する信頼できる方法がないため、ソルバー システムでは、これらの変換計算の操作の順序を確定的に定義します。

ソルバーでは、オブジェクトを他のオブジェクトまたはシステムにアタッチするためのさまざまな動作が提供されます。 もう 1 つの例は、(カメラに基づいて) ユーザーの前に浮遊するタグに沿ったオブジェクトです。 ソルバーをコントローラーとオブジェクトにアタッチして、オブジェクトをタグに沿ったコントローラーにすることもできます。 すべてのソルバーを安全にスタックすることができます。たとえば、タグに沿った動作 + 表面磁性 + 勢いです。

ソルバーの使用方法

ソルバー システムは、次の 3 つのカテゴリのスクリプトで構成されます。

  • Solver: すべてのソルバーの派生元である基本抽象クラス。 状態の追跡、パラメーターと実装のスムージング、自動的なソルバー システムの統合、更新順序が提供されます。
  • SolverHandler: 追跡する参照オブジェクト (メイン カメラの変換、ハンド レイなど) を設定して、ソルバー コンポーネントの収集を処理し、適切な順序でそれらの更新を実行します。

3 番目のカテゴリはソルバー自体です。 次のソルバーでは、基本動作のための構成要素が提供されます。

  • Orbital: 参照されるオブジェクトから指定された位置およびオフセットにロックします。
  • ConstantViewSize: 参照されるオブジェクトのビューに対して一定のサイズが維持されるようにスケーリングします。
  • RadialView: 参照されるオブジェクトによってキャストされたビュー コーン内のオブジェクトを保持します。
  • Follow: 参照されるオブジェクトの一連のユーザー定義の境界内にオブジェクトを保持します。
  • InBetween: 2 つの追跡対象オブジェクトの間にオブジェクトを保持します。
  • SurfaceMagnetism: ワールド内のサーフェスにレイをキャストし、そのサーフェスにオブジェクトを合わせます。
  • DirectionalIndicator: オブジェクトの位置と方向を方向インジケーターとして決定します。 SolverHandler の追跡対象の参照ポイントから、このインジケーターは指定された DirectionalTarget の方法を向きます。
  • Momentum: 他のソルバー/コンポーネントによって移動されるオブジェクトの勢いと弾力性をシミュレートするために、加速/ベロシティ/摩擦を適用します。
  • HandConstraint: GameObject と手が交差しない領域で、オブジェクトが手に従うように制約します。 メニューなどの手に制約される対話型コンテンツで役に立ちます。このソルバーは IMixedRealityHand で使用することが意図されていますが、IMixedRealityController でも動作します。
  • HandConstraintPalmUp: HandConstraint から派生しますが、アクティブにされる前に、手のひらがユーザーの方を向いているかどうかをテストするロジックが含まれています。 このソルバーは IMixedRealityHand コントローラーでのみ機能します。他のコントローラーの種類では、このソルバーはその基本クラスと同様に動作します。

ソルバー システムを使用するには、上記のいずれかのコンポーネントを GameObject に単純に追加します。 すべてのソルバーで SolverHandler が必要となるため、Unity によって自動的に作成されます。

注意

ソルバー システムの使用方法の例については、SolverExamples.scene ファイルを参照してください。

追跡参照を変更する方法

SolverHandler コンポーネントの [追跡対象の種類] プロパティでは、すべてのソルバーでアルゴリズムを計算するために使用される参照ポイントを定義します。 たとえば、単純な SurfaceMagnetism コンポーネントを使用する Head の値の種類は、ヘッドからのレイキャストと、サーフェスがヒットしたものを解決するためのユーザーの視線入力の方向になります。 TrackedTargetType プロパティの有効な値を次に示します。

  • Head : 参照のポイントは、メイン カメラの変換です
  • ControllerRay: 参照のポイントは、ライン レイの方向を指すコントローラーの LinePointer 変換です (つまり、 モーション コントローラーまたはハンド コントローラー上のポインターの原点)
    • 利き手設定を選択するには、TrackedHandedness プロパティを使用します (つまり、 左、右、両方)
  • HandJoint: 参照のポイントは、特定のハンドジョイントの変換です
    • 利き手設定を選択するには、TrackedHandedness プロパティを使用します (つまり、 左、右、両方)
    • 使用するジョイント変換を決定するには、TrackedHandJoint プロパティを使用します
  • CustomOverride: 割り当てられた TransformOverride からの参照のポイント

注意

種類が ControllerRayHandJoint の場合、ソルバー ハンドラーでは最初に左コントローラー/ハンド変換を提供することが試みられます。次に、前者が使用できない場合、TrackedHandedness プロパティに他のものが指定されている場合を除き、右が提供されます。

ソルバー追跡オブジェクト 各 TrackedTargetType に関連付けられたさまざまなプロパティの例

重要

ほとんどのソルバーでは、SolverHandler によって提供される追跡対象の変換ターゲットの前方ベクトルが使用されます。 追跡対象の種類 [ハンド ジョイント] を使用する場合、パーム ジョイントの前方ベクトルは、手のひらを介さずに指を介してポイントされることがあります。 これは、ハンド ジョイントのデータを提供するプラットフォームに依存します。 入力シミュレーションと Windows Mixed Reality の場合、これは手のひらを介してポイントする "アップ ベクトル" です (つまり、 緑色のベクトルはアップで、青色のベクトルは前方です)。

前方アップ ベクトル

これを回避するには、SolverHandler[追加の回転] プロパティを <90、0、0> に更新します。 これにより、ソルバーに渡される前方ベクトルが、手のひらを介して手の外にポイントされます。

追加の回転

または、追跡対象の種類 [コントローラー レイ] を使用して、両手でポイントする場合と同様の動作を取得します。

ソルバーを連結する方法

同じ GameObject に複数の Solver コンポーネントを追加して、それらのアルゴリズムを連結することができます。 SolverHandler コンポーネントによって、同じ GameObject に対するすべてのソルバーの更新が処理されます。 既定では、起動時に SolverHandler によって GetComponents<Solver>() が呼び出され、インスペクターに表示される順序でソルバーが返されます。

さらに、 [更新されたリンクされた変換] プロパティを true に設定すると、すべてのソルバーで計算された位置、方向、スケールをアクセス可能な中間変数に保存するように Solver に指示します (つまり、 GoalPosition). false の場合、Solver によって GameObject の変換が直接更新されます。 変換プロパティを中間の場所に保存することにより、他のソルバーで中間変数から計算を実行できます。 これは、Unity では gameObject.transform への更新を同じフレーム内にスタックできないためです。

注意

開発者は、SolverHandler.Solvers プロパティを直接設定することによって、ソルバーの実行順序を変更できます。

新しいソルバーを作成する方法

すべてのソルバーは、抽象基本クラス (Solver) から継承される必要があり ます。 ソルバー拡張機能の主な要件には、SolverUpdate メソッドをオーバーライドすることが含まれます。 このメソッドでは、開発者は継承された GoalPositionGoalRotationGoalScale プロパティを目的の値に更新する必要があります。 また、一般に、コンシューマーが必要とする参照のフレームとして SolverHandler.TransformTarget を利用すると役立ちます。

以下に示すコードは、アタッチされたオブジェクトを SolverHandler.TransformTarget の 2m 前に配置する InFront という新しいソルバー コンポーネントの例を示しています。 コンシューマーによって SolverHandler.TrackedTargetTypeHead として設定されている場合、SolverHandler.TransformTarget はカメラの変換になります。したがって、このソルバーによって、接続されている GameObject が、ユーザーの視線入力のすべてのフレームの 2m 前に配置されます。

/// <summary>
/// InFront solver positions an object 2m in front of the tracked transform target
/// </summary>
public class InFront : Solver
{
    ...

    public override void SolverUpdate()
    {
        if (SolverHandler != null && SolverHandler.TransformTarget != null)
        {
            var target = SolverHandler.TransformTarget;
            GoalPosition = target.position + target.forward * 2.0f;
        }
    }
}

ソルバーの実装ガイド

ソルバーの共通のプロパティ

すべてのソルバー コンポーネントには、主要なソルバーの動作を制御する同一のプロパティのコア セットがあります。

[スムージング] が有効になっている場合、ソルバーでは、GameObject の変換を計算された値に時間の経過とともに段階的に更新します。 この変更の速度は、すべての変換コンポーネントの LerpTime プロパティによって決まります。 たとえば、MoveLerpTime 値を大きくすると、フレーム間の移動の増分が遅くなります。

MaintainScale が有効になっている場合、ソルバーでは GameObject の既定のローカル スケールが使用されます。

ソルバーの主要なプロパティ
すべてのソルバー コンポーネントによって継承される共通のプロパティ

Orbital

Orbital クラスは、太陽系の惑星のように動作するタグに沿ったコンポーネントです。 このソルバーでは、アタッチされた GameObject が追跡対象の変換の周りを回るようになります。 したがって、SolverHandler[追跡対象の種類]Head に設定されている場合、GameObject は固定されたオフセットが適用された状態でユーザーの頭の周りを回るようになります。

開発者は、この固定されたオフセットを変更して、メニューやその他のシーン コンポーネントをユーザーの周りの目の高さまたは腰の高さに維持することができます。 これを行うには、 [ローカル オフセット] および [ワールド オフセット] プロパティを変更します。 [方向の種類] プロパティでは、オブジェクトで元の回転を維持するか、常にカメラの方を向くか、位置に影響する変換の方を向くかなど、オブジェクトに適用される回転を決定します。

Orbital の例
Orbital の例

RadialView

RadialView は、ユーザーの視錐台内に GameObject の特定の部分を保持する、もう 1 つのタグに沿ったコンポーネントです。

[最小ビュー深度] および [最大ビュー深度] プロパティでは、常に表示する必要がある GameObject の部分の大きさを決定します。

[最小距離] および [最大距離] プロパティでは、GameObject とユーザーの間に維持する距離を決定します。 たとえば、 [最小距離] が 1m の GameObject に向かって歩くと、そのユーザーの 1m 以内に近づかないように GameObject が退きます。

一般に、RadialView は、Head に設定された [追跡対象の種類] と組み合わせて使用されます。これにより、コンポーネントはユーザーの視線入力に従います。 ただし、このコンポーネントは、すべての [追跡対象の種類] の "ビュー" で維持されるように機能できます。

RadialView の例
RadialView の例

フォロー

Follow クラスでは、ローカルの前方軸を基準として、追跡対象のターゲットの前に要素が配置されます。 要素を緩やかに制約して ( タグに沿うとも言います)、追跡対象のターゲットがユーザー定義の境界を越えて移動するまで、従わないようにすることができます。

これは、 [最大水平ビュー深度] および [最大垂直ビュー深度] を管理するための追加のコントロールと、オブジェクトの [方向] を変更するためのメカニズムを使用すると、RadialView ソルバーと同様に動作します。

Follow のプロパティ
Follow のプロパティ

Follow のシーンの例
Follow のシーンの例 (Assets/MRTK/Examples/Demos/Solvers/Scenes/FollowSolverExample.unity)

InBetween

InBetween クラスでは、アタッチされた GameObject が 2 つの変換の間に維持されます。 これら 2 つの変換エンドポイントは、GameObject の独自の SolverHandler[追跡対象の種類]InBetween コンポーネントの [2 番目の 追跡対象の種類] プロパティによって定義されます。 通常は、両方の種類が CustomOverride に設定され、その結果の SolverHandler.TransformOverride および InBetween.SecondTransformOverride 値が 2 つの追跡対象エンドポイントに設定されます。

実行時には、 [2 番目の追跡対象の種類] および [2 番目の変換のオーバーライド] プロパティに基づいて、InBetween コンポーネントによってもう 1 つの SolverHandler コンポーネントが作成されます。

PartwayOffset では、2 つの変換の間のラインに沿って、中間に 0.5、最初の変換に 1.0、2 番目の変換に 0.0 を使用して、オブジェクトを配置する場所を定義します。

InBetween の例
InBetween ソルバーを使用して 2 つの変換の間にオブジェクトを保持する例

SurfaceMagnetism

SurfaceMagnetism は、一連のサーフェスの LayerMask に対してレイキャストを実行し、その接触ポイントに GameObject を配置することで機能します。

[サーフェスの法線のオフセット] では、サーフェス上のヒットしたポイントでの法線の方向に、サーフェスからメートル単位で設定された距離に GameObject が配置されます。

反対に、 [サーフェス レイのオフセット] では、実行されたレイキャストと逆の方向に、サーフェスからメートル単位で設定された距離に GameObject が配置されます。 したがって、レイキャストがユーザーの視線入力である場合、GameObject はサーフェス上のヒットしたポイントからカメラまでのラインに沿って近づきます。

[方向モード] では、サーフェス上の法線を基準にして適用される回転の種類が決定されます。

  • [None] - 回転は適用されません
  • [TrackedTarget] - レイキャストが実行される追跡対象の変換の方にオブジェクトが向きます
  • [SurfaceNormal] - サーフェス上のヒットしたポイントの法線に基づいてオブジェクトが調整されます
  • [Blended] - オブジェクトは、サーフェス上のヒットしたポイントの法線と、追跡対象の変換の方向に基づいて調整されます。

関連付けられている GameObject を [None] 以外のモードで垂直に保つには、 [方向を垂直に維持する] を有効にします。

注意

[方向のブレンド] プロパティを使用すると、 [方向モード][Blended] に設定されている場合の回転の要因のバランスを制御できます。 値 0.0 の場合は [TrackedTarget] モードによって方向が完全に決定され、値 1.0 の場合は [SurfaceNormal] によって方向が完全に決定されます。

SurfaceMagnetism の例

ヒットできるサーフェスを判別する

SurfaceMagnetism コンポーネントを GameObject に追加する場合は、GameObject とその子のレイヤーを考慮することが重要です (コライダーがある場合)。 このコンポーネントでは、さまざまな種類のレイキャストを実行して、それ自体に「磁性」を持たせるサーフェスを判別することによって機能します。 ソルバーの GameObject で SurfaceMagnetismMagneticSurfaces プロパティにリストされているいずれかのレイヤーにコライダーがある場合、レイキャストはそれ自体にヒットし、その結果、GameObject が独自のコライダー ポイントにアタッチされます。 この奇妙な動作を回避するには、メインの GameObject とすべての子を "レイキャストを無視" レイヤーに設定するか、MagneticSurfaces の LayerMask 配列を適切に変更します。

逆に、SurfaceMagnetism の GameObject は MagneticSurfaces プロパティにリストされていないレイヤー上のサーフェスとヒットしません。 通常は、必要なすべてのサーフェスを専用のレイヤー (つまり、 サーフェス) に配置し、MagneticSurfaces プロパティをこのレイヤーのみに設定することをお勧めします。 [既定] または [すべて] を使用すると、UI コンポーネントまたはカーソルがソルバーに寄与する可能性があります。

最後に、MaxRaycastDistance プロパティ設定よりも遠いサーフェスは、SurfaceMagnetism のレイキャストによって無視されます。

DirectionalIndicator

DirectionalIndicator クラスは、スペース内の目的のポイントの方向にそれ自体を向ける、タグに沿ったコンポーネントです。

SolverHandler[追跡対象の種類]Head に設定されている場合に最もよく使用されます。 このように、DirectionalIndicator ソルバーを使用する UX コンポーネントでは、スペース内の目的のポイントを見るようにユーザーを導きます。

スペースの目的のポイントは、 [方向のターゲット] プロパティを使用して決定されます。

ユーザーがその方向のターゲットを見ることができる場合、または SolverHandler に何らかの参照のフレームが設定されている場合、このソルバーによってその下にあるすべての Renderer コンポーネントが無効にされます。 見ることができない場合は、インジケーターですべてが有効になります。

インジケーターのサイズは、ユーザーが FOV で [方向のターゲット] のキャプチャに近づくほど縮小します。

  • [最小インジケーター スケール] - インジケーター オブジェクトの最小スケール

  • [最大インジケーター スケール] - インジケーター オブジェクトの最大スケール

  • [可視性スケール ファクター] - [方向のターゲット] ポイントを表示できるかどうかを決定する FOV を増減するための乗数

  • [オフセットの表示] - 参照のフレームの視点から (つまり、 カメラなど)、このプロパティでは、オブジェクトを配置する、ビューポートの中心からインジケーター方向への距離を定義します。

方向インジケーターのプロパティ
方向インジケーターのプロパティ

方向インジケーターのシーンの例
方向インジケーターのシーンの例 (Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)

HandConstraint と HandConstraintPalmUp を含むハンド メニュー

ハンド メニュー UX の例

HandConstraint の動作では、手に制約されるコンテンツ (ハンド UI、メニューなど) で追跡対象のオブジェクトを安全な領域に制約するソルバーが提供されます。 安全な領域は、手と交差しない領域と見なされます。 手のひらがユーザーの方を向いているときに、ソルバーの追跡対象のオブジェクトをアクティブ化する一般的な動作を示すために、HandConstraintPalmUp と呼ばれる HandConstraint の派生クラスも含まれています。

ハンド制約ソルバーを使用してハンド メニューを作成する例については、「ハンド メニュー」のページを参照してください

関連項目