1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SCNIKConstraintを使ってロボットの腕を自由自在にアニメーションさせる

Last updated at Posted at 2020-10-03

SceneKitで3Dモデルをアニメーションさせる方法はいくつかの選択肢がありますが、3Dモデルの腕や足を自由自在にアニメーションさせようとなると、選択肢はSCNIKConstraintか、SCNAnimationになってくると思います。

<アニメーションの方法>

  • SCNTransaction ・・・ シーン全体をノードの回転や移動を使って一斉にアニメーションさせる
  • SCNAction ・・・ 個別のノードについてノードの回転や移動を使ってアニメーションさせる
  • SCNIKConstraint ・・・ 連結されたボーンを使って操り人形のように動かす
  • SCNAnimation ・・・ 事前に設定されたアニメーションを実行する

それぞれの違いはこちらの記事が詳しいです。

SceneKitにおけるアニメーションの実施方法と使い分けについて

SCNAnimationは事前に定義しておけば自由自在に操作できますが、アニメーションの速度や移動量をインタラクティブに操作したいときにはSCNIKConstraintが適しています。

ということで、SCNIKConstraintでロボットの腕を自由自在にアニメーションさせる方法を説明します。

SCNIKConstraintとは?

SCNIKConstraintのIKは、Inverse kinematicsと呼ばれるものです。

こちらの記事がわかりやすかったので引用します。
Inverse Kinematicsの実装メモ

 IKとは、人間がとある場所に手を伸ばすときのように手、手首、腕、肩と連動して体を動かすように、連結されたものがとある点に向かうようにする動作を言います。

SCNIKConstraintは、SceneKitのノードにこのIKを適用できるようにするための仕組みです。

参考:
Apple公式: SCNIKConstraint

手順

今回は、ロボットの左腕がドラッグ量にあわせて移動するようなアニメーションを作ります。

1.3Dモデルを用意する

3Dモデルにはボーンの設定が入っているものが必要です。
今回は、既存のモデルを使用します。

AppleのARKitのサンプルプロジェクトにロボットの3Dモデル(ファイル名: robot.usdz)が付属しているので、これを使用します。

Capturing Body Motion in 3D

なお、こちらの記事にはモデリングツールで作っている例がありました。

【SceneKit】SCNIKConstraintの使い方

2.Xcodeのプロジェクト作成からGameのプロジェクトを作成する

3.プロジェクトにusdzのファイルをドラッグ & ドロップする

usdz形式の3DモデルをSceneKitに読み込む方法はこちらの記事をご覧ください。

usdz形式の3DモデルをSceneKitに読み込みんでアニメーションさせる

4.画面がドラッグされたら検知するようにする

viewDidLoadで、UIPanGestureRecognizerを登録します。

GameViewController.swift
let tapGesture = UIPanGestureRecognizer(target: self, action: #selector(handleDrag(_:)))
scnView.addGestureRecognizer(tapGesture)

5.起点と終点となる2つのジョイントを決定する

Xcodeでモデルのボーンの情報を確認しながら、起点と終点(実際に動く部分)となる2つのジョイントを決定します。
今回は、左の肩のあたりを起点として、左手を終点として移動させるようにしました。

image.png

2点のジョイントは適切に選ばないと、動かないか、おかしな動きになります。

例えば、腰と左手の2点を選んだらサタデーナイトフィーバーのジョン・トラボルタのようになってしまいました。

6.ドラッグされたらロボットの腕が動くようにする

ドラッグの移動量を取得し、それを元にロボットの腕の移動先を決定します。

GameViewController.swift
@objc
func handleDrag(_ gestureRecognize: UIPanGestureRecognizer) {
    // アニメーションの起点となる場所を取得する(ここでは左腕の肩)
    guard let root = scene.rootNode.childNode(withName: "left_shoulder_1_joint", recursively: true) else { return }
    // 実際に移動させる場所を取得する(ここでは左腕の手)
    guard let target = scene.rootNode.childNode(withName: "left_hand_joint", recursively: true) else { return }

    // SCNIKConstraintに、起点と移動させる場所を指定する
    let ik:SCNIKConstraint = SCNIKConstraint.inverseKinematicsConstraint(chainRootNode: root)
    target.constraints = [ik]

    // ドラッグの移動量から、ロボットの腕の移動量を決定する
    let move = gestureRecognize.translation(in: view)
    let targetPosition = SCNVector3(target.position.x + Float(move.x * 0.1), target.position.y + Float(move.y * 0.1 * -1), target.position.z)

    // 腕を移動させる
    ik.targetPosition = targetPosition
}

仕上がり

20201003qiita用.gif

iOSアプリ開発に関する情報を発信しています。
Twitterでも発信していますのでフォローして下さい。
https://twitter.com/jugemjugemjugem

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?