Genesis 物理シミュレーション 完全チュートリアル
🎯 このチュートリアルの目的
Genesisは、ロボット工学や物理シミュレーションのためのオープンソースエンジンです。 このチュートリアルでは、クラウドGPU環境(vast.ai)でディスプレイなしでGenesisを動かし、 布・液体・雪などの物理シミュレーションを行う方法を、初心者向けに解説します。
1. 環境構築
1.1 前提条件
クラウドGPU: vast.ai
GPU: NVIDIA GPU(RTX 4090 推奨)
OS: Ubuntu 24.04
Python: 3.10以上
1.2 必須パッケージのインストール
PyTorchが必要なためVast.aiで、PyTorchを含んだTemplateを選んでください。
また、クラウド環境にはディスプレイがないため、EGL(組み込みグラフィックスライブラリ)を使います。
# システムパッケージをインストール
apt-get update
apt-get install -y libegl1 libegl-dev libgl1 libgles2 libglvnd-dev
なぜ必要?
libegl1: EGLランタイム(ディスプレイなしでOpenGLを使うため)
libgl1: OpenGLライブラリ
libgles2: OpenGL ES(組み込み向けOpenGL)
libglvnd-dev: GPU選択用ライブラリ
1.3 環境変数の設定
# 現在のセッションに設定
export PYOPENGL_PLATFORM=egl
export __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/10_nvidia.json
# 永続化(次回ログイン時も有効)
echo 'export PYOPENGL_PLATFORM=egl' >> ~/.bashrc
echo 'export __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/10_nvidia.json' >> ~/.bashrc
source ~/.bashrc
各環境変数の意味:

1.4 Genesisのインストール
pip install genesis-world
1.5 インストール確認
import genesis as gs
gs.init(backend=gs.gpu)
print("Genesis installed successfully!")
2. 基本テスト:箱の落下
2.1 コンセプト
最初のテストとして、シンプルな箱が落下するシミュレーションを作ります。
学ぶこと:
シーンの作成
エンティティ(物体)の追加
カメラの設定
動画の録画・保存
2.2 コード
"""
Step 1: 基本テスト - 箱の落下
初心者向け:最もシンプルなGenesisシミュレーション
"""
import genesis as gs
# ========================================
# 1. Genesis初期化
# ========================================
# backend=gs.gpu でGPUを使用
gs.init(backend=gs.gpu)
# ========================================
# 2. シーン作成
# ========================================
scene = gs.Scene(
sim_options=gs.options.SimOptions(
dt=4e-3, # タイムステップ(小さいほど精密、遅い)
substeps=10, # 1ステップあたりの内部計算回数
),
show_viewer=False, # ★重要:ヘッドレス環境ではFalse
vis_options=gs.options.VisOptions(
show_world_frame=True, # 座標軸を表示
),
renderer=gs.renderers.Rasterizer(), # レンダラー
)
# ========================================
# 3. 地面を追加
# ========================================
plane = scene.add_entity(
morph=gs.morphs.Plane(), # 無限の平面
)
# ========================================
# 4. 箱を追加
# ========================================
box = scene.add_entity(
morph=gs.morphs.Box(
size=(0.2, 0.2, 0.2), # 20cm x 20cm x 20cm
pos=(0, 0, 1.0), # 高さ1mの位置
),
material=gs.materials.Rigid(), # 剛体
)
# ========================================
# 5. カメラを追加
# ========================================
cam = scene.add_camera(
res=(1280, 720), # 解像度
pos=(3.0, -3.0, 2.5), # カメラ位置
lookat=(0, 0, 0.5), # 注視点
fov=40, # 視野角
GUI=False, # ★重要:ヘッドレスではFalse
)
# ========================================
# 6. シーンをビルド
# ========================================
# build()を呼ぶと、全ての設定が確定される
scene.build()
# ========================================
# 7. シミュレーション実行&録画
# ========================================
cam.start_recording()
for i in range(500): # 500ステップ
scene.step() # 物理シミュレーションを1ステップ進める
cam.render() # カメラでレンダリング
# ========================================
# 8. 動画保存
# ========================================
cam.stop_recording(save_to_filename="step1_box_drop.mp4", fps=60)
print("✅ 完了: step1_box_drop.mp4")2.3 実行方法
PYOPENGL_PLATFORM=egl python step1_basic.py出力: step1_box_drop.mp4 - 箱が落下して地面で跳ねる動画
3. 布シミュレーション(PBD)
3.1 PBDとは?
PBD (Position Based Dynamics) は、布やロープなど柔らかい物体をシミュレートする手法です。
特徴:
高速で安定
リアルタイム向け
布、ロープ、ソフトボディに最適
3.2 布メッシュの作成
まず、布の形状を定義するメッシュファイル(.obj)を作成します。
"""
布メッシュ生成スクリプト
2m x 2m の平面メッシュを作成
"""
import numpy as np
import os
def create_cloth_mesh(filename, size=2.0, divisions=20):
"""
Parameters:
filename: 出力ファイル名
size: 布のサイズ(メートル)
divisions: 分割数(多いほど細かい)
"""
half = size / 2
vertices = []
faces = []
# 頂点を生成
for j in range(divisions + 1):
for i in range(divisions + 1):
x = -half + (i / divisions) * size
y = -half + (j / divisions) * size
z = 0
vertices.append((x, y, z))
# 面を生成(三角形)
for j in range(divisions):
for i in range(divisions):
# 4つの頂点インデックス
v0 = j * (divisions + 1) + i
v1 = v0 + 1
v2 = v0 + (divisions + 1)
v3 = v2 + 1
# 2つの三角形で1つの正方形を構成
faces.append((v0 + 1, v1 + 1, v3 + 1)) # OBJは1始まり
faces.append((v0 + 1, v3 + 1, v2 + 1))
# OBJファイルとして保存
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, 'w') as f:
f.write("# Cloth mesh\n")
for v in vertices:
f.write(f"v {v[0]} {v[1]} {v[2]}\n")
for face in faces:
f.write(f"f {face[0]} {face[1]} {face[2]}\n")
print(f"✅ メッシュ生成完了: {filename}")
print(f" 頂点数: {len(vertices)}, 面数: {len(faces)}")
# 実行
create_cloth_mesh("meshes/cloth.obj", size=2.0, divisions=20)
3.3 布シミュレーションコード
"""
Part 1: PBD布シミュレーション
4角を固定したハンモック状の布
"""
import genesis as gs
gs.init(backend=gs.gpu)
# シーン作成(PBDソルバー有効)
scene = gs.Scene(
sim_options=gs.options.SimOptions(
dt=4e-3,
substeps=10,
),
pbd_options=gs.options.PBDOptions(), # ★PBDソルバーを有効化
show_viewer=False,
vis_options=gs.options.VisOptions(
show_world_frame=True,
),
renderer=gs.renderers.Rasterizer(),
)
# 地面
scene.add_entity(morph=gs.morphs.Plane())
# 布を追加
cloth = scene.add_entity(
material=gs.materials.PBD.Cloth(), # ★PBD布マテリアル
morph=gs.morphs.Mesh(
file='meshes/cloth.obj',
scale=1.0,
pos=(0, 0, 1.0), # 高さ1m
),
surface=gs.surfaces.Default(
color=(0.2, 0.4, 0.8, 1.0), # 青色
vis_mode='particle', # 粒子表示(変形が見やすい)
)
)
# カメラ
cam = scene.add_camera(
res=(1280, 720),
pos=(4.0, -4.0, 2.5),
lookat=(0, 0, 0.5),
fov=45,
GUI=False,
)
# ビルド
scene.build()
# ========================================
# 布の4角を固定
# ========================================
# 固定したい角の座標(布の4隅)
corners = [
(-1, -1, 1.0), # 左下
(1, 1, 1.0), # 右上
(-1, 1, 1.0), # 左上
(1, -1, 1.0), # 右下
]
# 各角に最も近い粒子を見つけて固定
particle_indices = []
for corner in corners:
idx = cloth.find_closest_particle(corner)
particle_indices.append(idx)
# ★重要:fix_particles()はリストで渡す(複数形に注意!)
cloth.fix_particles(particle_indices)
# シミュレーション実行
cam.start_recording()
for i in range(1000):
scene.step()
cam.render()
cam.stop_recording(save_to_filename="cloth_hammock.mp4", fps=60)
print("✅ 完了: cloth_hammock.mp4")

