r3f-physics について
r3f-physicsは、React Three Fiberに物理シミュレーションを追加する開発者向けガイドです。Rapierの剛体、コライダー、力、時間刻み、衝突イベントを説明します。
主な機能
- 01剛体の種類とコライダー設定
- 02力とインパルスの管理
- 03物理時間刻みとレンダーループの指針
- 04センサー、衝突イベント、ジョイント
- 05キャラクターコントローラーとシミュレーション検証
活用シーン
- 01落下してクリック可能なオブジェクトの追加
- 02コライダーを使った静的環境の構築
- 03ジョイントによる剛体の接続
- 04センサーや高速移動する剛体のテスト
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ enzed/ r3f-skills --skill r3f-physicsインストール後、Claude Code で/r3f-physicsを入力して読み込まれたか確認します。
同梱ファイルreferences/controllers.md
詳細
React Three Fiber の物理演算
Fiber、React、Rapier のインストール済みバージョンを確認してください。Rapier 2 は Fiber 9/React 19 を対象としています。それ以前のプロジェクトでは、互換性のあるパッケージ系列が必要です。レンダリングとシミュレーションの管理は分離してください。
落下するボディとクリック可能なボディ
ライティングとともに Canvas の下にマウントしてください。Physics は WASM を非同期で読み込むため、Suspense を含めてください。Cuboid コライダーの引数は半径であり、BoxGeometry の全寸法とは異なります。
import { Suspense, useRef } from 'react'
import { CuboidCollider, Physics, RigidBody, type RapierRigidBody } from '@react-three/rapier'
function FallingBox() {
const body = useRef<RapierRigidBody>(null)
return (
<RigidBody ref={body} position={[0, 2, 0]} colliders="cuboid" restitution={0.2}>
<mesh name="physics-box" onClick={() => body.current?.applyImpulse({ x: 0, y: 3, z: 0 }, true)}>
<boxGeometry />
<meshStandardMaterial color="coral" />
</mesh>
</RigidBody>
)
}
export default function Example() {
return (
<Suspense fallback={null}>
<Physics timeStep={1 / 60}>
<FallingBox />
<RigidBody type="fixed" colliders={false}>
<CuboidCollider args={[4, 0.25, 4]} position={[0, -0.25, 0]} />
<mesh position={[0, -0.25, 0]}>
<boxGeometry args={[8, 0.5, 8]} />
<meshStandardMaterial color="slategray" />
</mesh>
</RigidBody>
</Physics>
</Suspense>
)
}
ボディとコライダー
- Dynamic ボディは力に反応します。Fixed ボディは静的な表面を表します。Position-kinematic ボディには
setNextKinematicTranslation/Rotationを使用し、velocity-kinematic ボディには線速度/角速度のセッターを使用します。 - 初期トランスフォームは RigidBody に設定してください。
useFrame内でシミュレーション中のメッシュの position をアニメーションさせないでください。物理ワールドが状態の管理を担い、補間によって上書きされる場合があります。 - シンプルなコライダー、または複合凸形状を優先してください。trimesh は主に静的な凹形状の環境に使用します。凸包は穴を塞ぐため、任意の凹形状を保持できません。
- 完全な手動コライダーを指定する場合は
colliders={false}を設定してください。そうしないと、自動コライダーも追加される場合があります。コライダーのサイズ/トランスフォームはワールドスケールに合わせてください。デバッグ描画を使って確認してください。 - コライダーの密度/質量は一貫性を保って設定し、自動コライダーと手動コライダーの重複による意図しない質量の二重計上を避けてください。
- 繰り返し使うボディが多数ある場合、InstancedRigidBodies はレンダリングのオーバーヘッドを削減しますが、各ボディのシミュレーションコストは削減しません。インスタンスのキー/トランスフォームは安定させてください。
力とシミュレーション時間
- インパルスは一度限りの運動量の変化です。力はリセットされるまで持続し、
addForceを繰り返し呼び出すと蓄積します。明示的な力の管理方針がない限り、レンダーフレームごとに同じ持続力を加えないでください。 - シミュレーションのティックに合わせる必要がある入力/力には
useBeforePhysicsStepを使用してください。コントローラーがボディに対するすべてのユーザー入力の力を管理する場合、ティックごとにリセットして再適用できます。リセットする前に、ほかの力の発生源と調整してください。 - キネマティックターゲットは物理ステップごとに進めてください。
setTranslationによるテレポートはキネマティック移動とは異なり、期待される衝突応答を回避する場合があります。 - 安定した挙動には固定タイムステップを優先してください。
timeStep="vary"は予測可能性と引き換えに可変ステップを使用します。値にレンダーの delta を掛けても、物理演算が決定論的になるわけではありません。 - demand rendering では
Physics updateLoop="independent"を使い、アクティブなボディがレンダリングを要求できるようにしてください。スリープ中のワールドによって不要なレンダリングが発生しないようにしてください。 - ボディはスリープできるようにし、必要なアクションを適用する際は明示的に起こしてください。トンネリングが問題になる高速/小型のボディでは、コストを考慮したうえで CCD を有効にしてください。
イベント、センサー、ジョイント
- センサーは接触応答なしで交差の開始/終了を報告します。通常の衝突イベントではなく、センサーの交差イベントを使用してください。
- 衝突グループには、両方のコライダーで互換性のある所属/フィルターマスクが必要です。形式上必要な場合を除き、マスクを手作業で構築する代わりに
interactionGroupsを使用してください。 - 衝突ペイロードには、独立したコライダーの rigidBodyObject が含まれない場合があります。相手側のコライダー/ボディを安全に調べ、すべての衝突対象が名前付きメッシュだと決めつけないでください。
- インストール済み Rapier のコールバック制約に従ってください。接触フィルターフックでは、Rust のシミュレーション状態が借用されている間に問い合わせを行わず、ステップ前にボディの状態をキャッシュしてください。
- ジョイントはワールド座標ではなく、ローカルアンカーと軸を使ってボディ参照を接続します。固定、回転、球面、スプリング、ロープの各拘束について、フックが求めるタプルの形を確認してください。
- ステップに同期したキネマティックプラットフォームと、正しく配置されたヒンジについては、制御された移動とジョイントを参照してください。
- 衝突を考慮するキャラクターコントローラーは、メッシュを移動させたり、dynamic ボディの位置を設定したりすることとは別のものです。インストール済み Rapier のキャラクターコントローラー API を使用し、階段/斜面/接地をテストしてください。
- ワールドスナップショットを復元するには、ボディの作成とハンドルの関係を一致させる必要があります。既存の React 参照の下で任意のシーンを切り替える汎用的な方法ではありません。
検証
静止時の接触、コライダーの位置合わせ、インパルス、スリープとウェイク、および異なるレンダリングフレームレートを確認します。使用する経路について、センサーの進入と退出、高速ボディのトンネリング、Strict Mode での再マウントをテストします。
ソース
コメント
Markdown 対応