Live2Dモデルで表情差分をボタン(スクリプト制御)などの操作で実装する方法について

148 views
Skip to first unread message

To M

unread,
Mar 11, 2024, 11:00:49 PMMar 11
to 宴ユーザーグループ
UTAGE4.0.5
Unity 2022.3.16f1
Windows

Unity
CibismSDK
それぞれ3か月ほど使用

▶問題点

https://groups.google.com/g/utageuser/c/xBefRuJ5oCk/m/r_ybyH1xAQAJ
『Lve2Dをボタンで動かす』

こちらの記事を参考にパラメーター変化によって着替えをするプログララムを書いて、Live2Dのプレハブにコンポーネントとして追加した後、ボタンで関数を呼び出す処理も行いましたが動作が正常に行われませんでした。

Live2Dプレハブからパラメーターのインデックスを読み取りボタンを押したらパラメータ値を1に変更するプログラムですが、実際にボタンを押しても差分に切り替わりません。

デバッグでは関数の呼び出しは正常に行われいるようなのですが、Cubism Parameters Inspectorコンポーネントの更新が行われません。
ただ、不思議なことにLive2Dアセット内のプレハブはパラメータ値の更新が行われますがヒエラルキーに表示されるクローンのプレハブのパラメータ値は更新されていません。

使用したプログラムは以下になります。
ーーーーーーーーーー
using UnityEngine;
using Live2D.Cubism.Core;
using Live2D.Cubism.Framework;
using System;
using System.Data.Common;
using Utage;
using UtageExtensions;

public class ParameterLateUpdate : MonoBehaviour
{
    private CubismModel _model;
    private CubismParameter __parameter;
    [SerializeField]
    private int parameterIndex = 15; // パラメーターのインデックス
    private int moge = 0;


    private CubismParameter _parameter
    {
        get { return __parameter; }
        set { __parameter = value; }
    }

    public void Start()
    {
        moge = 2;

        _model = this.FindCubismModel();
        if (_model != null && _model.Parameters.Length > parameterIndex)
        {
            _parameter = _model.Parameters[parameterIndex];
        }
    }

    // ボタンを押したときに呼び出されるメソッド
    public void SetParameterValueToOne()
    {
        EnsureParameter();
        moge = 3;
        if (_parameter != null)
        {
            _parameter.Value = 1f;
        }
    }

    private void EnsureParameter()
    {
        if (_parameter == null)
        {
            moge = 4;
            _model = this.FindCubismModel();
            if (_model != null && _model.Parameters.Length > parameterIndex)
            {
                _parameter = _model.Parameters[parameterIndex];
            }
        }
    }
}
ーーーーーーーーーー


▶実現したいこと
パラメーター変化によって着替えをするプログララムを書いて、ボタンクリックによってLive2Dのヒエラルキーにあるプレハブ(clone)のパラメータ値を変更したい。

可能でしたら、方法を教えていただけますと幸いです。


マッドネスラボ

unread,
Mar 12, 2024, 9:11:10 AMMar 12
to 宴ユーザーグループ
>ただ、不思議なことにLive2Dアセット内のプレハブはパラメータ値の更新が行われますがヒエラルキーに表示されるクローンのプレハブのパラメータ値は更新されていません。
であれば、呼び出し側のプログラムが間違っているのだと思います。
アセット内のプレハブを対象にプログラムを呼び出さず、
シーン内のプレハブインスタンス(ヒエラルキーにあるプレハブ(clone))に対して行うようにしてください。




2024年3月12日火曜日 12:00:49 UTC+9 hyk...@gmail.com:

To M

unread,
Mar 12, 2024, 10:41:50 AMMar 12
to 宴ユーザーグループ
早速のご返信ありがとうございます。
ご指摘の通り、呼び出し側のプログラムが間違っておりアセット内のプレハブに設定しておりました。
再度調整してみます。
2024年3月12日火曜日 22:11:10 UTC+9 マッドネスラボ:

To M

unread,
Mar 12, 2024, 12:03:56 PMMar 12
to 宴ユーザーグループ
現在、調整を行っているのですが
シーン内のプレハブインスタンス(ヒエラルキーにあるプレハブ(clone))に対してボタンからOnClickで呼び出しを行う場合、最初は空になっているのですがゲーム開始後にスクリプトでプレハブ(clone)を割り当てる方法はありますでしょうか。
2024年3月12日火曜日 23:41:50 UTC+9 To M:

マッドネスラボ

unread,
Mar 12, 2024, 2:29:32 PMMar 12
to 宴ユーザーグループ
できはなくはないですが、あまり意味がないと思います。

>『Lve2Dをボタンで動かす』
こちらの質問は、非公開でやりとりが続いていたのですが、
そのときに作成したサンプルプログラムを下記に記述します。




using UnityEngine;
using Utage;
using UtageExtensions;

//宴とゲーム処理を繋げてコントロールするためのサンプル
public class SampleController : MonoBehaviour
{
//ADVエンジン
public AdvEngine Engine
{
get { return this.GetComponentCacheFindIfMissing(ref engine); }
}
[SerializeField] protected AdvEngine engine;

//指定の名前のAdvGraphicObjectを探す
public AdvGraphicObject FindObject(string objectLabel)
{
return Engine.GraphicManager.transform.FindDeepAsComponent<AdvGraphicObject>(objectLabel,true);
}

//指定の名前のAdvGraphicObjectを探し、描画オブジェクト(プレハブならプレハブインスタンス)のコンポーネントを取得
public T FindAdvGraphicTargetComponent<T>(string objectLabel)
where T : class
{
AdvGraphicObject obj = FindObject(objectLabel);
if (obj == null)
{
//見つからない
return null;
}

//AdvGraphicObject以下に描画オブジェクトがない可能性があるので
//obj.TargetObjectで取得
var target = obj.TargetObject;
return target.GetComponentInChildren<T>();
}


//クリック処理のサンプル
public void SampleOnClick()
{
//ログを出力(不要なら消すこと)
Debug.Log($"SampleOnClick");
//指定の名前のキャラクター名のオブジェクト探し、
//そのコンポーネントを取得
string label = "うたこ";

var component = FindAdvGraphicTargetComponent<SamplePrefabComponent>(label);
if (component == null)
{
//見つからない
Debug.LogError($"{label} is not found");
return;
}

//ボタンクリック処理を呼び出す
component.OnClick();
}

//AdvEngine以下に一つしかSamplePrefabComponentを持つオブジェクトがないとわかっている場合に、
//そのコンポーネントを取得して呼び出す処理
void SampleSingleComponent()
{
var singleComponent = Engine.GetComponentInChildren<SamplePrefabComponent>();
singleComponent.OnClick();
}

//AdvEngine以下の全SamplePrefabComponentに処理をするなら
void SampleAllComponents()
{
foreach (var component in Engine.GetComponentsInChildren<SamplePrefabComponent>(true))
{
component.OnClick();
}
}
}




Unityの基本的なプログラムのやり方として、
プレハブから作成したオブジェクトなど、シーン内で参照を持っていない他のオブジェクトにあるコンポーネントを探してくる場合
特定の仕組みに関わりなく、汎用的に行うのであれば、
Find系のメソッドや、GetComponentInChildren系のメソッドを使用します。

指定のオブジェクト以下にある、指定の型のコンポーネントを取得するなら、GetComponentInChildrenを使います。
指定のオブジェクト以下にある、指定の型のコンポーネントをすべて取得するなら、GetComponentsInChildrenを使います。
名前で区別する場合、GetComponentsInChildrenで取得したのちに名前で一致するものを検索するだけです。

宴の場合でもそれは同じで、大抵はそれで事足りると思うのですが、
一応宴の仕組みに依存した書き方として、「GraphicManager以下にある指定の名前ラベルのオブジェクトの、プレハブインスタンスのコンポーネント」を取得する場合は、
上記のサンプルプログラムの「FindAdvGraphicTargetComponent」を使います。

呼び出すキャラクターラベルなどは任意にアレンジしてください。
また、SamplePrefabComponentは、適当につけているサンプル名なので、プレハブに追加した自作コンポーネント(質問の例ですと、CubismParameter など)の型に置き換えてください。



2024年3月13日水曜日 1:03:56 UTC+9 hyk...@gmail.com:

マッドネスラボ

unread,
Mar 12, 2024, 2:38:54 PMMar 12
to 宴ユーザーグループ
上記のサンプルは
> 最初は空になっているのですがゲーム開始後にスクリプトでプレハブ(clone)を割り当てる
コンポーネントから見える形で割り当てをあえて行わず、プログラムで探してきたオブジェクトやコンポーネントをそのまま使ってしまう形になっています。

一応、探してきたオブジェクトを代入すれば(割り当てをすれば)インスペクター等からオブジェクトを確認できるのでデバッグ等で便利という面もあるのですが、
不必要にオブジェクトへの参照を残してしまうと、メモリリークのリスクというまた別のリスクがでてくるのでケースバイケースかと思います。(これはまた別のちょっと複雑な話です)

2024年3月13日水曜日 3:29:32 UTC+9 マッドネスラボ:

To M

unread,
Mar 13, 2024, 8:50:45 AMMar 13
to 宴ユーザーグループ

ありがとうございます。無事解決しました。
2024年3月13日水曜日 3:38:54 UTC+9 マッドネスラボ:
Reply all
Reply to author
Forward
0 new messages