AIプログラムとかUnityゲーム開発について

探索や学習などを活用したAI系ゲームを作りたいと思います。

簡単にSpringBoneを仕込めるスクリプト

PMCAで作ったモブ子さんに簡単にSpringBoneを仕込んで揺らせるようになりました。

f:id:yasu9780:20161125113035g:plain

 debug=trueだとスプリングボーンのコライダーが黄色で見えます。
 緑色はスプリングコライダーです。

  • 初めにColliderを登録
  • 髪の毛やスカートなどは、それぞれのルートの親ボーンを登録
  • 初めに登録したSpringコライダーはすべてSpringBoneに自動登録される
  • SpringManagerにはSpringBoneが自動登録される

スプリングコライダーの登録方法

例:setupSpringCollider("3.joint_Head", "HeadCollider", Vector3.up * 0.12f, 0.1f);

 引数
  該当ボーンの名称
  このボーンの子供として登録されるコライダー自体の名前
  コライダーのボーンからの相対位置
  コライダー球の半径

スプリングボーンの登録方法

例: setupSpringBone("59.joint_FrontHair1", 0.03f, 0.02f, 0.02f);
 引数
  該当ボーンの名称
  スプリングボーンの半径
  stiffnessForce 小さい値ほどよく揺れる   
  dragForce 揺れの減衰力 小さい値ほどよく揺れる バネ定数K?

現状、SpringBoneを仕込むボーンの子供は一つのボーンを持つという構造が前提になります。


ルートにSpringManagerは自動登録されます。
f:id:yasu9780:20161125123248p:plain

