Help us understand the problem. What is going on with this article?

VCIで人型の関節を動かす

概要

VCIで人型オブジェクトの関節を操作できるようにします。
記事を書いてる途中に改めて思いましたが、結構面倒です。
D2CY_nmU4AAqiZz.jpg
© Unity Technologies Japan/UCL
まぁ、でも頑張ると一人でも画面映えしますよ。
結構ゴリ押しなので、バージョンアップでダメになるかもしれません。

前書き

2019/03/20現在、VCIはwikiに「※SubItemの下の階層にSubItemを配置する事はできません。」とあるとおり、Unityで言う所の子オブジェクトに対する参照ができません。これは、関節の操作をするにあたっては難しい制約です。ので、Fixed Jointを使って無理やり近い振る舞いをさせます。

Unityドキュメントより引用

Fixed Joints は、オブジェクトの動きを別のオブジェクトに依存するよう制限します。これは、親子関係 に若干似ていますが、トランスフォーム 階層ではなく、物理特性を通して実現されます。簡単に分解したいオブジェクトがある場合や、親子関係なしで 2 つのオブジェクトの動きをつなげたい場合などが、最適な使い道です。

仕組み

以下3つが要点です。
・関節ごとに分離してSubItem化
・関節の位置にFixed Jointで繋いだSubItemの作成
・関節操作用のSubItemの作成

関節ごとに分離してSubItem化

00.png
人型オブジェクトを根本から辿って、動かしたい関節の部分からVCIObjectの直下に配置してSubItem化します。RigidbodyのUse Gravityは無効にしておきましょう。え?これ動くの?と、私も思いましたが、動きます。UnityEditor上で確認できます。画像の例は「首腕肘足膝」計9関節です。

関節の位置にFixed Jointで繋いだSubItemの作成

01.png
各関節と同じ位置に別途SubItemを作成して、その親に該当するオブジェクトをFixed Jointで繋ぎます。RigidbodyのUse Gravityは無効にしておきましょう。位置はTransformの右上の歯車からCopy Componen→Paste Component Valuesで同じ位置を設定できます。画像の例は頭なので、親は人型オブジェクトの根本にしています。肘(Elb)なら腕(UpperArm)、膝(Kne)なら足(UpperLeg)にします。

関節操作用のSubItemの作成

02.png
各関節の操作用に別途SubItemを作成します。操作用なのでColliderを追加します。Colliderの形と大きさを調整して、IsTriggerを有効にします。SubItemはGrabbableを有効にして、ここでもUse Gravityは無効にしておきましょう。

全体の位置移動と同期

お疲れ様です。一応ここまでの設定で関節操作の準備は整いました。が、全体の位置移動と同期のためにもうひと踏ん張り必要です。
03.png
全体の位置移動のため、人型オブジェクトの根本(Fixed Joint視点で見ても根本)にColliderを追加して、形と大きさを調整、IsTriggerを有効にします。SubItemのGrabbableを有効にして、ここでもUse Gravityは無効です。あとは同期のため、全てのSubItemのGroupIDを1に設定します。
※ここでのColliderの大きさは肩用のColliderと干渉しやすいので、小さめがオススメです。

スクリプト

仕上げにVCIObjectへスクリプトを貼り付ければ完成です。各SubItemの名前は適宜読み替えて変更してください。

local Obj = {
    "J_Bip_C_Head",
    "J_Bip_L_UpperArm",
    "J_Bip_R_UpperArm",
    "J_Bip_L_LowerArm",
    "J_Bip_R_LowerArm",
    "J_Bip_L_UpperLeg",
    "J_Bip_R_UpperLeg",
    "J_Bip_L_LowerLeg",
    "J_Bip_R_LowerLeg"
}

local Pos = {
    "Pos_Head",
    "Pos_ArmL",
    "Pos_ArmR",
    "Pos_ElbL",
    "Pos_ElbR",
    "Pos_LegL",
    "Pos_LegR",
    "Pos_KneL",
    "Pos_KneR"
}

local Rot = {
    "Rot_Head",
    "Rot_ArmL",
    "Rot_ArmR",
    "Rot_ElbL",
    "Rot_ElbR",
    "Rot_LegL",
    "Rot_LegR",
    "Rot_KneL",
    "Rot_KneR"
}

local Root = "Sample"

local RootGrab = false

function updateAll()
    for i = 1, #Pos do
        local pos = vci.assets.GetSubItem(Pos[i]).GetPosition()
        vci.assets.GetSubItem(Obj[i]).SetPosition(pos)
        vci.assets.GetSubItem(Rot[i]).SetPosition(pos)
    end
    for i = 1, #Rot do
        local rot = vci.assets.GetSubItem(Rot[i]).GetRotation()
        vci.assets.GetSubItem(Obj[i]).SetRotation(rot)
    end
    if RootGrab then
        for i = 1, #Pos do
            local rot = vci.assets.GetSubItem(Pos[i]).GetRotation()
            vci.assets.GetSubItem(Obj[i]).SetRotation(rot)
            vci.assets.GetSubItem(Rot[i]).SetRotation(rot)
        end
    end
end

function onGrab(target)
    if target == Root then
        RootGrab = true
    end
end

function onUngrab(target)
    for i = 1, #Obj do
        Stop(Obj[i])
        Stop(Pos[i])
        Stop(Rot[i])
    end
    Stop(Root)
    RootGrab = false
end

function Stop(target)
    local SubItem = vci.assets.GetSubItem(target)
    SubItem.SetVelocity(Vector3.__new(0, 0, 0))
    SubItem.SetAngularVelocity(Vector3.__new(0, 0, 0))
end

知能が感じられない脳筋スクリプトですが、一応動きます。(ご指摘お待ちしています!

参考

VCI作成
https://virtualcast.jp/wiki/doku.php?id=%E3%83%A2%E3%83%87%E3%83%AB%E4%BD%9C%E6%88%90:vci%E4%BD%9C%E6%88%90:vci%E4%BD%9C%E6%88%90
使用可能なUnityComponent
https://virtualcast.jp/wiki/doku.php?id=%E3%83%A2%E3%83%87%E3%83%AB%E4%BD%9C%E6%88%90:vci%E4%BD%9C%E6%88%90:%E4%BD%BF%E7%94%A8%E5%8F%AF%E8%83%BD%E3%81%AAunitycomponent
Fixed Joint
https://docs.unity3d.com/jp/current/Manual/class-FixedJoint.html
GroupIDについて
https://virtualcast.jp/wiki/doku.php?id=%E3%83%A2%E3%83%87%E3%83%AB%E4%BD%9C%E6%88%90:vci%E4%BD%9C%E6%88%90:groupid%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6
バーチャルキャストのVCIスクリプトの例
https://qiita.com/sakano/items/adc88174a7dfd32ae248
サンプルVCI
https://seed.online/items/8d7e3473bd5d31e872a0bffb6829aea468bdc45b9a44e159cb05600226cc3d62

120byte
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした