View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

その他のビデオ

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • トランスクリプト
  • コード
  • Reality Composer Proにおけるインタラクティブな3Dコンテンツの作成

    3Dコンテンツに生命を吹き込む、Reality Composer ProのTimelineビューについて解説します。インバースキネマティクス、ブレンドシェイプ、スケルトンポーズを使用して、キャラクターやオブジェクトが互いにやり取りしたり、それらを取り巻く世界と関わったりするアニメーションストーリーを作成する方法をご紹介します。組み込みのカスタムアクションの使用方法、アクションシーケンスの作成方法、トリガーの適用方法、自然な動きの実装方法についても説明します。

    関連する章

    • 0:00 - Introduction
    • 2:54 - Introducing timelines
    • 18:22 - Inverse kinematics
    • 22:55 - Animation actions
    • 27:23 - Blend Shapes animation
    • 30:35 - Skeletal poses

    リソース

    • Composing interactive 3D content with RealityKit and Reality Composer Pro
    • Forum: Spatial Computing
      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC24

    • カスタム環境でのよりイマーシブなメディア視聴体験の実現
    • 空間コンピューティング向けに3Dアセットを最適化
    • iOS、macOS、visionOS向けRealityKit APIの紹介
    • RealityKitデバッガの詳細

    WWDC23

    • Reality Composer Proにおけるマテリアルの詳細
    • Reality Composer Proについて
  • ダウンロード

    こんにちは Marinです RealityKit Toolsのエンジニアです 本日ご紹介するのは Reality Composer Proの まったく新しい機能「Timeline」です 新しいインタラクティブな方法で 3Dコンテンツに命を吹き込むことができます 昨年 Appleが発表した Reality Composer Proでは アプリで使用する3Dコンテンツの プレビューと準備を 簡単に行うことができます このツールのビジュアルエディタでは シーンを作成したり アセットを整理したり インタラクティブ機能や物理特性を追加したり または ShaderGraphエディタを使用して マテリアルの外観を微調整したりと 様々なことが行えます Reality Composer Proを初めて使う場合や 使用方法を再確認したい場合は 昨年のWWDCのこれらのセッションを ぜひご覧ください Reality Composer Proでは RealityKitコンテンツを視覚的に デザイン 編集 プレビューできます シーンの構成 コンポーネントの設定 複雑なマテリアルの作成 音声の追加など 様々な操作をすべて1か所で行えます 今年は 新しい機能を追加しました タイムラインエディタを使用して アニメーションを作成したり ライトを追加したり 環境オーサリングをサポートする機能です このセッションでは タイムラインエディタに焦点を当て Timelineを使用して インタラクティブなアプリを開発する方法と RealityKitの新しい アニメーションAPIについて説明します さっそく見てみましょう

    他のセッションでも このBOT-anistアプリを ご覧になっているかもしれません このアプリのロボットを利用して 新たに作り直し 独自のインタラクティブなバーチャル体験を 作成してみましょう このアプリを見ると 3種類の植物がしおれ始めています しおれている植物をタップすると ロボットがその植物まで移動して 水やりを始めます 植物はゆっくりと元気を取り戻し ロボットはプラットフォームの 中央に戻ります また別のロボットは 周囲を飛び回る蝶に 手を伸ばして触ろうとしています このセッションのリンク先から サンプルプロジェクトをダウンロードできます このアプリを構築するには まず Reality Composer Proの Timelineを使用して 植物の位置までロボットを移動させます

    次に RealityKitの フルボディインバースキネマティクス システムを利用して ロボットを動かし 植物に 水やりをさせる方法を説明します

    その後 ロボットを方向転換させ 開始位置まで戻すための アニメーションアクションを コードで記述する方法を 見ていきます

    さらに ブレンドシェイプ アニメーションを使用して 植物をアニメーション化する方法を紹介します

    最後に 蝶を追っている2体目のロボットに スケルトンポーズアニメーションを追加します

    では Timelineの概要から始めましょう TimelineはReality Composer Proの まったく新しい機能です 特定の順序で または特定の時間に 実行させるアクションの シーケンスを作成できます Reality Composer Proを使用すると これらのアクションの編集や設定を 簡単に行えます 左側のパネルには すべてのタイムラインがリスト表示されます

    中央はメインのタイムラインエディタです 右側のパネルにはビルトインアクションが すべてリスト表示されます タイムラインを作成すると トリガーに基づいて再生し タイムラインを開始することができます

    最初のアニメーションを見てみましょう このアプリでは 植物をタップすると ロボットがその植物の方向に動き出します このタイムラインシーケンスの 作成方法をご紹介しましょう Reality Composer Proを開くと 下部のパネルに という新しいタブがあります 中央にはボタンがあります タイムラインを作成するため このボタンを選択しましょう 左側には 利用可能な すべてのタイムラインがリスト表示されます 中央がメインのタイムラインエディタです ここでアクションを設定して タイムライン上に並べることができます 右側には あらかじめ用意しておいた すべてのビルトインアクションが リスト表示されています これらをタイムライン上に 簡単にドラッグ&ドロップできます タイムライン名を 「MoveToPoppy」に変更しましょう タイムラインを選択して ダブルタップし 「MoveToPoppy」と入力します

    まず ロボットがタップされた 植物の方を向くようにします そのためには 既存のアクションリストにある Spinアクションを使用します アクションを タイムラインまでドラッグします

    ロボットを回転させたいので インスペクタパネルのフィールドで を選択します 次に 階層ツリーまたはビューポートで ロボットエンティティを探し それを選択します 目的のエンティティを選択したら をタップします

    次に ロボットをどの程度 回転させるかを設定しましょう インスペクタパネルの を使用します これを「0.12」に設定しましょう

    1回転ではなく 少しだけ回転させます 実際に見てみましょう タイムラインエディタの上に 再生ボタンがあります このボタンをタップすると 設定したアクションをプレビューできます

    いいですね ロボットが少し回転して 植物の方を向きました 回転したあと ロボットを移動させてみましょう そのためには Transform Toアクションを使用します ビルトインアクションリストから アクションをドラッグして エディタ上にドロップします Spinアクションの1秒後に実行されるように シーケンスを設定します ロボットが植物に向かって 移動するようにしたいので このアクションのターゲットを ロボットに設定しましょう をタップして 階層ツリーでロボットを選択し をタップします ロボットの移動方向を視覚的に示す グラフィックスが表示されます 現在はプラットフォームの中央にいるので 変更する必要があります マニピュレータを使用して ポピーの前までロボットを動かします

    これで大丈夫です 次に Transformアクションの 継続時間を変更しましょう デフォルトの継続時間は1秒ですが もっと大きい値に変更します ロボットがより長い時間をかけて 植物まで移動するようになります そのためには エディタでアクションの 右端をドラッグします

    または インスペクタパネルで を設定します

    アクションをドラッグして 別のトラックへ移動できます これにより 複数のアクションを 同時に実行させることができます Spinアクションを別のトラックまで ドラッグしましょう これは後で使用します 再生ボタンをタップして どのように表示されるか プレビューしましょう

    いいですね 希望どおりになりました ロボットが植物まで移動する間に適用される アニメーションと音声を追加しましょう そのためには 別のタイムラインを作成して 歩行のアニメーションと音声が 同期するようにします タイムラインリストの下部にある ボタンをタップします このタイムラインの名前を 「RobotMove」に変更しましょう 新しいタイムラインを選択してダブルタップし 「RobotMove」と入力します

    アニメーションと音声を再生するため 2つの新しいコンポーネントを使用します Animation Libraryコンポーネントと Audio Libraryコンポーネントです これら2つのコンポーネントについて 説明しましょう Animation Libraryコンポーネントは アニメーションを保存し それを再生するエンティティと 関連付けるために使用されます Animation Libraryコンポーネントを 対象エンティティに追加し そのAnimation Libraryコンポーネントに アニメーションリソースを追加します Reality Composer Proでは Animation Libraryコンポーネントに アニメーションを簡単に追加できます ボタンをタップして プロジェクトからアニメーションを選択します これで そのエンティティの Animation Libraryコンポーネントに アニメーションリソースが追加されます これは このあとコードを使用して または Reality Composer Proでタイムラインを使用して アニメーションを再生するときに 使用できます

    Audio Libraryコンポーネントも Animation Libraryコンポーネントと よく似ています Audio Libraryコンポーネントを使用して 音声リソースを保存し それらを再生するエンティティに関連付けます Audio Libraryコンポーネントを エンティティに追加し そのAudio Libraryコンポーネントに 音声リソースを追加します Audio Libraryコンポーネントに 音声リソースを追加するには ボタンをタップして プロジェクトから音声ファイルを選択します これで そのエンティティの Audio Libraryコンポーネントに 音声リソースが追加されます

    そのあとコードで またはタイムラインを使用して 音声を再生できます Reality Composer Proに戻って 音声とアニメーションの タイムラインへの追加を完了させましょう RobotMoveタイムラインで 新しい Animation Libraryコンポーネントを使用して Animationアクションを追加します これから使用するプロジェクト画面に すでにUSDアニメーションが追加されています 階層ツリーでロボットを選択します インスペクタパネルを見ると 既にAnimation Libraryコンポーネントが 追加されていることがわかります これは このエンティティに 既にUSDアニメーションが 関連付けられているためです Reality Composer Proによって このコンポーネントが自動的に追加され デフォルトのアニメーションが アニメーションリストに表示されます インスペクタパネルの下部にある ボタンを選択して Animation Libraryコンポーネントを 手動で追加することもできます を 選択すると 再生ボタンを使用して このアニメーションをプレビューできます または はさみアイコンを使用して 複数のクリップに分割できます このアニメーションは少し長いので 2つのクリップに分割しましょう 短縮した前半と後半のアニメーションを 続けて再生します そのためには 再生ヘッドをドラッグして スライスしたい最初の位置まで動かします 次に はさみアイコンをクリックします 2つのクリップが作成されます もう1か所スライスして 最後の部分だけを使用します もう一度再生ヘッドをドラッグして 2番目のスライス位置まで移動します はさみアイコンをクリックします

    これで2つのクリップを 続けて再生できるようになりました 2つのクリップの名前を 「startWalk」と「endWalk」に変更します

    次に RobotMoveタイムラインを選択します これらのアニメーションが 続けて再生されるように並べましょう Aanimationアクションを タイムラインまでドラッグします

    このアクションのターゲットを ロボットにするため を選択した後 階層ツリーでロボットを選択します 次に を クリップに設定します

    2つ目のクリップ用として 別のAnimation アクションをタイムラインまでドラッグします

    このアニメーションは 最初のアニメーションの直後に実行します このアクションも ターゲットをロボットに設定します

    をendWalkクリップに設定します

    アニメーションの実行中 音声クリップも 同時に再生しようと思います そのためには Audio Libraryコンポーネントと 既にプロジェクトに追加してある 音声ファイルを使用します 階層ツリーでロボットを選択しましょう インスペクタパネルの ボタンを選択して 新しいコンポーネントを追加します リストから Audio Libraryコンポーネントを選択します

    ボタンをタップして

    必要な音声ファイルを見つけます ここでは2つの音声ファイルを追加します ロボットの方向転換時の音声と 移動する時の音声です

    RobotMoveタイムラインに戻って 音声アクションを実行する タイミングを設定しましょう Play Audioアクションを タイムラインにドラッグします ロボットが音声を発するようにしたいので としてロボットを選択します 先ほど追加した歩行用の オーディオクリップを再生するため オーディオリソースとして 歩行用音声を設定します さらに このオーディオアクションを ドラッグして 歩行アニメーションと同時に 再生されるようにします

    では 再生してみましょう

    アニメーションと音声が 一緒に再生されました これで RobotMoveタイムラインを MoveToPoppyタイムラインで 使用する準備が整いました MoveToPoppyタイムラインを選択しましょう 次に RobotMoveタイムラインを右クリックして オプションを選択します RobotMoveタイムラインが MoveToPoppyタイムラインに挿入されます これで タイムラインが別のタイムライン内で 再生されるようになりました ネスト化されたこのタイムラインは ドラッグして どこにでも移動できます 回転した直後に このアニメーションが 再生されるようにしましょう

    さらに Transformアクションと組み合わせて このアニメーションと変形が 同時に発生するようにします Transformアクションの 継続時間を変更しましょう アニメーションの開始から 少し遅れて移動し始め アニメーション終了の少し前に 移動を終えるようにします 次に ロボットが回転するときに再生する 音声クリップを追加しましょう 既定のアクションのリストから Play Audioアクションをドラッグし Spinアクションと同時に 実行されるように配置します ロボットをエミッタとして設定し 音声リソースとして 回転用の音声を設定します

    プレビューして どのように再生されるか確認しましょう

    素晴らしい!ロボットがポピーまで移動し アニメーションと音声が再生されました タイムラインを作成しましたが この再生をどのように 開始するのでしょうか? 2つの方法があります 1つは コードでRealityKit APIを使用し タイムラインのアニメーション リソースインスタンスで entity.playAnimationを呼び出す方法です またはReality Composer ProのUIを使用して 新しいBehaviorsコンポーネントを追加します この場合 コードを記述しなくても タイムラインを起動して 再生を開始できます Reality Composer Proを使用して タイムラインの再生を開始するには タイムラインをトリガーさせるエンティティに Behaviorsコンポーネントを 追加する必要があります タイムラインの再生を 開始するために使用できるトリガーは 数種類あります タップ時 衝突時 シーンにエンティティが追加された時 コードで通知が渡された時です Reality Composer Proに戻り 植物へのタップジェスチャでタイムラインの 実行が開始されるようにしましょう タップジェスチャを設定するには まず タップする植物を選択します ここでは 階層ツリーで ポピーを選択します 新しいコンポーネントを追加するため インスペクタパネルで ボタンをタップし Behaviorsコンポーネントを選択します 次に ボタンをタップして タップトリガーを選択します ユーザーのタップに ポピーが反応するようにするためです ポピー草をタップしたとき MoveToPoppyタイムラインの再生が トリガーされるようにしましょう リストから MoveToPoppyタイムラインを選択します ここで タップジェスチャに反応するよう RealityViewに指示する必要があります Xcodeを見てみましょう RealityViewで タップジェスチャを追加します

    タップジェスチャが targetedToAnyEntityになります ポピーをタップして指を上げたとき 渡された値からエンティティを取得し タップ動作をそのエンティティに適用します つまり 特定のエンティティをタップしたとき ここではポピーをタップしたとき Reality Composerで指定したタップ動作である MoveToPoppyタイムラインが適用されます これをビルドして実行すれば 動作を確認できます ポピーをタップして どうなるか見てみましょう

    素晴らしい!ポピーをタップした時 ロボットが向きを変えて その方向に移動しました 最初のアニメーションを適切に作成し ユーザーの入力に基づいて 再生が開始されるようになりました すごいですね! 2つ目のアニメーションでは ロボットがポピーまで移動した後 その花に手を伸ばすようにしましょう そのためには Notificationアクションを追加して そのNotificationアクションを コード内でリッスンします 通知が発生したとき ロボットがポピーに手を伸ばすようにするための カスタムコードを記述します では Reality Composer Proに戻って Notificationアクションを追加しましょう

    既定のアクションリストから Notificationアクションをドラッグして タイムラインの最後にドロップします

    このNotificationアクションの ターゲットとしてポピーを設定します 次に この通知の識別名として 「ReachToPoppy」と入力します

    この文字列は 通知が発生したときに渡されます Reality Composer Proで通知を設定したので この通知をリッスンするコードを ImmersiveViewに追加しましょう XcodeのImmersiveViewで 通知名「ReachToPoppy」を追加します 次に この通知のパブリッシャーを追加します

    その後 onReceiveを使用して RealityViewでの通知の受信を 処理します 出力から通知を受け取った時 ユーザー情報辞書から ソースエンティティを取得できます さらに ロボットがポピーに 手を伸ばす動作を開始するための コードを記述します どのようなアニメーションにするかを ご覧ください ポピー草の前まで移動したロボットが その花に手を伸ばします

    そのためには RealityKitのフルボディ インバースキネマティクスシステムを使用します インバースキネマティクスでは リグ付きスケルトン構造で 運動方程式を使用し 目的の位置に到達するための ジョイントの動きを決定します 目的の位置と 影響を受けるジョイントの 制約を指定すると そこに到達するまでのジョイントの位置が 自動的に計算されます 例えば 目的の位置まで手を動かす場合 その位置へ到達するように 肘の位置が自動的に調整されます これを使用すれば キャラクターの動きを 自然に見せることができます ここでは 新しい Inverse Kinematics APIについて 模式図を使用して説明し コードでの使用方法をご紹介します まず IKRigをインスタンス化します IKRigは インバースキネマティクスソルバが どのように動作するかを定義します IKRigにモデルスケルトンと イテレーション回数などの設定を追加します 同じエンティティで アニメーションを再生する場合 そのアニメーションに 重みを付加する必要があります IKの重みにより IKソルバは 何をオーバーライドするかを判断します 次に制約を追加します 制約とは ジョイントの 動きに対する制限です 制約を加えることで ひじを外側に曲げるなどの 不自然な動きを回避できます

    次に 定義したIKRigをもとに IKResourceを作成します IKResourceはIKソルバが 処理で使用するランタイムデータです IKResourceからIKComponentを作成し それをエンティティに追加します IKComponentをインスタンス化する時点で このソルバを設定し 実行時にフレームごとに更新できます

    ここで重要なのは RealityKitのIKソルバは ジョイント階層の一部だけでなく キャラクターの全身のスケルトンを 同時に解決する点です では インバースキネマティクスを使用して ロボットが植物に 手を伸ばすコードを記述しましょう

    インバースキネマティクスソルバを 設定するには まず 空のリグを初期化して modelSkeletonで渡します 次に グローバルなリグ設定を更新します 試行錯誤の結果 maxIterationsを30に設定し globalFkWeightを0.02に設定すると 最もよいことがわかりました その後 リグのスケルトンで ジョイント名を参照します この例では ロボットの腰 胸 手を動かして 植物に手を伸ばす ロボットのアニメーションが 自然に見えるようにする必要があります

    次に リグの制約を定義します ここでは 2つの親制約と 1つの点制約を設定します 親制約はジョイントの位置と 向きを制限します 点制約はジョイントの位置を制限します 次に このリグを含むリソースを作成し 指定したリソースを含む IKComponentを追加します フレームごとにIKターゲットを更新するため シーンでエンティティを見つけて それを配置します

    まず 手を伸ばしたときの位置を取得します この位置は IKComponentが 追加されているエンティティを 基準にする必要があります reachPositionのx、y、zの位置を変更して フレームごとにわずかに異なるようにします

    左手の制約もフレームごとに 更新する必要があります そのため エンティティから IKComponentを取得します 左手のターゲットの移動と 左手の位置を設定します 値0は IKによる制約への影響が ないことを意味します 値1は 制約に対して IKが完全に影響することを意味します

    IKの開始時および終了時にロボットの腕を スムーズにアニメーションさせるため 位置がIKによってどの程度動かされるか そして時間の経過とともに 基準ポーズによってどの程度動かされるかの 重みを徐々に増減させます その後 更新した値を IKComponentにコミットします

    コードを実行してみましょう

    いいですね アニメーションの目標を達成しました ロボットが手を伸ばした後 パーティクルエフェクトを使用して 花に水をやります 花への水やりが終わったので ロボットを開始位置に戻しましょう そのためには Animationアクションを使用します Animationアクションを使用すると アクションが発生するタイミングを設定し そのシーケンスを特定の時間に わたって作成できます ゲームのカットシーンの アニメーションに似ていますが Animationアクションでは これをリアルタイムで行えます よくある使用例の1つに キャラクターが歩くときの フットフォールイベントがあります キャラクターの足が地面に着くたびに 音を鳴らします Animationアクションを使用し プラットフォームの中央まで ロボットを戻しましょう

    アクションのAPIには 組み込みとカスタムがあります 組み込みアクションは複数の既定の アクションで構成され 簡単に設定できます SpinActionやPlayAnimationAction などがあります これらは Reality Composer Proの タイムライン機能の 基盤となるAPIです 組み込みアクション以外が必要な場合は カスタムアクションを使用できます 独自のアクションをコードで記述し タイムラインで同期させることができます 組み込みアクションAPIを使用するには まず 組み込みアクションを 使用するエンティティの アニメーション定義を作成します 次に その定義から アニメーションリソースを作成します 同時に 再生する アニメーションリソースをグループ化して それらを再生する順序に並べます 最後に エンティティで playAnimationを呼び出します これをコードで行う方法を確認しましょう

    それぞれロジックを含む 複数のメソッドがあります これらは ロボットを回転 移動 位置調整するためのアニメーションを定義し アニメーションリソースを返します これらのアニメーションリソース インスタンスのロジックは 既存のRealityKit APIを使用して 定義されています アニメーションのシーケンスを作成します 先頭から RotateAnimation WalkAndMoveAnimation AlignAtHomeAction RobotTravelHomeCompleteAction の順になります 次に 既存のplayAnimation APIを使用して これらのアニメーションを この順序で再生します

    カスタムアクションの場合 まず EntityActionに準拠した 独自のプロトコルを作成します 次に それをもとに makeActionAnimation APIを使用して AnimationResourceを作成します さらに そのAnimationResourceを 他とグループ化します または 特定の順序で 実行されるように並べます

    最後に エンティティで Play Animationを呼び出します これで 実行時に カスタムアクションの 開始イベントと終了イベントを サブスクライブできます

    これらのステップをコードで確認し 植物への水やりを終えたロボットが 開始位置に戻るようにしましょう RobotMoveToHomeCompleteという名前の カスタムアクションを作成します これを使用して move-to-home手順の 完了時に通知されるようにします 次に RobotMoveToHomeComplete EntityActionのインスタンスを作成します makeActionAnimation APIを使用して そこからAnimationResourceを生成します

    注目すべき点は カスタムアクションを使用して 複数のアニメーションをシーケンス処理したり グループ化したりできることです ここではアニメーションが1つだけなので シーケンス処理は行いません

    次に playAnimation APIを使用して AnimationResourceを再生します

    EntityActionの開始イベントを サブスクライブします このアクションが開始された時点で サブスクリプションクロージャが呼び出されます 開始イベントが発生すると ロボットが目的地に 到着したことがわかります 再生コントローラを停止して アニメーションを終了します さらに RobotMoveToHomeComplete EntityActionの終了イベントも サブスクライブします クロージャが呼び出されたら ロボットを.arrivedHome状態に 遷移させます

    では このアニメーションシーケンスを 実行してみましょう

    いいですね 順調に進んでいます

    次は植物のアニメーションに注目しましょう ここではブレンドシェイプ アニメーションを使用します ブレンドシェイプを使用すると 別のポーズへスムーズに遷移し リアルな動きを表現することができます 例えば キャラクターの顔や身体を アニメーション化するため 異なる一連のシェイプを ブレンドするときなどに使用されます ここでは しおれた植物が元気になる様子 またはその逆の様子を アニメーション化します

    ブレンドシェイプアニメーションAPIは BlendShapeWeightsMapping BlendShapeWeightsComponent および アニメーションを手続き的に実行する方法と USDで実行する方法で構成されます BlendShapeWeightsMappingでは ブレンドターゲットに関連付ける 重みを設定できます エンティティでブレンドターゲットを設定し 各ターゲットにそれぞれ重みを 関連付けることができます 重みは0〜1で設定できます ここでは しおれた状態の植物に重み1 中間の状態に重み0.5 元気な状態に重み0を設定します しおれた植物が元気になる様子を アニメーション化するため 時間の経過と共に重み値を更新します ブレンドシェイプアニメーションAPIを 使用するには まず BlendShapeWeightsMapping を定義します 次に このマッピングから BlendShapeWeightsComponentを作成して それをエンティティに追加します BlendShapeWeightsComponentを エンティティに追加した後は このコンポーネントに重み値を照会して いつでも更新することができます これで FromToByまたはサンプリングされた ブレンドシェイプアニメーションを 手続き的に作成できるようになりました 既存の RealityKit playAnimation APIを使用して USDブレンドシェイプアニメーションを 再生することもできます コードでの作成手順を見ていきましょう まず エンティティ階層で モデルコンポーネントを含む モデルエンティティを見つけます そのメッシュリソースを取得し そこから BlendShapeWeightsMappingを作成します 次に このマッピングから BlendShapeWeightsComponentを作成します

    実行時にブレンドの重みを更新するため エンティティから BlendShapeWeightsComponentを取得します

    BlendShapeWeightsSetのコピーを取得します これで このセットに重み値を 割り当てることができます

    BlendShapeWeightsSetの blendWeightIndexによって すべての重み値を更新します 元気な状態の植物を示す 「0」に設定します ここでは 植物が 元気な状態になるように設定します ここからしおれた状態に遷移させるため イージング関数を使用して この値を徐々に増減します

    その後 新しい重み値を BlendShapeWeightsComponentに割り当てて 有効にします

    コードを実行して これらの花を元気にしましょう

    しおれていた花が 元気を取り戻しました ここで もう1台のロボットが 何をしているか見てみましょう

    インバースキネマティクスにより ロボットが蝶に 手を伸ばしています また Animationアクションによって 蝶が飛び回っています これらは Reality Composer Proで タイムラインを使用して作成されています 蝶の位置を変更する カスタムコンポーネントも使用されています ロボットの頭部に注目すると 蝶の飛ぶ方向を 追っているのがわかります この動きを実現するには 新しいスケルトンポーズAPIを使用します 標準的なリグ付き3Dキャラクターは 相互接続されたボーンからなる スケルトン構造になっています 各ボーンは キャラクターまたは オブジェクトの それぞれ異なる部分に対応します

    キャラクターをアニメーション化するには ジョイントを回転させて オブジェクトにポーズを取らせ 様々な位置に動かします この手法は キャラクターを歩かせたり 走らせたりするときによく用いられます

    スケルトンポーズAPIは新しい SkeletalPosesComponentを追加します RealityKitによって生成される アニメーションを使用できます または インターフェイスを使用して 実行時にスケルトンを変更できます その場合 特定のジョイントについて プログラムで SkeletalPosesComponentに照会し トランスフォームを更新します

    ここでは スケルトンポーズAPIを使用して ロボットのネックボーンを回転させ 飛び回る蝶を見ているかのような 動きを実現します

    USDファイルから RealityKitにインポートされる スキンメッシュでは SkeletalPosesComponentが既に エンティティにアタッチされているので 初期化する必要はありません SkeletalPosesComponentを エンティティから取得するだけです 首関節の回転を更新します これはローカル空間であることに 注意してください フレームごとに首の回転を更新するには RealityKitの更新関数から このコードを呼び出します RealityKitは フレームごとに 登録済みの すべてのシステムで更新関数を呼び出します さらに 更新した値を コンポーネントにコミットします ジョイントトランスフォーム全体 または並行移動 スケール 回転のみを 更新できます 最大で毎フレーム更新できます コードを実行して 飛び回る蝶を目で追う ロボットの動作を確認しましょう

    どうでしょう ワクワクしませんか?

    このセッションで取り上げた内容を まとめましょう

    Reality Composer Proの Timeline機能を使用してタイムライン上に アクションを配置し 初期化した後 トリガーによって再生する方法を説明しました 新しいフルボディインバースキネマティクスAPI を使用して ロボットがオブジェクトに 手を伸ばす動作を作成しました 組み込みとカスタムのアクションを使用して アクションのシーケンスを作成しました ブレンドシェイプアニメーションを使用して 異なる一連のシェイプを ブレンドする方法を見てきました ジョイントを回転させて オブジェクトを様々な位置に配置して ポーズ付けをし それらを アニメーション化する方法を見ました

    これらの他にも 今年 Reality Composer Proには 数々のエキサイティングな機能が 追加されました ビデオドッキング iOSとmacOSへのデプロイ機能 そして visionOS 環境オーサリング ライティングなどです

    これらのトピックについて詳しくは 次のセッションをご覧ください 「Enhance the immersion of media viewing in custom environments」 「Discover RealityKit APIs for iOS, macOS and visionOS」 これらの新機能はインタラクティブな 3Dコンテンツの作成に役立ちます 今後 皆さんが開発するアプリを 楽しみにしています ありがとうございました WWDCをお楽しみください

    • 20:31 - Setup IKComponent

      // Setup IKComponent
      import RealityKit
      
      struct HeroRobotRuntimeComponent: Component {
              var rig = try? IKRig(for: modelSkeleton)
                      
              rig.maxIterations = 30
              rig.globalFkWeight = 0.02
                      
              let hipsJointName = "root/hips"
              let chestJointName = "root/hips/spine1/spine2/chest"
              let leftHandJointName = "root/hips/spine1/spine2/chest/…/L_arm3/L_arm4/L_arm5/L_wrist"
      
              rig.constraints = [
                  .parent(named: "hips_constraint",
                          on: hipsJointName,
                          positionWeight: SIMD3(repeating: 90.0),
                          orientationWeight: SIMD3(repeating: 90.0)),
                  .parent(named: "chest_constraint",
                          on: chestJointName,
                          positionWeight: SIMD3(repeating: 120.0),
                          orientationWeight: SIMD3(repeating: 120.0)),
                  .point(named: "left_hand_constraint",
                         on: leftHandJointName,
                         positionWeight: SIMD3(repeating: 10.0))
                      ]
                      
              let resource = try? IKResource(rig: rig)                
              modelComponentEntity.components.set(IKComponent(resource: resource))
      }
    • 21:33 - Update IKComponent

      // Update IKComponent
      import RealityKit
      
      struct HeroRobotRuntimeComponent: Component {
              guard let reachTarget = sceneRoot.findEntity(named: "reachTargetName") else {
                  return
              }
      
              var reachPosition = reachTarget.position(relativeTo: entity)
      
              let time = sin(simTime)
              reachPosition.x += (20.0 + 50.0 * time)
              reachPosition.y += (40.0 + 30.0 * abs(time))
              reachPosition.z += (20.0 + 20.0 * abs(time))
        
             guard let ikComponent = modelComponentEntity.components[IKComponent.self] else {
                 return
             }
      
             var reachPosition = reachTarget.position(relativeTo: entity)
             ...
             var leftHandConstraint = ikComponent.solvers.first?.constraints["left_hand_constraint"]
             leftHandConstraint?.target.translation = reachPosition
      
             // A blendValue = 0 means no influence on the constraint.
             // A blendValue = 1 means full influence on the constraint.
             var blendValue = isEnabled ? (time / totalBlendTime) : (1.0 - time / totalBlendTime)
             leftHandConstraint?.animationOverrideWeight.position = blendValue
      
             modelComponentEntity.components.set(ikComponent)
      }
    • 24:36 - Sequence and play animation actions

      // Play Animation Actions
      import RealityKit
      
      struct HeroRobotRuntimeComponent: Component {
             let rotateAnimationResource = createRotateAnimationResource()
             let walkAndMoveAnimationGroup = createWalkAndMoveAnimationGroup()
             let alignAtHomeActionResource = createAlignAtHomeActionResource()
             let robotTravelHomeCompleteActionResource = createRobotTravelHomeCompleteAction()
      
             // Build a sequence of the rotate, move and align animations/actions to play.
             let moveHomeSequence = try? AnimationResource.sequence(with: [rotateAnimationResource,
                                                                          walkAndMoveAnimationGroup,
                                                                          alignAtHomeActionResource,
                                                             robotTravelHomeCompleteActionResource])
                                  
             // Play the move-to-home sequence.
             _ = robotEntity.playAnimation(moveHomeSequence)
      }
    • 25:59 - Setup EntityActions

      // Setup EntityActions
      import RealityKit
      
      struct HeroRobotRuntimeComponent: Component {
          struct RobotMoveToHomeComplete: EntityAction {
              var animatedValueType: (any AnimatableData.Type)? { nil }
          }
      
          let travelCompleteAction = RobotMoveToHomeComplete()
      
          let actionResource = try! AnimationResource.makeActionAnimation(for: travelCompleteAction,
                                                                          duration: 0.1)
          
          let _ = robotEntity.playAnimation(actionResource)
      }
    • 26:39 - EntityAction subscription

      // EntityAction subscription
      import RealityKit
      
      struct HeroRobotRuntimeComponent: Component {
                        // Subscribe to know when the EntityAction has started.
                      RobotMoveToHomeComplete.subscribe(to: .started) { event in
                          if event.playbackController.entity != nil {
                              event.playbackController.stop()
                          }
                      }
        
                      // Possible states of the robot.
                      public enum HeroRobotState: String, Codable {
                          case available
                          …
                          case arrivedHome
                      }
      
                     // Subscribe to know when the EntityAction has ended.
                      RobotMoveToHomeComplete.subscribe(to: .ended) { event in
                          if let robotEntity = event.playbackController.entity,
                          var component = robotEntity.components[HeroRobotRuntimeComponent.self] {
                             component.setState(newState:.arrivedHome)
                          }
                      }
      }
    • 29:17 - Setup BlendshapeWeightsComponent

      // Setup BlendShapeWeightsComponent
      import RealityKit
      
      struct HeroPlantComponent: Component, Codable {
              guard let modelComponentEntity = findModelComponentEntity(entity: entity),
                    let modelComponent = modelComponentEntity.components[ModelComponent.self]
              else { return }
      
                  let blendShapeWeightsMapping
                     = BlendShapeWeightsMapping(meshResource: modelComponent.mesh)
      
                  // Create the blend shape weights component.
                  entity.components.set(BlendShapeWeightsComponent(weightsMapping:
                                                                  blendShapeWeightsMapping))
      }
    • 29:38 - Update BlendshapeWeightsComponent

      // Update BlendShapeWeightsComponent
      
      struct HeroPlantComponent: Component, Codable {
              guard let component = entity.components[BlendShapeWeightsComponent.self]
              else { return }
      
              var blendWeightSet = blendShapeComponent.weightSet
      
              // Update the weights in the BlendShapeWeightsSet
              for weightIndex in 0..<blendWeightSet[blendWeightsIndex].weights.count {
                  blendWeightSet[blendWeightsIndex].weights[weightIndex] = 0.0
              }
      
              // Assign the new weights to the blend shape component.
             for index in 0..<blendWeightSet.count {
                  component?.weightSet[blendWeightsIndex].weights = blendWeightSet[index].weights
              }
      }
    • 32:01 - Setup and update Skeletal Poses

      // Update Skeletal Poses
      import RealityKit
      
      struct StationaryRobotRuntimeComponent: Component {
      
              guard var component = entity.components[SkeletalPosesComponent.self] 
              else {
                  return
              }
              
              let neckRotation = calculateRotation()
      
              component.poses.default?.jointTransforms[neckJointIndex].rotation = neckRotation
      }
  • 特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。

    クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。

Developer Footer

  • ビデオ
  • WWDC24
  • Reality Composer Proにおけるインタラクティブな3Dコンテンツの作成
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン