新しいLive2D公式コミュニティ(日本向け)が公開されました!
ぜひご利用ください!
Live2D公式コミュニティ

■このコミュニティの今後について
このコミュニティ(forum.live2d.com)につきましては、しばらくの間新コミュニティと並行して運営しますが、2022年内を目処に閉鎖する予定です。
閉鎖時期や内容については決定次第お知らせいたします。
海外向けコミュニティについては変更ございません。
Live2Dに関するユーザーのみなさま同士の交流・ご質問・不具合の報告・提案・要望などについて是非お寄せください。
※Live2D公式スタッフからの発言や回答については確約できないことを予めご了承ください。

Live2D ヘルプ

Cubism Editorダウンロード / 動作環境
Cubism SDKダウンロード / 対応表
Cubism 製品利用ライセンス(SDK含)

Cubism 製品のライセンスについてのお問い合わせはこちら
nizima 及び nizima 製品についてのお問い合わせはこちら
【各最新OSの対応状況について】
Cubism Editorは 4.1.02 正式版以降でWindows 11 及び macOS Monterey に対応しております。ぜひ最新版をご利用ください。
※macOSをお使いの方でOSアップデートする際は必ずCubism Editorのライセンスを解除してください。
Cubism EditorをインストールしているmacOSをアップグレードしたい
Cubism SDKについては各SDKのREADMEまたはNOTICEをご確認ください。

【Mac各機種への対応状況について】
現在、Cubism EditorはApple M1チップ搭載機種には対応しておりません。
詳細は 動作環境 をご参照ください。
関連するお問い合わせへの対応はこの文章をもって代えさせていただきます。
Cubism 製品のマニュアル・チュートリアルはこちら
 
Cubism Editorマニュアル    Cubism Editorチュートリアル    Cubism SDKマニュアル    Cubism SDKチュートリアル

質問:横髪に物理演算を適用する方法(Unity)

