1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Animation Rigging】プレハブ内の各種ConstraintのSourceObjectsを実行中に変更する方法

Last updated at Posted at 2020-12-24

はじめに

Animation RiggingパッケージのTwoBoneIKConstraintMulti-AimConstraintなど各種Constraintを持つPrefabをインスタンスする際、SourceObject(Target等)にシーン内のオブジェクトを参照する方法を紹介します。

環境

  • Unity 2019.4.9f1
  • Animation Rigging preview-0.2.7

できない例

例えば以下のようなコードで、プレハブをインスタンスした後、Multi-AimConstraintsourceObjectsにターゲットをセットしようとします。

Spawn.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations.Rigging;

public class Spawn : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    [SerializeField] private Transform target;
    private GameObject spawndAvatar;

   private void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            // インスタンス
            spawndAvatar = Instantiate(prefab, transform.position, Quaternion.identity);

            // RigBuilderの3つ目に登録されているRigの子供を列挙
            foreach (Transform lookat in spawndAvatar.GetComponent<RigBuilder>().layers[2].rig.transform)
            {
                // sourceObjectsにターゲットを設定する
                var source = lookat.GetComponent<MultiAimConstraint>().data.sourceObjects;
                source.SetTransform(0, target);
                lookat.GetComponent<MultiAimConstraint>().data.sourceObjects = source;
            }
        }
    }
}

HeadRig以下の3つのオブジェクトについているMulti-AimConstraintについてSourceObjectを設定します。
RigBuilder
RigLayers>HeadRig
階層
HeadRig/HeadLookAt,NeckLookAt,HeadYawLookAt

この時、Inspector上では正しく設定されているように見えてもConstraintは効いてくれません。

2020-12-24 (2).png
MainCameraを設定しているのでカメラ目線になってくれるはず……

※単眼キャラクターです。苦手な方はご注意を
2020-12-24 (1).png
つーん
ちなみにこの子はオダマキちゃんといいます。単眼なのは私が好きだからです。

方法1 RigBuilderをビルドする

こちらで見つけた方法です。
https://forum.unity.com/threads/multi-aim-constraint-set-source-at-runtime.944559/

先ほどのコードに一行付け足すだけです。

Spawn.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations.Rigging;

public class Spawn : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    [SerializeField] private Transform target;
    private GameObject spawndAvatar;

   private void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            // インスタンス
            spawndAvatar = Instantiate(prefab, transform.position, Quaternion.identity);

            // RigBuilderの3つ目に登録されているRigの子供を列挙
            foreach (Transform lookat in spawndAvatar.GetComponent<RigBuilder>().layers[2].rig.transform)
            {
                // sourceObjectsにターゲットを設定する
                var source = lookat.GetComponent<MultiAimConstraint>().data.sourceObjects;
                source.SetTransform(0, target);
                lookat.GetComponent<MultiAimConstraint>().data.sourceObjects = source;
            }

            // 設定後にRigBuilderをビルドしなおす。
            spawndAvatar.GetComponent<RigBuilder>().Build();
        }
    }
}

2020-12-24 (5).png

怖い……

方法2 生成する前のprefabに代入する

いじってたら見つけた対症療法。インスタンスの際にされているであろうビルドの前にターゲットを設定する方法です。

後述しますがシーンごとに挙動が変わってしまう恐れがあるので複数シーンで使う場合はおすすめしません。単一シーンで使う場合はこの後のおまけの章で紹介する方法の方が簡単だと思います。

結論使わない方がいいです。

Spawn.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations.Rigging;

public class Spawn : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    [SerializeField] private Transform target;
    private GameObject spawndAvatar;

   private void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            // インスタンス前にprefabでセットしてしまう
            foreach (Transform lookat in spawndAvatar.GetComponent<RigBuilder>().layers[2].rig.transform)
            {
                var source = lookat.GetComponent<MultiAimConstraint>().data.sourceObjects;
                source.SetTransform(0, target);
                lookat.GetComponent<MultiAimConstraint>().data.sourceObjects = source;
            }

            // インスタンス
            spawndAvatar = Instantiate(prefab, transform.position, Quaternion.identity);
        }
    }
}

これを試した後、ターゲットをセットするforeachブロックを消してインスタンスを実行しても、なんとターゲットがセットされました

project内のprefabなのでもちろんシーン内への参照は持てませんし、prefabを開いて確認してもNoneになっています。怖い……

(prefabをシーンにドラッグアンドドロップをすると参照が生えるので内部的には保持している状態なのでしょうか。別のシーンに持っていくともちろんNoneのままです。)

おまけ そもそもプレハブをシーン中に置いておけば解決するのでは?

『projectのプレハブなのでシーン内のオブジェクト参照できない→実行中にスクリプトから入れなければならない』

でお困りの場合は、プレハブをシーン内に置いてしまえば解決する場合も多いと思います。

シーン内のオブジェクトでもprojectのプレハブと同様にインスタンスすることができます。「動いてしまうと困る」「StartやAwakeを実行してほしくない」場合は非アクティブなGameObjectの子にしてしまえばいいです。インスタンス時にアクティブにする必要もないですし。

2020-12-24 (6).png

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?