|
1 | 1 | import math |
2 | 2 | import os |
| 3 | +import queue |
3 | 4 | import sys |
4 | 5 | import xml.etree.ElementTree as ET |
5 | 6 |
|
@@ -1034,6 +1035,183 @@ def test_batched_offscreen_rendering(show_viewer, tol): |
1034 | 1035 | assert_allclose(steps_rgb_arrays[0][i], steps_rgb_arrays[1][i], tol=tol) |
1035 | 1036 |
|
1036 | 1037 |
|
| 1038 | +@pytest.mark.required |
| 1039 | +@pytest.mark.skipif(sys.platform == "darwin", reason="Segfault inside 'shadow_mapping_pass' on MacOS VM.") |
| 1040 | +@pytest.mark.xfail(reason="This test is not passing on all platforms for now.") |
| 1041 | +def test_batched_mounted_camera_rendering(show_viewer, tol): |
| 1042 | + scene = gs.Scene( |
| 1043 | + vis_options=gs.options.VisOptions( |
| 1044 | + env_separate_rigid=False, |
| 1045 | + ), |
| 1046 | + show_viewer=show_viewer, |
| 1047 | + show_FPS=False, |
| 1048 | + ) |
| 1049 | + plane = scene.add_entity( |
| 1050 | + morph=gs.morphs.Plane(), |
| 1051 | + surface=gs.surfaces.Aluminium( |
| 1052 | + ior=10.0, |
| 1053 | + ), |
| 1054 | + ) |
| 1055 | + scene.add_entity( |
| 1056 | + morph=gs.morphs.Mesh( |
| 1057 | + file="meshes/sphere.obj", |
| 1058 | + scale=0.1, |
| 1059 | + pos=(-0.2, -0.8, 0.2), |
| 1060 | + fixed=True, |
| 1061 | + ), |
| 1062 | + surface=gs.surfaces.Rough( |
| 1063 | + diffuse_texture=gs.textures.ColorTexture( |
| 1064 | + color=(1.0, 0.5, 0.5), |
| 1065 | + ), |
| 1066 | + ), |
| 1067 | + ) |
| 1068 | + scene.add_entity( |
| 1069 | + morph=gs.morphs.Mesh( |
| 1070 | + file="meshes/sphere.obj", |
| 1071 | + scale=0.1, |
| 1072 | + pos=(-0.2, -0.5, 0.2), |
| 1073 | + fixed=True, |
| 1074 | + ), |
| 1075 | + surface=gs.surfaces.Rough( |
| 1076 | + color=(1.0, 1.0, 1.0), |
| 1077 | + ), |
| 1078 | + ) |
| 1079 | + scene.add_entity( |
| 1080 | + morph=gs.morphs.Mesh( |
| 1081 | + file="meshes/sphere.obj", |
| 1082 | + scale=0.1, |
| 1083 | + pos=(-0.2, -0.2, 0.2), |
| 1084 | + fixed=True, |
| 1085 | + ), |
| 1086 | + surface=gs.surfaces.Smooth( |
| 1087 | + color=(0.6, 0.8, 1.0), |
| 1088 | + ), |
| 1089 | + ) |
| 1090 | + scene.add_entity( |
| 1091 | + morph=gs.morphs.Mesh( |
| 1092 | + file="meshes/sphere.obj", |
| 1093 | + scale=0.1, |
| 1094 | + pos=(-0.2, 0.2, 0.2), |
| 1095 | + fixed=True, |
| 1096 | + ), |
| 1097 | + surface=gs.surfaces.Iron( |
| 1098 | + color=(1.0, 1.0, 1.0), |
| 1099 | + ), |
| 1100 | + ) |
| 1101 | + scene.add_entity( |
| 1102 | + morph=gs.morphs.Mesh( |
| 1103 | + file="meshes/sphere.obj", |
| 1104 | + scale=0.1, |
| 1105 | + pos=(-0.2, 0.5, 0.2), |
| 1106 | + fixed=True, |
| 1107 | + ), |
| 1108 | + surface=gs.surfaces.Gold( |
| 1109 | + color=(1.0, 1.0, 1.0), |
| 1110 | + ), |
| 1111 | + ) |
| 1112 | + scene.add_entity( |
| 1113 | + morph=gs.morphs.Mesh( |
| 1114 | + file="meshes/sphere.obj", |
| 1115 | + scale=0.1, |
| 1116 | + pos=(-0.2, 0.8, 0.2), |
| 1117 | + fixed=True, |
| 1118 | + ), |
| 1119 | + surface=gs.surfaces.Glass( |
| 1120 | + color=(1.0, 1.0, 1.0), |
| 1121 | + ), |
| 1122 | + ) |
| 1123 | + scene.add_entity( |
| 1124 | + morph=gs.morphs.Mesh( |
| 1125 | + file="meshes/sphere.obj", |
| 1126 | + scale=0.1, |
| 1127 | + pos=(0.2, -0.8, 0.2), |
| 1128 | + fixed=True, |
| 1129 | + ), |
| 1130 | + surface=gs.surfaces.Smooth( |
| 1131 | + color=(1.0, 1.0, 1.0, 0.5), |
| 1132 | + ), |
| 1133 | + ) |
| 1134 | + scene.add_entity( |
| 1135 | + morph=gs.morphs.Mesh( |
| 1136 | + file="meshes/wooden_sphere_OBJ/wooden_sphere.obj", |
| 1137 | + scale=0.025, |
| 1138 | + pos=(0.2, -0.5, 0.2), |
| 1139 | + fixed=True, |
| 1140 | + ), |
| 1141 | + ) |
| 1142 | + scene.add_entity( |
| 1143 | + morph=gs.morphs.Mesh( |
| 1144 | + file="meshes/wooden_sphere_OBJ/wooden_sphere.obj", |
| 1145 | + scale=0.025, |
| 1146 | + pos=(0.2, -0.2, 0.2), |
| 1147 | + fixed=True, |
| 1148 | + ), |
| 1149 | + surface=gs.surfaces.Rough( |
| 1150 | + diffuse_texture=gs.textures.ImageTexture( |
| 1151 | + image_path="textures/checker.png", |
| 1152 | + ) |
| 1153 | + ), |
| 1154 | + ) |
| 1155 | + robot = scene.add_entity( |
| 1156 | + gs.morphs.MJCF(file="xml/franka_emika_panda/panda.xml"), |
| 1157 | + ) |
| 1158 | + n_envs = 3 |
| 1159 | + env_spacing = (2.0, 2.0) |
| 1160 | + cams = [scene.add_camera(GUI=show_viewer, fov=70) for _ in range(n_envs)] |
| 1161 | + scene.build(n_envs=n_envs, env_spacing=env_spacing) |
| 1162 | + |
| 1163 | + T = np.eye(4) |
| 1164 | + T[:3, :3] = np.array([[1, 0, 0], [0, -1, 0], [0, 0, -1]]) |
| 1165 | + T[:3, 3] = np.array([0.1, 0.0, 0.1]) |
| 1166 | + for nenv, cam in enumerate(cams): |
| 1167 | + cam.attach(robot.get_link("hand"), T, nenv) |
| 1168 | + |
| 1169 | + target_quat = np.tile(np.array([0, 1, 0, 0]), [n_envs, 1]) # pointing downwards |
| 1170 | + center = np.tile(np.array([-0.25, -0.25, 0.5]), [n_envs, 1]) |
| 1171 | + rng = np.random.default_rng(42) |
| 1172 | + angular_speed = rng.uniform(-10, 10, n_envs) |
| 1173 | + r = 0.25 |
| 1174 | + |
| 1175 | + ee_link = robot.get_link("hand") |
| 1176 | + |
| 1177 | + steps_rgb_queue: queue.Queue[list[np.ndarray]] = queue.Queue(maxsize=2) |
| 1178 | + |
| 1179 | + for i in range(50): |
| 1180 | + target_pos = np.zeros([n_envs, 3]) |
| 1181 | + target_pos[:, 0] = center[:, 0] + np.cos(i / 360 * np.pi * angular_speed) * r |
| 1182 | + target_pos[:, 1] = center[:, 1] + np.sin(i / 360 * np.pi * angular_speed) * r |
| 1183 | + target_pos[:, 2] = center[:, 2] |
| 1184 | + |
| 1185 | + q = robot.inverse_kinematics( |
| 1186 | + link=ee_link, |
| 1187 | + pos=target_pos, |
| 1188 | + quat=target_quat, |
| 1189 | + rot_mask=[False, False, True], # for demo purpose: only restrict direction of z-axis |
| 1190 | + ) |
| 1191 | + |
| 1192 | + robot.set_qpos(q) |
| 1193 | + scene.step() |
| 1194 | + if i < 10: |
| 1195 | + # skip the first few frames because the robots start off with the same state |
| 1196 | + for cam in cams: |
| 1197 | + cam.render() |
| 1198 | + continue |
| 1199 | + robots_rgb_arrays = [] |
| 1200 | + for cam in cams: |
| 1201 | + rgb_array, *_ = cam.render() |
| 1202 | + assert np.std(rgb_array) > 10.0 |
| 1203 | + robots_rgb_arrays.append(rgb_array) |
| 1204 | + steps_rgb_queue.put(robots_rgb_arrays) |
| 1205 | + |
| 1206 | + if steps_rgb_queue.full(): # we have a set of 2 consecutive frames |
| 1207 | + diff_tol = 0.05 # expect atlest 5% difference between each frame |
| 1208 | + frames_t_minus_1 = steps_rgb_queue.get() |
| 1209 | + frames_t = steps_rgb_queue.get() |
| 1210 | + for i in range(n_envs): |
| 1211 | + diff = frames_t[i] - frames_t_minus_1[i] |
| 1212 | + assert np.count_nonzero(diff) > diff_tol * np.prod(diff.shape) |
| 1213 | + |
| 1214 | + |
1037 | 1215 | @pytest.mark.required |
1038 | 1216 | @pytest.mark.parametrize("backend", [gs.cpu]) |
1039 | 1217 | def test_pd_control(show_viewer): |
|
0 commit comments