編集済: 1月 2015 一般
初めまして、現在Live2Dを用いてアプリを制作してるKYという者です。
質問したい内容はタイトルにも書いている通り、Unity(C#)のコードでLive2Dモデルの指定したテクスチャーに物理演算を適用する方法についてです。
具体的にはLive2D Viewerを用いて「プロジェクト-サンプル-物理演算:髪揺れ」を実行した時と同じような機能をUnity上のLive2Dモデルに実装したいと考えています。
自前のLive2Dモデルの横髪のモデルパラメータはデフォルトの「髪揺れ 横」に設定しています。
以下のリファレンスの内容を読んだのですが、分からない点がいくつかあるので以下に列挙します。
http://doc.live2d.com/api/core/cpp1.0j/a00041.html
・列挙型の SRC_TO_X, SRC_TO_Y, SRC_TO_G_ANGLE ,TARGET_FROM_ANGLE , TARGET_FROM_ANGLE_V が何を意味しているのか
・addSrcParam()とaddTargetParam()の違い
・PhysicsHair.updateの第2引数time に何を指定すればいいのか
・Unityのコード場でどのようにPhysicsHairを使えばいいのか。(サンプルコード付きで解説してくれると非常に助かります!)
・そもそもPhysicsHairでLive2D Viewerの髪揺れ機能が実装出来るか分からない・・・

Live2Dのリファレンスはサンプルコードが無いものが多くどのようにコーディングしたらいいのか分からないものが多々あるのでサンプルコード付きで解説してくれると非常に助かります。

自分の環境
MacOSX ver10.9.5
Unity ver4.6.1f1
Live2D SDK Live2D_SDK_Unity_2.0.02_1_jp

コメント

  • 追記
    制作したゲームは以下のものです。
    http://unitygameuploader.jpn.org/game/3542.html

    ここに登場するキャラクターの横髪を物理演算で制御したいと思っています。
    naotaro
  • 編集済: 2月 2015
    回答が遅れてすみません。


    >・列挙型の SRC_TO_X, SRC_TO_Y, SRC_TO_G_ANGLE ,TARGET_FROM_ANGLE , TARGET_FROM_ANGLE_V が何を意味しているのか
    これは二つ目の質問のaddSrcParam()とaddTargetParam()の設定に使用するものです。
    詳細は各関数の項目で説明します。

    >・addSrcParam()とaddTargetParam()の違い
    addSrcParam()とaddTargetParam()の違いですが、簡単にいえば
    addSrcParam()が入力の設定、addTargetParam()が出力の設定、というかんじです。

    addSrcParam()では、どのパラメーターが動いた時に計算するのかを設定します。
    第2引数に指定したパラメータの値がどのような動きなのかは第1引数で設定します。
    (パラメーターだけでは数値の増減しかわからず、それがどのような動きを制御しているかがわからないため)

    第1引数には、PhysicsHair.Srcの値を入れます。各値の詳細は以下の通りです。
    PhysicsHair.Src.SRC_TO_X :
    顔や体の向きを横に変える、横回転の動き
    設定された部位には、振り向いた時に翻るスカートのような動きとして計算されます

    PhysicsHair.Src.SRC_TO_Y :
    顔の向きを縦に変えたり、上下に移動する縦の動き
    設定された部位には、飛び跳ねた時の胸の揺れのような動きとして計算されます。

    PhysicsHair.Src.SRC_TO_G_ANGLE :
    顔を横に傾ける動き
    設定された部位には、傾けた時に重力で垂れる髪のような動きとして計算されます。


    また、addSrcParam()関数では「どの部分に対して物理演算を適用するか」は設定しません。
    addSrcParam()の設定をどの部分に反映させるかは、addTargetParam()関数で設定します。
    addTargetParam()の第2引数に渡すパラメータIDの値に、物理演算の値を適用します。

    第1引数には、PhysicsHair.Targetの値を入れます。
    PhysicsHair.Target.TARGET_FROM_ANGLE :
    入力されたパラメータの変化を傾きとして計算します。
    重力に引かれて垂れるようなものの場合はこれを渡します。

    PhysicsHair.Target.TARGET_FROM_ANGLE_V :
    入力されたパラメータの値が変化する加速度から計算します。
    頭を動かした勢いで髪の毛が揺れるような動きの場合はこちらを渡します。


    >・PhysicsHair.updateの第2引数time に何を指定すればいいのか
    ここにはプロジェクト実行時からの経過時間(ミリ秒)を渡します。
    Unityで言えば、Start()で開始時刻を記録して、Update()やOnRenderObject()で
    現在時刻から開始時刻を引いた値を第2引数に渡します。


    >・そもそもPhysicsHairでLive2D Viewerの髪揺れ機能が実装出来るか分からない・・・
    Viewerで表示されるものはそのまま他プラットフォームでも再現できます。
    Viewerは各プラットフォームでも同じように表示される環境で作られており、また、Viewerも物理演算にPhysicsHairクラスを利用しています。


    (続
  • 承前)

    実際には以下の様な使い方になります。
    PhysicsHairクラスのインスタンスは、動きの元のパラメータや適用する部位、揺れ方毎に用意しておきます。
    ここでは直接インスタンスを作ってますが、部位が増えればその分インスタンスが増えてしまうため、配列で管理して設定などはループで行うのがいいかと思われます。
    // 開始時間
    long startTimeMSec;

    // 物理演算クラスのインスタンス
    PhysicsHair physicsHairFront_X; // 前髪の揺れ
    PhysicsHair physicsHairFront_Z; // 前髪の傾き
    PhysicsHair physicsHairBack_X; // 後髪の揺れ
    PhysicsHair physicsHairBack_Z; // 後髪の傾き

    void Start ()
    {
    // Live2Dの初期化


    // 初期化
    physicsHairFront_X = new PhysicsHair();
    physicsHairFront_Z = new PhysicsHair();
    physicsHairBack_X = new PhysicsHair();
    physicsHairBack_Z = new PhysicsHair();



    // 物理演算する物体の設定
    physicsHairFront_X.setup (0.17f, 0.5f, 0.1f);
    physicsHairFront_Z.setup (0.17f, 0.5f, 0.1f);
    physicsHairBack_X.setup (0.34f, 0.5f, 0.2f);
    physicsHairBack_Z.setup (0.34f, 0.5f, 0.2f);



    // 入力の設定
    PhysicsHair.Src srcX = PhysicsHair.Src.SRC_TO_X;
    PhysicsHair.Src srcZ = PhysicsHair.Src.SRC_TO_G_ANGLE;

    physicsHairFront_X.addSrcParam (srcX, "PARAM_ANGLE_X", 0.005f, 1);
    physicsHairFront_Z.addSrcParam (srcZ, "PARAM_ANGLE_Z", 0.8f, 1);
    physicsHairBack_X.addSrcParam (srcX, "PARAM_ANGLE_X", 0.005f, 1);
    physicsHairBack_Z.addSrcParam (srcZ, "PARAM_ANGLE_Z", 0.005f, 1);



    // 出力の設定
    PhysicsHair.Target targetV = PhysicsHair.Target.TARGET_FROM_ANGLE_V;
    PhysicsHair.Target targetA = PhysicsHair.Target.TARGET_FROM_ANGLE;

    physicsHairFront_X.addTargetParam (targetV, "PARAM_HAIR_FRONT", 0.025f, 1);
    physicsHairFront_Z.addTargetParam (targetA, "PARAM_HAIR_FRONT", 0.025f, 1);
    physicsHairBack_X.addTargetParam (targetV, "PARAM_HAIR_BACK", 0.025f, 1);
    physicsHairBack_Z.addTargetParam (targetA, "PARAM_HAIR_BACK", 0.025f, 1);


    // 開始時間
    startTimeMSec = UtSystem.getTimeMSec();
    }


    void OnRenderObject()
    {
    // === マトリックス計算 ===
    // === パラメータの更新 ===


    // 経過時間
    long time = UtSystem.getTimeMSec() - startTimeMSec;

    // 物理演算をモデルに適用
    physicsHairFront_X.update(live2DModel, time);
    physicsHairFront_Z.update(live2DModel, time);
    physicsHairBack_X.update(live2DModel, time);
    physicsHairBack_Z.update(live2DModel, time);

    live2DModel.update();
    live2DModel.draw();
    }

    この内容は、あとでマニュアルに加筆したものを追加しておきます。
    また何かわからないことがありましたらお気軽にどうぞ。
  • 編集済: 2月 2015
    y_a_s様
    丁寧かつ大変分かりやすい解答ありがとうございます。
    無事Live2Dモデルに物理演算処理を適用することが出来ました。
    しかし、現在次のような別の問題に悩まされています。
    ・複数のPhysicsHairインスタンスを使用してそれぞれをアップデートすると、最後にアップデートしたインスタンスの物理演算パラメータしか適用されない。

    以下に使用しているコードを記載します。

    // 開始時間
    private long start_timesec;

    // 物理演算クラスのインスタンス
    private PhysicsHair physicshairX;//横髪の揺れ1(顔の向き(x軸)に影響)
    private PhysicsHair physicshairZ;//横髪の揺れ2(首の角度に影響)

    void Start ()
    {
    // Live2Dの初期化


    //初期化
    physicshairX = new PhysicsHair();
    physicshairZ = new PhysicsHair();
    physicshairX.setup (0.35f, 0.6f, 0.22f);
    physicshairZ.setup (0.35f, 0.6f, 0.22f);

    //入力
    PhysicsHair.Src srcX = PhysicsHair.Src.SRC_TO_X;
    PhysicsHair.Src srcZ = PhysicsHair.Src.SRC_TO_G_ANGLE;
    //ドラッグ処理で顔の向き(X軸)を変えた時の物理演算処理
    physicshairX.addSrcParam (srcX, "PARAM_ANGLE_X", 0.005f, 1f);
    //首を傾けた時の物理演算処理
    physicshairZ.addSrcParam (srcZ, "PARAM_ANGLE_Z", 0.8f, 1);

    //出力
    PhysicsHair.Target targetA = PhysicsHair.Target.TARGET_FROM_ANGLE;
    physicshairX.addTargetParam (targetA, "PARAM_HAIR_SIDE", 0.022f, 1);
    physicshairZ.addTargetParam (targetA, "PARAM_HAIR_SIDE", 0.022f, 1);

    start_timesec = UtSystem.getTimeMSec ();
    }


    void OnRenderObject()
    {
    // === マトリックス計算 ===
    // === パラメータの更新 ===


    // 経過時間
    long time = UtSystem.getTimeMSec() - start_timesec;

    // 物理演算をモデルに適用 *問題が起きている部分
    physicshairX.update (live2DModel,time);//横髪に物理演算を適用
    physicshairZ.update (live2DModel,time);//横髪に物理演算を適用

    live2DModel.update();
    live2DModel.draw();
    }


    問題が起きているのは物理演算をモデルに適用する部分で、上記コードの場合physicshairZ.update()はモデルに正常に適用されるのに対し、physicshairX.update()はモデルに適用されません。
    physicshairX.update()とphysicshairZ.update()を反対に書くと、physicshairXによる物理演算はモデルに正常に適用されるのに対し、physicshairZの物理演算はモデルに適用されません。

    もしこちらの問題も何か解決につながる方法をご存知でしたらご教授の程宜しくお願い致します。
  • 回答が遅れてすみません。
    上の例ですが、大きな勘違いをしてました。

    設定毎にインスタンスを用意していましたが、実際は出力毎(この例で言えば前髪に一つ、後髪に一つ)でした。

    正確には、以下の様な使い方になります。
    // 開始時間
    long startTimeMSec;

    // 物理演算クラスのインスタンス
    PhysicsHair physicsHairFront; // 前髪
    PhysicsHair physicsHairBack; // 後髪

    void Start ()
    {
    // Live2Dの初期化


    // 初期化
    physicsHairFront = new PhysicsHair();
    physicsHairBack = new PhysicsHair();



    // 物理演算する物体の設定
    physicsHairFront.setup (0.17f, 0.5f, 0.1f);
    physicsHairBack.setup (0.34f, 0.5f, 0.2f);



    // 入力の設定
    PhysicsHair.Src srcX = PhysicsHair.Src.SRC_TO_X;
    PhysicsHair.Src srcZ = PhysicsHair.Src.SRC_TO_G_ANGLE;

    // 入力の分だけ設定
    physicsHairFront.addSrcParam (srcX, "PARAM_ANGLE_X", 0.005f, 1);
    physicsHairFront.addSrcParam (srcZ, "PARAM_ANGLE_Z", 0.8f, 1);
    physicsHairBack.addSrcParam (srcX, "PARAM_ANGLE_X", 0.005f, 1);
    physicsHairBack.addSrcParam (srcZ, "PARAM_ANGLE_Z", 0.005f, 1);



    // 出力の設定
    PhysicsHair.Target targetA = PhysicsHair.Target.TARGET_FROM_ANGLE;

    physicsHairFront.addTargetParam (targetA, "PARAM_HAIR_FRONT", 0.025f, 1);
    physicsHairBack.addTargetParam (targetA, "PARAM_HAIR_BACK", 0.025f, 1);


    // 開始時間
    startTimeMSec = UtSystem.getTimeMSec();
    }


    void OnRenderObject()
    {
    // === マトリックス計算 ===
    // === パラメータの更新 ===


    // 経過時間
    long time = UtSystem.getTimeMSec() - startTimeMSec;

    // 物理演算をモデルに適用
    physicsHairFront.update(live2DModel, time);
    physicsHairBack.update(live2DModel, time);

    live2DModel.update();
    live2DModel.draw();
    }

コメントするにはサインインまたは登録して下さい。