仮想と物理とエトセトラ

xRや物理とかごった煮の備忘録的技術ブログ

ConstraintManagerで自作の制約を加える

今回はMRTKの勉強です。 Object Manipulatorや、Bounds Controlを使用する際に一緒にアタッチされる、Constraint Managerの活用について確認します。

docs.microsoft.com

Constraint Managerについては、やや古いですが下記が詳しいです。

hololabinc.github.io

Constraint Managerをオブジェクトにアタッチすると、アタッチしているオブジェクトのTransformに制約を加えることができます。
あらかじめ用意されている制約は以下があります。

  • FaceUserConstraint:
    オブジェクトが常にユーザ方向(カメラ方向)を向くようになる制約。
  • FixedDistanceConstraint:
    カメラや任意の物体との距離を固定する制約。
  • FixedRotationToUserConstraint:
    操作中にカメラとの回転位置関係を固定する制約。
  • FixedRotationToWorldConstraint:
    操作中にワールド座標との回転位置関係を固定する制約。
  • MaintainApparentSizeConstraint:
    カメラからの見かけの大きさを固定する制約。
  • MoveAxisConstraint:
    移動可能な軸を固定する制約。
  • RotationAxisConstraint:
    回転可能な軸を固定する制約。
  • MinMaxScaleConstraint:
    拡縮の最大最小制限を付与する制約。

上記でも十分制約をつけることができますが、それでは不足することがあります。
例えば、1回の移動距離に制限を加えたり、精密操作のため操作量と移動量を不一致にさせたい場合があります。
その場合、それぞれの制約の継承元である、TransformConstraintを継承したスクリプトを作成することで自作の制約を使用することができます。

自作の制約を作る

自作の制約は、TransformConstraintを継承することで作成できます。
制約のベースとなるスクリプトは以下のスクリプトになります。

  • ConstraintBase.cs
クリックで展開
using Microsoft.MixedReality.Toolkit.UI;
using Microsoft.MixedReality.Toolkit.Utilities;
using UnityEngine;

/// <summary>
/// 自作制約作成のベース
/// </summary>
public class ConstraintBase : TransformConstraint
{
    /// <summary>
    /// 制約のタイプ
    /// Positionの制約の場合:TransformFlags.Move
    /// Rotationの制約の場合:TransformFlags.Rotate
    /// Scaleの制約の場合:TransformFlags.Scale
    /// </summary>
    public override TransformFlags ConstraintType => TransformFlags.Move;

    /// <summary>
    /// 制約の付与
    /// transformがその時点でのtransform値。
    /// transformの値を変更することで制約を行う。
    /// </summary>
    /// <param name="transform"></param>
    public override void ApplyConstraint(ref MixedRealityTransform transform)
    {
        // 制約を加えるための処理

        /*
        TransformConstraint.worldPoseOnManipulationStart :  操作開始時のTransform
        */
    }
}

worldPoseOnManipulationStart には操作開始時のTransformが格納されており、制約を加えるために使用できます。
上記をもとに、移動距離の制約を加えると次のようになります。

  • MoveDistanceConstraint.cs
クリックで展開
using Microsoft.MixedReality.Toolkit.UI;
using Microsoft.MixedReality.Toolkit.Utilities;
using UnityEngine;

/// <summary>
/// 移動距離の制約
/// </summary>
public class MoveDistanceConstraint : TransformConstraint
{
    /// <summary>
    /// 移動の制約
    /// </summary>
    public override TransformFlags ConstraintType => TransformFlags.Move;

    /// <summary>
    /// 移動距離の制限
    /// </summary>
    [SerializeField]
    private float limitedDistance = 1.0f;

    public override void ApplyConstraint(ref MixedRealityTransform transform)
    {
        // 操作開始時からの移動距離
        Vector3 moveDistance = transform.Position - worldPoseOnManipulationStart.Position;
        
        // 各軸での比較
        CompLimitation(ref moveDistance.x);
        CompLimitation(ref moveDistance.y);
        CompLimitation(ref moveDistance.z);

        // 制約付与した後の移動距離でtransformを書き換える
        transform.Position = worldPoseOnManipulationStart.Position + moveDistance;

    }

    /// <summary>
    /// 比較用関数
    /// </summary>
    /// <param name="distance"></param>
    private void CompLimitation(ref float distance)
    {
        if (Mathf.Abs(distance) > limitedDistance)
        {
            distance = Mathf.Sign(distance) * limitedDistance;
        }
    }

}

スクリプトを作成すると、自動でConstraintManagerで選択できるようになります。
ConstraintManagerのAdd Constraint to GameObjectから先ほど作成した制約が選択できます。
f:id:napo909:20210627181144p:plain

アタッチすると、継承元のTransformConstraintにより、HandType(どの手で操作したとき実行するか)とProxymity type(どの距離によって制約するか)を設定できます。
f:id:napo909:20210627182042p:plain

動作確認

ConstraintManagerでMoveDistanceConstraintを追加した後動作確認すると次のようになります。

f:id:napo909:20210627181647g:plain

一回の移動量にConstraintManagerを用いて制約を加えることができました。
TransformConstraintとConstraintManagerを使用することで、比較的簡単に移動や回転、拡縮に関する制約をつけることができます。