Skip to content

Commit 17e511c

Browse files
committed
Merge branch 'main' of https://github.com/ACMLCZH/Genesis
2 parents 8d07248 + 0d8b55b commit 17e511c

File tree

120 files changed

+17791
-5462
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+17791
-5462
lines changed

.github/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Thank you for your interest in contributing to Genesis! We welcome contributions
6161
- (Optional) You can run CI tests locally to ensure you pass the online CI checks.
6262

6363
```python
64-
python -m unittest discover tests
64+
pytest -v --forked -m required ./tests
6565
```
6666

6767
- In the title of your Pull Request, please include [BUG FIX], [FEATURE] or [MISC] to indicate the purpose.
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
name: Generic - CPU only
1+
name: Generic
22

33
on:
44
pull_request:
55
branches:
66
- main
77

8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
10+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
11+
812
jobs:
913
generic-cpu:
1014
strategy:
@@ -52,13 +56,11 @@ jobs:
5256
shell: bash
5357
run: |
5458
# FIXME: Updating to 25.1.0 breaks rendering regardless PYOPENGL_PLATFORM is set to osmesa or egl.
55-
curl -L -o mesa.7z https://github.com/pal1000/mesa-dist-win/releases/download/24.3.4/mesa3d-24.3.4-release-msvc.7z
59+
curl -L -o mesa.7z https://github.com/pal1000/mesa-dist-win/releases/download/23.3.3/mesa3d-23.3.3-release-msvc.7z
5660
7z x mesa.7z -omesa
5761
mv -v mesa/x64/* /C/Windows/System32/
5862
ls -alt /C/Windows/System32/opengl32.dll
5963
60-
echo "PYOPENGL_PLATFORM=osmesa" >> $GITHUB_ENV
61-
6264
- name: Install system dependencies (Linux)
6365
if: startsWith(matrix.OS, 'ubuntu-')
6466
run: |
Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Linux x86 - Nvidia GPU
1+
name: Production
22

33
on:
44
# Trigger the workflow on push on the master branch, or for any pull request
@@ -7,6 +7,12 @@ on:
77
- main
88
pull_request:
99

10+
concurrency:
11+
# Cancel all workflows that are stil running if any when updating branches associated with PRs,
12+
# BUT don't do anything for workflows that are not triggered by PRs.
13+
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
14+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
15+
1016
jobs:
1117
linux-gpu:
1218
runs-on: [self-hosted, coreweave]
@@ -35,6 +41,12 @@ jobs:
3541
3642
mkdir -p "${HOME}/.cache"
3743
44+
# Prefer idle nodes if any
45+
IDLE_NODES=$(sinfo -h -o "%N %t" | awk '$2 == "idle" {print $1}')
46+
if [[ -n "$IDLE_NODES" ]]; then
47+
NODELIST="--nodelist=$IDLE_NODES"
48+
fi
49+
3850
srun \
3951
--container-image="/mnt/data/images/genesis-v${GENESIS_IMAGE_VER}.sqsh" \
4052
--container-mounts=\
@@ -44,7 +56,7 @@ jobs:
4456
--export=\
4557
HF_TOKEN="${HF_TOKEN}",\
4658
NVIDIA_DRIVER_CAPABILITIES=all \
47-
--partition=hpc-mid --nodes=1 --gpus=1 --time="${TIMEOUT_MINUTES}" \
59+
--partition=hpc-mid ${NODELIST} --nodes=1 --time="${TIMEOUT_MINUTES}" \
4860
--job-name=${SLURM_JOB_NAME} \
4961
bash -c "
5062
pip install -e '.[dev,render]' && \
@@ -69,16 +81,16 @@ jobs:
6981
"${{ github.workspace }}":/root/workspace \
7082
--no-container-mount-home --container-workdir=/root/workspace \
7183
--export=${SLURM_ENV_VARS} \
72-
--partition=hpc-mid --exclusive --nodes=1 --gpus=1 --time="${TIMEOUT_MINUTES}" \
84+
--partition=hpc-mid --exclusive --nodes=1 --time="${TIMEOUT_MINUTES}" \
7385
--job-name=${SLURM_JOB_NAME} \
7486
bash -c "
7587
: # sudo apt install -y tmate && \
7688
tmate -S /tmp/tmate.sock new-session -d && \
7789
tmate -S /tmp/tmate.sock wait tmate-ready && \
7890
tmate -S /tmp/tmate.sock display -p '#{tmate_ssh}'
7991
pip install -e '.[dev,render]' && \
80-
pytest --print -x -m 'benchmarks' --backend gpu ./tests && \
81-
cp 'speed_test.txt' '/mnt/data/artifacts/speed_test_${SLURM_JOB_NAME}.txt'
92+
pytest --print -x -m 'benchmarks' ./tests && \
93+
cat speed_test*.txt > '/mnt/data/artifacts/speed_test_${SLURM_JOB_NAME}.txt'
8294
: # tmate -S /tmp/tmate.sock wait tmate-exit
8395
"
8496

.pre-commit-config.yaml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
repos:
22
- repo: https://github.com/psf/black
3-
rev: 25.1.0 # Use the latest version or specify the version you prefer
3+
rev: 25.1.0
44
hooks:
55
- id: black
6-
args:
7-
- --line-length=120
8-
- .

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# Genesis
1919

2020
## 🔥 News
21+
- [2025-07-02] The development of Genesis is now officially supported by [Genesis AI](https://genesis-ai.company/).
2122
- [2025-01-09] We released a [detailed performance benchmarking and comparison report](https://github.com/zhouxian/genesis-speed-benchmark) on Genesis, together with all the test scripts.
2223
- [2025-01-08] Released v0.2.1 🎊 🎉
2324
- [2025-01-08] Created [Discord](https://discord.gg/nukCuhB47p) and [Wechat](https://drive.google.com/uc?export=view&id=1ZS9nnbQ-t1IwkzJlENBYqYIIOOZhXuBZ) group.
@@ -113,6 +114,31 @@ docker run --gpus all --rm -it \
113114
genesis
114115
```
115116

117+
### AMD users
118+
AMD users can use Genesis using the `docker/Dockerfile.amdgpu` file, which is built by running:
119+
```
120+
docker build -t genesis-amd -f docker/Dockerfile.amdgpu docker
121+
```
122+
123+
and can then be used by running:
124+
125+
```xhost +local:docker \
126+
docker run -it --network=host \
127+
--device=/dev/kfd \
128+
--device=/dev/dri \
129+
--group-add=video \
130+
--ipc=host \
131+
--cap-add=SYS_PTRACE \
132+
--security-opt seccomp=unconfined \
133+
--shm-size 8G \
134+
-v $PWD:/workspace \
135+
-e DISPLAY=$DISPLAY \
136+
genesis-amd
137+
```
138+
139+
The examples will be accessible from `/workspace/examples`. Note: AMD users should use the vulkan backend. This means you will need to call `gs.init(vulkan)` to initialise Genesis.
140+
141+
116142
## Documentation
117143

118144
Comprehensive documentation is available in [English](https://genesis-world.readthedocs.io/en/latest/user_guide/index.html), [Chinese](https://genesis-world.readthedocs.io/zh-cn/latest/user_guide/index.html), and [Japanese](https://genesis-world.readthedocs.io/ja/latest/user_guide/index.html). This includes detailed installation steps, tutorials, and API references.

docker/Dockerfile.amdgpu

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#FROM rocm/pytorch:rocm6.4.1_ubuntu22.04_py3.10_pytorch_release_2.4.1
2+
FROM rocm/pytorch:rocm6.4.1_ubuntu22.04_py3.10_pytorch_release_2.6.0
3+
4+
ENV DEBIAN_FRONTEND=noninteractive
5+
6+
WORKDIR /workspace/examples
7+
8+
# Install Vulkan
9+
RUN wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc | tee /etc/apt/trusted.gpg.d/lunarg.asc
10+
RUN wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.4.309-jammy.list https://packages.lunarg.com/vulkan/1.4.309/lunarg-vulkan-1.4.309-jammy.list
11+
RUN apt update
12+
RUN apt install -y vulkan-sdk
13+
14+
# handle add the render group
15+
RUN groupadd -f render
16+
RUN usermod -aG render root
17+
RUN usermod -aG video root
18+
19+
# Necessary for visualisation on Wayland backed systems like Ubuntu
20+
ENV PYOPENGL_PLATFORM='glx'
21+
22+
# Install Genesis verified against 0.2.1
23+
RUN pip3 install genesis-world trimesh
24+
25+
# Workaround for igl issue
26+
RUN pip3 install libigl==2.5.1

examples/collision/pyramid.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import numpy as np
2+
import genesis as gs
3+
import argparse
4+
5+
pile_type = "static"
6+
num_cubes = 5
7+
8+
parser = argparse.ArgumentParser()
9+
parser.add_argument("--pile_type", type=str, default=pile_type, choices=["static", "falling"])
10+
parser.add_argument("--num_cubes", type=int, default=num_cubes, choices=range(5, 11))
11+
parser.add_argument("--cpu", action="store_true", help="Use CPU backend instead of GPU")
12+
args = parser.parse_args()
13+
14+
pile_type = args.pile_type
15+
num_cubes = args.num_cubes
16+
cpu = args.cpu
17+
backend = gs.cpu if cpu else gs.gpu
18+
19+
gs.init(backend=backend, precision="32")
20+
21+
scene = gs.Scene(
22+
sim_options=gs.options.SimOptions(
23+
dt=0.01,
24+
),
25+
rigid_options=gs.options.RigidOptions(
26+
box_box_detection=False,
27+
max_collision_pairs=1000,
28+
use_gjk_collision=True,
29+
enable_mujoco_compatibility=False,
30+
),
31+
viewer_options=gs.options.ViewerOptions(
32+
camera_pos=(0, -5.5, 2.5),
33+
camera_lookat=(0, 0.0, 1.5),
34+
camera_fov=30,
35+
max_FPS=60,
36+
),
37+
show_viewer=True,
38+
)
39+
40+
plane = scene.add_entity(gs.morphs.Plane(pos=(0, 0, 0)))
41+
42+
# create pyramid of boxes
43+
box_size = 0.25
44+
if pile_type == "static":
45+
box_spacing = box_size
46+
else:
47+
box_spacing = 1.1 * box_size
48+
vec_one = np.array([1.0, 1.0, 1.0])
49+
box_pos_offset = (0 - 0.5, 1, 0.0) + 0.5 * box_size * vec_one
50+
boxes = {}
51+
for i in range(num_cubes):
52+
for j in range(num_cubes - i):
53+
box = scene.add_entity(
54+
gs.morphs.Box(size=box_size * vec_one, pos=box_pos_offset + box_spacing * np.array([i + 0.5 * j, 0, j])),
55+
)
56+
57+
scene.build()
58+
59+
for i in range(1000):
60+
scene.step()

examples/collision/tower.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import numpy as np
2+
import genesis as gs
3+
import argparse
4+
5+
object_type = "cylinder"
6+
7+
parser = argparse.ArgumentParser()
8+
parser.add_argument(
9+
"--object",
10+
type=str,
11+
default=object_type,
12+
choices=["sphere", "cylinder", "duck"],
13+
)
14+
args = parser.parse_args()
15+
object_type = args.object
16+
17+
gs.init(backend=gs.cpu, precision="32")
18+
19+
scene = gs.Scene(
20+
sim_options=gs.options.SimOptions(
21+
dt=0.005,
22+
),
23+
rigid_options=gs.options.RigidOptions(
24+
box_box_detection=False,
25+
max_collision_pairs=2000,
26+
use_gjk_collision=True,
27+
enable_mujoco_compatibility=False,
28+
),
29+
viewer_options=gs.options.ViewerOptions(
30+
camera_pos=(20, -20, 20),
31+
camera_lookat=(0.0, 0.0, 5.0),
32+
camera_fov=30,
33+
max_FPS=60,
34+
),
35+
show_viewer=True,
36+
)
37+
38+
plane = scene.add_entity(gs.morphs.Plane(pos=(0, 0, 0)))
39+
40+
# create pyramid of boxes
41+
box_width = 0.25
42+
box_length = 2.0
43+
box_height = 0.1
44+
num_stacks = 50
45+
height_offset = 0.0
46+
for i in range(num_stacks):
47+
horizontal = i % 2 == 0
48+
49+
if horizontal:
50+
box_size = np.array([box_width, box_length, box_height])
51+
box_pos_0 = (-0.4 * box_length, 0, i * (height_offset + box_size[2]) + 0.5 * box_size[2])
52+
box_pos_1 = (+0.4 * box_length, 0, i * (height_offset + box_size[2]) + 0.5 * box_size[2])
53+
else:
54+
box_size = np.array([box_length, box_width, box_height])
55+
box_pos_0 = (0, -0.4 * box_length, i * (height_offset + box_size[2]) + 0.5 * box_size[2])
56+
box_pos_1 = (0, +0.4 * box_length, i * (height_offset + box_size[2]) + 0.5 * box_size[2])
57+
58+
scene.add_entity(
59+
gs.morphs.Box(size=box_size, pos=box_pos_0),
60+
)
61+
scene.add_entity(
62+
gs.morphs.Box(size=box_size, pos=box_pos_1),
63+
)
64+
65+
# Drop a huge mesh
66+
if object_type == "duck":
67+
duck_scale = 1.0
68+
duck = scene.add_entity(
69+
morph=gs.morphs.Mesh(
70+
file="meshes/duck.obj",
71+
scale=duck_scale,
72+
pos=(0, 0, num_stacks * (height_offset + box_height) + 10 * duck_scale),
73+
),
74+
)
75+
elif object_type == "sphere":
76+
sphere_radius = 2.0
77+
scene.add_entity(
78+
morph=gs.morphs.Sphere(
79+
radius=sphere_radius, pos=(0.0, 0.0, num_stacks * (height_offset + box_height) + 5 * sphere_radius)
80+
),
81+
)
82+
elif object_type == "cylinder":
83+
cylinder_radius = 2.0
84+
cylinder_height = 1.0
85+
scene.add_entity(
86+
morph=gs.morphs.Cylinder(
87+
radius=cylinder_radius,
88+
height=cylinder_height,
89+
pos=(0.0, 0.0, num_stacks * (height_offset + box_height) + 5 * cylinder_height),
90+
),
91+
)
92+
93+
scene.build()
94+
for i in range(5000):
95+
scene.step()

examples/drone/hover_env.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import torch
22
import math
3+
import copy
34
import genesis as gs
45
from genesis.utils.geom import quat_to_xyz, transform_by_quat, inv_quat, transform_quat_by_quat
56

@@ -28,7 +29,7 @@ def __init__(self, num_envs, env_cfg, obs_cfg, reward_cfg, command_cfg, show_vie
2829
self.command_cfg = command_cfg
2930

3031
self.obs_scales = obs_cfg["obs_scales"]
31-
self.reward_scales = reward_cfg["reward_scales"]
32+
self.reward_scales = copy.deepcopy(reward_cfg["reward_scales"])
3233

3334
# create scene
3435
self.scene = gs.Scene(
@@ -121,10 +122,11 @@ def _resample_commands(self, envs_idx):
121122
self.commands[envs_idx, 2] = gs_rand_float(*self.command_cfg["pos_z_range"], (len(envs_idx),), gs.device)
122123

123124
def _at_target(self):
124-
at_target = (
125-
(torch.norm(self.rel_pos, dim=1) < self.env_cfg["at_target_threshold"]).nonzero(as_tuple=False).flatten()
125+
return (
126+
(torch.norm(self.rel_pos, dim=1) < self.env_cfg["at_target_threshold"])
127+
.nonzero(as_tuple=False)
128+
.reshape((-1,))
126129
)
127-
return at_target
128130

129131
def step(self, actions):
130132
self.actions = torch.clip(actions, -self.env_cfg["clip_actions"], self.env_cfg["clip_actions"])
@@ -134,7 +136,7 @@ def step(self, actions):
134136
self.drone.set_propellels_rpm((1 + exec_actions * 0.8) * 14468.429183500699)
135137
# update target pos
136138
if self.target is not None:
137-
self.target.set_pos(self.commands, zero_velocity=True, envs_idx=list(range(self.num_envs)))
139+
self.target.set_pos(self.commands, zero_velocity=True)
138140
self.scene.step()
139141

140142
# update buffers
@@ -168,11 +170,11 @@ def step(self, actions):
168170
)
169171
self.reset_buf = (self.episode_length_buf > self.max_episode_length) | self.crash_condition
170172

171-
time_out_idx = (self.episode_length_buf > self.max_episode_length).nonzero(as_tuple=False).flatten()
173+
time_out_idx = (self.episode_length_buf > self.max_episode_length).nonzero(as_tuple=False).reshape((-1,))
172174
self.extras["time_outs"] = torch.zeros_like(self.reset_buf, device=gs.device, dtype=gs.tc_float)
173175
self.extras["time_outs"][time_out_idx] = 1.0
174176

175-
self.reset_idx(self.reset_buf.nonzero(as_tuple=False).flatten())
177+
self.reset_idx(self.reset_buf.nonzero(as_tuple=False).reshape((-1,)))
176178

177179
# compute reward
178180
self.rew_buf[:] = 0.0

0 commit comments

Comments
 (0)