Skip to content

Commit a6fd2d5

Browse files
committed
Add support for CompoundMesh to tesseract_viewer_python
1 parent 2c43395 commit a6fd2d5

File tree

1 file changed

+139
-107
lines changed

1 file changed

+139
-107
lines changed

tesseract_viewer_python/tesseract_robotics_viewer/tesseract_env_to_gltf.py

Lines changed: 139 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def _append_link_recursive(gltf_dict, gltf_buf_io, link_map, joint_map, link_nam
164164
for visual in link.visual:
165165
visual_i += 1
166166
_, visual_ind = _append_link_visual(gltf_dict, gltf_buf_io, link_name, visual, visual_i, shapes_mesh_inds)
167-
child_inds.append(visual_ind)
167+
child_inds.extend(visual_ind)
168168

169169
child_joints = _find_child_joints(joint_map, link_name)
170170
for j in child_joints:
@@ -182,121 +182,100 @@ def _append_link_recursive(gltf_dict, gltf_buf_io, link_map, joint_map, link_nam
182182

183183
return link_node, link_ind
184184

185-
def _append_link_visual(gltf_dict, gltf_buf_io, link_name, visual, visual_i, shapes_mesh_inds):
186-
187-
visual_u_name = visual.name + str(visual_i)
188-
visual_name = "link_" + link_name + "_visual_" + visual_u_name
189-
visual_node, visual_ind = _append_node(gltf_dict, visual.origin, visual_name)
190-
185+
def _convert_mesh(gltf_dict, gltf_buf_io, visual_node, visual_name, mesh):
191186
tf_material = None
192-
193-
visual_geom = visual.geometry
194-
if (isinstance(visual_geom,tesseract_geometry.PolygonMesh)):
187+
vertices = mesh.getVertices()
188+
positions = np.zeros((len(vertices),3),dtype=np.float32)
189+
for i in range(len(vertices)):
190+
positions[i,:] = vertices[i].flatten()
195191

196-
mesh=visual_geom
197-
vertices = mesh.getVertices()
198-
positions = np.zeros((len(vertices),3),dtype=np.float32)
199-
for i in range(len(vertices)):
200-
positions[i,:] = vertices[i].flatten()
201-
202-
indices = mesh.getFaces().flatten().astype(np.uint32).reshape((-1,4))[:,1:4].flatten()
203-
204-
_, positions_ind = _append_accessor(gltf_dict, gltf_buf_io, positions)
205-
_, indices_ind = _append_accessor(gltf_dict, gltf_buf_io, indices)
206-
207-
normals_ind = None
208-
normals = mesh.getNormals()
209-
if normals is not None:
210-
normals2 = np.zeros((len(normals),3),dtype=np.float32)
211-
for i in range(len(normals)):
212-
normals2[i,:] = normals[i].flatten()
213-
_, normals_ind = _append_accessor(gltf_dict, gltf_buf_io, normals2)
214-
215-
mesh_dict, mesh_ind = _append_dict_list(gltf_dict, "meshes", {
216-
"primitives": [
217-
{
218-
"attributes": {
219-
"POSITION": positions_ind
220-
},
221-
"indices": indices_ind
222-
}
223-
],
224-
"name": visual_name + "_mesh"
225-
})
192+
indices = mesh.getFaces().flatten().astype(np.uint32).reshape((-1,4))[:,1:4].flatten()
193+
194+
_, positions_ind = _append_accessor(gltf_dict, gltf_buf_io, positions)
195+
_, indices_ind = _append_accessor(gltf_dict, gltf_buf_io, indices)
196+
197+
normals_ind = None
198+
normals = mesh.getNormals()
199+
if normals is not None:
200+
normals2 = np.zeros((len(normals),3),dtype=np.float32)
201+
for i in range(len(normals)):
202+
normals2[i,:] = normals[i].flatten()
203+
_, normals_ind = _append_accessor(gltf_dict, gltf_buf_io, normals2)
204+
205+
mesh_dict, mesh_ind = _append_dict_list(gltf_dict, "meshes", {
206+
"primitives": [
207+
{
208+
"attributes": {
209+
"POSITION": positions_ind
210+
},
211+
"indices": indices_ind
212+
}
213+
],
214+
"name": visual_name + "_mesh"
215+
})
226216

227-
# if normals_ind is not None:
228-
# mesh_dict["primitives"][0]["attributes"]["NORMAL"] = normals_ind
217+
# if normals_ind is not None:
218+
# mesh_dict["primitives"][0]["attributes"]["NORMAL"] = normals_ind
229219

230-
visual_node["scale"] = list(mesh.getScale().flatten())
220+
visual_node["scale"] = list(mesh.getScale().flatten())
231221

232-
if not mesh.getResource().getUrl().lower().endswith('.stl'):
233-
mesh_material = mesh.getMaterial()
234-
if mesh_material is not None:
222+
if not mesh.getResource().getUrl().lower().endswith('.stl'):
223+
mesh_material = mesh.getMaterial()
224+
if mesh_material is not None:
225+
226+
tf_material = {
227+
"name": "material_" + visual_name,
228+
"alphaMode": "MASK",
229+
"alphaCutoff": 0.4
230+
}
231+
232+
base_color_factor = mesh_material.getBaseColorFactor().flatten().tolist()
235233

236-
tf_material = {
237-
"name": "material_" + visual_name,
238-
"alphaMode": "MASK",
239-
"alphaCutoff": 0.4
240-
}
241-
242-
base_color_factor = mesh_material.getBaseColorFactor().flatten().tolist()
243-
244-
tf_material["pbrMetallicRoughness"] = {
245-
"baseColorFactor": base_color_factor,
246-
"roughnessFactor": mesh_material.getRoughnessFactor(),
247-
"metallicFactor": mesh_material.getMetallicFactor(),
234+
tf_material["pbrMetallicRoughness"] = {
235+
"baseColorFactor": base_color_factor,
236+
"roughnessFactor": mesh_material.getRoughnessFactor(),
237+
"metallicFactor": mesh_material.getMetallicFactor(),
238+
}
239+
240+
mesh_textures = mesh.getTextures()
241+
if mesh_textures is not None and len(mesh_textures) > 0:
242+
mesh_tex = mesh_textures[0]
243+
mesh_tex_image = mesh_tex.getTextureImage()
244+
tex_name = mesh_tex_image.getUrl()
245+
tex_mimetype = "image/jpg"
246+
if tex_name.endswith('png'):
247+
tex_mimetype = "image/png"
248+
249+
mesh_tex_image_bytes = bytearray(mesh_tex_image.getResourceContents())
250+
tex_img = cv2.imdecode(np.frombuffer(mesh_tex_image_bytes,dtype=np.uint8),flags=1)
251+
img_h, img_w, _ = tex_img.shape
252+
_, image_bufview_ind = _append_bufview(gltf_dict, gltf_buf_io, mesh_tex_image_bytes)
253+
_, image_ind = _append_dict_list(gltf_dict, "images", {
254+
"mimeType": tex_mimetype,
255+
"bufferView": image_bufview_ind
256+
})
257+
258+
_, tex_ind = _append_dict_list(gltf_dict, "textures", {
259+
"source": image_ind
260+
})
261+
262+
tf_material["pbrMetallicRoughness"]["baseColorTexture"] = {
263+
"index": tex_ind,
264+
"texCoord": 0
248265
}
249266

250-
mesh_textures = mesh.getTextures()
251-
if mesh_textures is not None and len(mesh_textures) > 0:
252-
mesh_tex = mesh_textures[0]
253-
mesh_tex_image = mesh_tex.getTextureImage()
254-
tex_name = mesh_tex_image.getUrl()
255-
tex_mimetype = "image/jpg"
256-
if tex_name.endswith('png'):
257-
tex_mimetype = "image/png"
258-
259-
mesh_tex_image_bytes = bytearray(mesh_tex_image.getResourceContents())
260-
tex_img = cv2.imdecode(np.frombuffer(mesh_tex_image_bytes,dtype=np.uint8),flags=1)
261-
img_h, img_w, _ = tex_img.shape
262-
_, image_bufview_ind = _append_bufview(gltf_dict, gltf_buf_io, mesh_tex_image_bytes)
263-
_, image_ind = _append_dict_list(gltf_dict, "images", {
264-
"mimeType": tex_mimetype,
265-
"bufferView": image_bufview_ind
266-
})
267-
268-
_, tex_ind = _append_dict_list(gltf_dict, "textures", {
269-
"source": image_ind
270-
})
271-
272-
tf_material["pbrMetallicRoughness"]["baseColorTexture"] = {
273-
"index": tex_ind,
274-
"texCoord": 0
275-
}
276-
277-
mesh_uvs = mesh_tex.getUVs()
278-
tf_uvs = np.zeros((len(mesh_uvs),2),dtype=np.float32)
279-
for i in range(len(mesh_uvs)):
280-
tf_uvs1 = mesh_uvs[i].flatten()
281-
tf_uvs[i,:] = [tf_uvs1[0], 1.0-tf_uvs1[1]]
282-
_, tex_ind = _append_accessor(gltf_dict, gltf_buf_io, tf_uvs)
283-
284-
mesh_dict["primitives"][0]["attributes"]["TEXCOORD_0"] = tex_ind
267+
mesh_uvs = mesh_tex.getUVs()
268+
tf_uvs = np.zeros((len(mesh_uvs),2),dtype=np.float32)
269+
for i in range(len(mesh_uvs)):
270+
tf_uvs1 = mesh_uvs[i].flatten()
271+
tf_uvs[i,:] = [tf_uvs1[0], 1.0-tf_uvs1[1]]
272+
_, tex_ind = _append_accessor(gltf_dict, gltf_buf_io, tf_uvs)
285273

286-
elif (isinstance(visual_geom,tesseract_geometry.Box)):
287-
box=visual_geom
288-
mesh_dict, mesh_ind = _append_shape_mesh(gltf_dict, gltf_buf_io, "cube_geometry", visual_name, shapes_mesh_inds)
289-
visual_node["scale"] = [0.5*box.getX(), 0.5*box.getY(), 0.5*box.getZ()]
274+
mesh_dict["primitives"][0]["attributes"]["TEXCOORD_0"] = tex_ind
290275

291-
elif (isinstance(visual_geom,tesseract_geometry.Sphere)):
292-
sphere=visual_geom
293-
mesh_dict, mesh_ind = _append_shape_mesh(gltf_dict, gltf_buf_io, "sphere_geometry", visual_name, shapes_mesh_inds)
294-
visual_node["scale"] = [sphere.getRadius(), sphere.getRadius(), sphere.getRadius()]
276+
return mesh_dict, mesh_ind, tf_material
295277

296-
elif (isinstance(visual_geom,tesseract_geometry.Cylinder)):
297-
cylinder=visual_geom
298-
mesh_dict, mesh_ind = _append_shape_mesh(gltf_dict, gltf_buf_io, "cylinder_geometry", visual_name, shapes_mesh_inds)
299-
visual_node["scale"] = [cylinder.getRadius(), cylinder.getRadius(), 0.5*cylinder.getLength()]
278+
def _apply_material(gltf_dict, gltf_buf_io, mesh_dict, visual_name, tf_material, visual_material):
300279

301280
if tf_material is None:
302281
tf_material = {
@@ -305,7 +284,7 @@ def _append_link_visual(gltf_dict, gltf_buf_io, link_name, visual, visual_i, sha
305284
"alphaCutoff": 0.4
306285
}
307286

308-
material = visual.material
287+
material = visual_material
309288

310289
if material is None:
311290
tf_color = [0.5,0.5,0.5,1]
@@ -322,10 +301,63 @@ def _append_link_visual(gltf_dict, gltf_buf_io, link_name, visual, visual_i, sha
322301

323302
mesh_dict["primitives"][0]["material"] = material_ind
324303

304+
def _append_link_visual(gltf_dict, gltf_buf_io, link_name, visual, visual_i, shapes_mesh_inds):
305+
306+
visual_geom = visual.geometry
307+
308+
visual_u_name = visual.name + str(visual_i)
309+
visual_name = "link_" + link_name + "_visual_" + visual_u_name
310+
311+
if (isinstance(visual_geom,tesseract_geometry.CompoundMesh)):
312+
meshes = visual_geom.getMeshes()
313+
mesh_count = 0
314+
visual_nodes = []
315+
visual_inds = []
316+
for m in meshes:
317+
visual_name1 = visual_name + "_mesh_" + str(mesh_count)
318+
visual_node1, visual_ind1 = _append_node(gltf_dict, visual.origin, visual_name1)
319+
mesh_dict1, mesh_ind1, tf_material1 = _convert_mesh(gltf_dict, gltf_buf_io, visual_node1, visual_name1, m)
320+
_apply_material(gltf_dict, gltf_buf_io, mesh_dict1, visual_name1, tf_material1, visual.material)
321+
visual_node1["mesh"] = mesh_ind1
322+
visual_nodes.append(visual_node1)
323+
visual_inds.append(visual_ind1)
324+
print(mesh_dict1)
325+
mesh_count += 1
326+
327+
return visual_nodes, visual_inds
328+
329+
visual_node, visual_ind = _append_node(gltf_dict, visual.origin, visual_name)
330+
331+
tf_material = None
332+
333+
if (isinstance(visual_geom,tesseract_geometry.PolygonMesh)):
334+
335+
mesh=visual_geom
336+
337+
mesh_dict, mesh_ind, tf_material = _convert_mesh(gltf_dict, gltf_buf_io, visual_node, visual_name, mesh)
338+
339+
340+
elif (isinstance(visual_geom,tesseract_geometry.Box)):
341+
box=visual_geom
342+
mesh_dict, mesh_ind = _append_shape_mesh(gltf_dict, gltf_buf_io, "cube_geometry", visual_name, shapes_mesh_inds)
343+
visual_node["scale"] = [0.5*box.getX(), 0.5*box.getY(), 0.5*box.getZ()]
344+
345+
elif (isinstance(visual_geom,tesseract_geometry.Sphere)):
346+
sphere=visual_geom
347+
mesh_dict, mesh_ind = _append_shape_mesh(gltf_dict, gltf_buf_io, "sphere_geometry", visual_name, shapes_mesh_inds)
348+
visual_node["scale"] = [sphere.getRadius(), sphere.getRadius(), sphere.getRadius()]
349+
350+
elif (isinstance(visual_geom,tesseract_geometry.Cylinder)):
351+
cylinder=visual_geom
352+
mesh_dict, mesh_ind = _append_shape_mesh(gltf_dict, gltf_buf_io, "cylinder_geometry", visual_name, shapes_mesh_inds)
353+
visual_node["scale"] = [cylinder.getRadius(), cylinder.getRadius(), 0.5*cylinder.getLength()]
354+
355+
_apply_material(gltf_dict, gltf_buf_io, mesh_dict, visual_name, tf_material, visual.material)
356+
325357
visual_node["mesh"] = mesh_ind
326358

327359

328-
return visual_node, visual_ind
360+
return [visual_node], [visual_ind]
329361

330362
_COMPONENT_TYPE_INT8 = 5120
331363
_COMPONENT_TYPE_UINT8 = 5121

0 commit comments

Comments
 (0)