3.4 実行結果
布が重力で垂れ下がり、ハンモック状になる
4角が固定されているため、中央が最も下がる
4. 液体シミュレーション(SPH)
4.1 SPHとは?
SPH (Smoothed Particle Hydrodynamics) は、流体を粒子の集まりとしてシミュレートする手法です。
特徴:
水、油などの液体に最適
粒子ベースで飛沫も表現可能
計算コストは高め
4.2 液体シミュレーションコード
"""
Part 2: SPH液体シミュレーション
水のブロックが落下して広がる
"""
import genesis as gs
gs.init(backend=gs.gpu)
# シーン作成(SPHソルバー有効)
scene = gs.Scene(
sim_options=gs.options.SimOptions(
dt=4e-3,
substeps=10,
),
sph_options=gs.options.SPHOptions(
lower_bound=(-1.0, -1.0, 0.0), # シミュレーション領域の下限
upper_bound=(1.0, 1.0, 2.0), # シミュレーション領域の上限
particle_size=0.015, # 粒子サイズ
),
show_viewer=False,
renderer=gs.renderers.Rasterizer(),
)
# 地面
scene.add_entity(morph=gs.morphs.Plane())
# 水ブロックを追加
water = scene.add_entity(
material=gs.materials.SPH.Liquid(), # ★SPH液体マテリアル
morph=gs.morphs.Box(
size=(0.3, 0.3, 0.3), # 30cm立方体
pos=(0, 0, 0.5), # 高さ0.5m
),
surface=gs.surfaces.Default(
color=(0.3, 0.5, 0.9, 0.8), # 青色(半透明)
vis_mode='particle',
)
)
# カメラ
cam = scene.add_camera(
res=(1280, 720),
pos=(2.5, -2.5, 1.5),
lookat=(0, 0, 0.2),
fov=50,
GUI=False,
)
# ビルド
scene.build()
# シミュレーション実行
cam.start_recording()
for i in range(800):
scene.step()
cam.render()
if (i + 1) % 200 == 0:
print(f"進行中... {i+1}/800 ステップ")
cam.stop_recording(save_to_filename="liquid_splash.mp4", fps=60)
print("✅ 完了: liquid_splash.mp4")

4.3 パフォーマンス
FPS: 約8 FPS(粒子数27,000個)
SPHは近傍探索が計算負荷高いため、他のソルバーより遅い
5. 雪・砂シミュレーション(MPM)
5.1 MPMとは?
MPM (Material Point Method) は、雪・砂・粘土など粒状体をシミュレートする手法です。
特徴:
大きな変形に強い
雪の圧縮、砂の崩壊を表現可能
Disney映画「アナと雪の女王」で使用
5.2 MPMシミュレーションコード
"""
Part 3: MPMシミュレーション
雪と砂が落下して変形
"""
import genesis as gs
gs.init(backend=gs.gpu)
# シーン作成(MPMソルバー有効)
scene = gs.Scene(
sim_options=gs.options.SimOptions(
dt=4e-3,
substeps=100, # ★重要:MPMは100以上推奨
),
mpm_options=gs.options.MPMOptions(
grid_density=64, # グリッド密度
),
show_viewer=False,
renderer=gs.renderers.Rasterizer(),
)
# 地面
scene.add_entity(morph=gs.morphs.Plane())
# 雪ブロック
snow = scene.add_entity(
material=gs.materials.MPM.Snow(), # ★MPM雪マテリアル
morph=gs.morphs.Box(
size=(0.3, 0.3, 0.3),
pos=(0, 0, 0.8),
),
surface=gs.surfaces.Default(
color=(0.95, 0.95, 1.0, 1.0), # 白
vis_mode='particle',
)
)
# 砂ブロック
sand = scene.add_entity(
material=gs.materials.MPM.Sand(), # ★MPM砂マテリアル
morph=gs.morphs.Box(
size=(0.2, 0.2, 0.2),
pos=(0.5, 0, 0.6),
),
surface=gs.surfaces.Default(
color=(0.9, 0.8, 0.5, 1.0), # 黄色
vis_mode='particle',
)
)
# カメラ
cam = scene.add_camera(
res=(1280, 720),
pos=(2.5, -2.5, 1.5),
lookat=(0.2, 0, 0.3),
fov=50,
GUI=False,
)
# ビルド
scene.build()
# シミュレーション実行
cam.start_recording()
for i in range(800):
scene.step()
cam.render()
cam.stop_recording(save_to_filename="snow_sand.mp4", fps=60)
print("✅ 完了: snow_sand.mp4")

5.3 ⚠️ 重要な発見:substepsの設定

