2024年4月30日火曜日

UnityでつけたポーズをBlenderに取り込む方法(もっと簡単な方法あるかも)

Unityのエディタでシーンビュー内でつけたポーズをBlenderにもっていく方法
1. Unity側のスクリプトをポーズを付けたFBXにアタッチしてレストポーズにしたFBXを
referenceModelとして設定する。
ポーズを付けたFBXのrootBoneと出力先のパスを設定する。
2. インスペクター上で右クリックでExportBoneData
3. Blender側のスクリプトでアーマチュアの名前と読み込むポーズのファイルのパスを設定して RunScript


↓Unity側

using System.Collections.Generic;

using UnityEngine;

using System.IO;


[System.Serializable]

public class BoneData

{

    public string name;

    public Vector3 position;

    public Vector3 scale;

    public Quaternion rotation; // This will be Q_relative

}


[System.Serializable]

public class BoneDataList

{

    public List<BoneData> bones = new List<BoneData>();

}


public class BoneDataExporter : MonoBehaviour

{

    public Transform rootBone;

    public GameObject referenceModel; // Add a field for the reference model

    public string boneDataPath = "Assets/boneData.json";



    [ContextMenu("Export Bone Data")]

    void ExportBoneData()

    {

        BoneDataList boneDataList = new BoneDataList();

        CollectBoneData(rootBone, boneDataList.bones, referenceModel.transform);

        string json = JsonUtility.ToJson(boneDataList, true);

        File.WriteAllText(boneDataPath, json);

        Debug.Log("Bone data exported!");

    }


    void CollectBoneData(Transform bone, List<BoneData> boneData, Transform reference)

    {


        // Find the same bone in the reference model by name

        Transform referenceBone = reference.FindChildRecursive(bone.name);

        Quaternion Q0 = referenceBone != null ? referenceBone.localRotation : Quaternion.identity;

        Quaternion Q = bone.localRotation;

        Quaternion Q0_inv= Quaternion.Inverse(Q0);

        Quaternion Q_relative =Q0_inv*Q;

        Quaternion Q_final = new Quaternion(Q_relative.x, -Q_relative.y, -Q_relative.z, Q_relative.w);


        boneData.Add(new BoneData

        {

            name = bone.name,

            position = bone.localPosition,

            scale = bone.localScale,

            rotation = Q_final // Store the relative rotation

        });


        foreach (Transform child in bone)

        {

            CollectBoneData(child, boneData, reference);

        }

    }

}


↓Blender側

import bpy

import json


def apply_pose(armature_name, json_path):

    with open(json_path, 'r') as f:

        data = json.load(f)


    armature = bpy.data.objects[armature_name]

    bpy.context.view_layer.objects.active = armature

    bpy.ops.object.mode_set(mode='POSE')


    for bone_data in data['bones']:

        bone = armature.pose.bones.get(bone_data['name'])

        if bone:

            bone.location = (bone_data['position']['x'], bone_data['position']['y'], bone_data['position']['z'])

            bone.scale = (bone_data['scale']['x'], bone_data['scale']['y'], bone_data['scale']['z'])

            # 注意:四元数は (w, x, y, z) の順で設定

            bone.rotation_quaternion = (bone_data['rotation']['w'], bone_data['rotation']['x'], bone_data['rotation']['y'], bone_data['rotation']['z'])


    # Save the pose

    bpy.ops.object.posemode_toggle()

    bpy.ops.wm.save_mainfile()


# ファイルパスは適宜設定してください


apply_pose('RobinArmature', 'C:boneData.json')

    





0 件のコメント:

コメントを投稿