初めてウェイトを塗り、初めてボーンを仕込んだ

 今回のキャラですがポニーテルがまずまともに動きませんでした。根本付近があらぶります。
 PMXで読み込んで動かしても再現したので調べるとウェイトの塗りが足りてないようでした。しっかり塗ったら治りました。
 次に、セーラー服の襟の後ろにウェイトがありませんでした。なので、襟がめくれると、下のカーティガンがくっついてきます。
 襟だけにウェイトを塗りました。

 PMCAにはもともと胸ボーンがありませんが、試しにつけてみました。ボーンを一つ入れただけなので多段ではありません。
 そもそもほとんど胸が無いようなmeshですので。
 ただ、制服の上からカーディガンを着ている構造なので、胸を揺らすと時々カーディガンを突き破って下の制服が見えます。
 それぞれにウェイトを塗るべきなのか、それとも下の服にはいらないのか?
 ウェイトを塗ったのも、ボーンを入れたのも初めてのガチ初心者なのでさっぱりわかりません(´・ω・`)
 でも、いろいろ初めてのことができたので良かったです( ゚Д゚)

 PMXで言うところの剛体=SpringCollider、バネ付きジョイント=SpringBoneですね。

それでも太ももがスカートを突き破る

 せっかく仕込んだけど、やっぱりスカートを太ももが突き破りますね。
 PMCAだからものすごくボーンが少ないってのもありますが(プロ生ちゃんと比較して)
 でも、激しい動きだとプロ生ちゃんの太もももスカートを突き破っています。
 よく見てみると、コライダーはちゃんと太ももを避けているんですよ。

 ・O・ みたいにスカートのボーンが太ももを挟む形に避けているので、結果としてスカートがめり込んでるんです。
 これは、スカートのボーンには縦の親子関係はあっても、横の兄弟関係が無いからです。
 あくまで尻尾みたいなものが対象で、横の兄弟関係も見るなら、それはClothコンポーネントのような仕組みになると思います。
 例えば、横のボーンとの距離も一定に保ちつつ、太ももと反発するように位置取りすれば、スカートがめり込まないようにできるし、それがClothシミュレーションだと思う。
 今のままだと、縦糸はあっても横糸が無い状態。



※追加
Instantiate((GameObject)Resources.Load("SpringCollider"), Vector3.zero, Quaternion.identity) as GameObject;
ここでロードしてるのはただのemptyです。resourcesフォルダに入れておいてください。
loadしないでも済むようにする予定

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class SpringSetup : MonoBehaviour {
    GameObject[] gm = new GameObject[80];
    PronamaChan.SpringBone[] sb = new PronamaChan.SpringBone[50];
    int sbIndex = 0;
    List<PronamaChan.SpringCollider> sc = new List<PronamaChan.SpringCollider>();
    Vector3 boneAxis = new Vector3(0, -1, 0);

    void Start()
    { 
        setupSpringCollider("3.joint_Head", "HeadCollider", Vector3.up * 0.12f, 0.1f);
        setupSpringCollider("1.joint_Torso", "BodyCollider", Vector3.up * 0.15f, 0.06f);
        //sc.Add( setupSpringCollider("7.joint_HipMaster", "BodyCollider2", -Vector3.up * 0.3f, 0.1f);
        //sc.Add( setupSpringCollider("35.joint_RightArmTwist", "ArmColliderR1", Vector3.up * 0.0f, 0.07f);
        //sc.Add( setupSpringCollider("10.joint_LeftArmTwist", "ArmColliderL1", Vector3.up * 0.0f, 0.07f);
        setupSpringCollider("30.joint_LeftHip", "LegColliderL1", -Vector3.up * 0.02f, 0.09f);
        setupSpringCollider("30.joint_LeftHip", "LegColliderL2", -0.001f*transform.forward+transform.right*0.03f - Vector3.up * 0.16f, 0.08f);
        setupSpringCollider("55.joint_RightHip", "LegColliderR1", - Vector3.up * 0.02f, 0.09f);
        setupSpringCollider("55.joint_RightHip", "LegColliderR2", -0.001f * transform.forward + -transform.right * 0.04f - Vector3.up * 0.16f, 0.08f);

        setupSpringBone("59.joint_FrontHair1", 0.03f, 0.02f, 0.02f);
        setupSpringBone("60.joint_FrontHair2", 0.03f, 0.02f, 0.02f);
        setupSpringBone("61.joint_FrontHair3", 0.03f, 0.02f, 0.02f);
        setupSpringBone("88.joint_BackHair1",  0.03f, 0.01f, 0.1f);
        setupSpringBone("6.joint_eri"         ,0.03f, 0.2f, 0.1f);

        setupSpringBone("28.joint_LeftSkirtFront" , 0.05f, 0.01f, 0.05f);
        setupSpringBone("29.joint_LeftSkirtBack"  , 0.05f, 0.01f, 0.05f);
        setupSpringBone("53.joint_RightSkirtFront", 0.05f, 0.01f, 0.05f);
        setupSpringBone("54.joint_RightSkirtBack" , 0.05f, 0.01f, 0.05f);

        setupSpringBone("111.joint_muneR1", 0.01f, 0.03f, 0.2f);
        setupSpringBone("112.joint_muneL1", 0.01f, 0.03f, 0.2f);
        setupSpringManager();
    }
    void setupSpringBone(string root, float radius, float stiffnessForce, float dragForce)
    {
        gm[sbIndex] = FindDeep(this.gameObject, root);
        if (gm[sbIndex] == null) return;

        for (;;)
        {
            sb[sbIndex] = gm[sbIndex].AddComponent<PronamaChan.SpringBone>() as PronamaChan.SpringBone;
            sb[sbIndex].boneAxis = boneAxis;
            sb[sbIndex].radius = radius;
            sb[sbIndex].stiffnessForce = stiffnessForce; //バネが戻る力
            sb[sbIndex].dragForce = dragForce;//揺れ減衰力
            sb[sbIndex].springForce = new Vector3(0.0f, -0.0001f, 0.0f);
            sb[sbIndex].child = gm[sbIndex].transform.GetChild(0).transform;
            sb[sbIndex].debug = true;

            sb[sbIndex].colliders = new PronamaChan.SpringCollider[sc.Count];
            for (int i = 0; i < sc.Count; i++) sb[sbIndex].colliders[i] = sc[i];

            sbIndex++;
            gm[sbIndex] = sb[sbIndex - 1].child.gameObject;
            if (gm[sbIndex].transform.childCount == 0) break;
        }
        return;
    }

    void setupSpringCollider(string bone,string colName,Vector3 pos,float radius)
    {
        Debug.Log(bone);
        GameObject manager = FindDeep(this.gameObject, bone);
        if (manager == null) return;
        GameObject col =Instantiate((GameObject)Resources.Load("SpringCollider"), Vector3.zero, Quaternion.identity) as GameObject;
        col.name = colName;
        col.transform.SetParent(manager.transform);
        col.transform.localPosition = Vector3.zero+pos;

        PronamaChan.SpringCollider sc0 = col.GetComponent<PronamaChan.SpringCollider>() as PronamaChan.SpringCollider;
        sc0.radius = radius;
        sc.Add(sc0);
    }
    void setupSpringManager()
    {
        PronamaChan.SpringManager sm = this.gameObject.AddComponent<PronamaChan.SpringManager>() as PronamaChan.SpringManager;

        sm.springBones = new PronamaChan.SpringBone[sbIndex];
        for (int i = 0; i < sbIndex; i++) sm.springBones[i] = sb[i];
    }

    GameObject FindDeep( GameObject self, string name )
    {
        Transform[] children = self.GetComponentsInChildren<Transform>();
        foreach (Transform t in children)
        {
            if (t.name == name)
                return t.gameObject;
        }
        return null;
    }
}