教訓:MPMは高いsubsteps値が必要!
6. 統合シミュレーション
6.1 複数ソルバーの同時使用
布(PBD)+ 液体(SPH)+ 雪(MPM)を同時にシミュレート。
"""
Part 4: 統合シミュレーション
布・液体・雪を同時にシミュレート
"""
import genesis as gs
gs.init(backend=gs.gpu)
# 全ソルバーを有効化
scene = gs.Scene(
sim_options=gs.options.SimOptions(
dt=4e-3,
substeps=100,
),
pbd_options=gs.options.PBDOptions(),
sph_options=gs.options.SPHOptions(
lower_bound=(-1.5, -1.5, 0.0),
upper_bound=(1.5, 1.5, 2.0),
particle_size=0.02,
),
mpm_options=gs.options.MPMOptions(
grid_density=64,
),
show_viewer=False,
renderer=gs.renderers.Rasterizer(),
)
# 地面
scene.add_entity(morph=gs.morphs.Plane())
# 布(PBD)
cloth = scene.add_entity(
material=gs.materials.PBD.Cloth(),
morph=gs.morphs.Mesh(
file='meshes/cloth.obj',
scale=0.8,
pos=(0, 0, 0.4),
),
surface=gs.surfaces.Default(
color=(0.2, 0.4, 0.8, 1.0),
vis_mode='particle',
)
)
# 水(SPH)
water = scene.add_entity(
material=gs.materials.SPH.Liquid(),
morph=gs.morphs.Box(
size=(0.15, 0.15, 0.15),
pos=(0, 0, 0.9),
),
surface=gs.surfaces.Default(
color=(0.3, 0.5, 0.9, 0.8),
vis_mode='particle',
)
)
# 雪(MPM)
snow = scene.add_entity(
material=gs.materials.MPM.Snow(),
morph=gs.morphs.Box(
size=(0.15, 0.15, 0.15),
pos=(0.3, 0.3, 0.8),
),
surface=gs.surfaces.Default(
color=(0.95, 0.95, 1.0, 1.0),
vis_mode='particle',
)
)
# 2つのカメラ(斜めと真上)
cam1 = scene.add_camera(res=(1280, 720), pos=(3, -3, 2), lookat=(0, 0, 0.3), fov=45, GUI=False)
cam2 = scene.add_camera(res=(1280, 720), pos=(0, 0, 3), lookat=(0, 0, 0.3), fov=60, GUI=False)
# ビルド
scene.build()
# 布の4角を固定
corners = [(-0.4, -0.4, 0.4), (0.4, 0.4, 0.4), (-0.4, 0.4, 0.4), (0.4, -0.4, 0.4)]
particle_indices = [cloth.find_closest_particle(c) for c in corners]
cloth.fix_particles(particle_indices)
# シミュレーション実行(2カメラ同時録画)
cam1.start_recording()
cam2.start_recording()
for i in range(1000):
scene.step()
cam1.render()
cam2.render()
cam1.stop_recording(save_to_filename="combined_side.mp4", fps=60)
cam2.stop_recording(save_to_filename="combined_top.mp4", fps=60)
print("✅ 完了!")

6.2 ⚠️ 発見された制限

原因: GenesisのPBD-SPH間の衝突検出が完全にはサポートされていない可能性
7. トラブルシューティング
7.1 よくあるエラーと解決策

7.2 API変更への対応(Genesis 0.3.7)
# ❌ 旧API(エラーになる)
cloth.fix_particle(idx)
# ✅ 新API(正しい)
cloth.fix_particles([idx]) # リストで渡す
8. 得られた知見とベストプラクティス
8.1 ソルバー別推奨設定

8.2 パフォーマンス最適化
粒子数を減らす: particle_size を大きく
解像度を下げる: res=(640, 360) など
substepsを調整: 最小限で安定する値を探す
ステップ数を減らす: 必要な動きが見えたら終了
8.3 録画のベストプラクティス
# 複数カメラで同時録画
cam1.start_recording()
cam2.start_recording()
for i in range(steps):
scene.step()
cam1.render() # 両方レンダリング
cam2.render()
cam1.stop_recording(save_to_filename="view1.mp4", fps=60)
cam2.stop_recording(save_to_filename="view2.mp4", fps=60)
8.4 表示モードの違い

8.5 ソルバー間の相互作用(制限事項)
実験から判明した重要な制限:

📝 まとめ
学んだこと
ヘッドレス環境ではEGL設定が必須
ソルバー選択は用途に合わせて(PBD/SPH/MPM)
MPMは高いsubsteps(100以上)が必要
API変更に注意(fix_particle → fix_particles)
ソルバー間の相互作用には制限がある
次のステップ
ロボットアームの追加
URDFモデルの読み込み
強化学習との連携
📚 参考リンク
このチュートリアルは、2025年11月の実験に基づいています。 Genesis バージョン: 0.3.7
