Skip to content

Commit 1c98a33

Browse files
johnwasonLevi-Armstrong
authored andcommitted
Improved mesh parsing to include normals, vertex color, material and texture (#490)
1 parent 433e675 commit 1c98a33

File tree

6 files changed

+154
-15
lines changed

6 files changed

+154
-15
lines changed

tesseract_python/swig/tesseract_common_python.i

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787

8888
%tesseract_aligned_vector(VectorIsometry3d, Eigen::Isometry3d);
8989
%template(VectorVector3d) std::vector<Eigen::Vector3d>;
90+
%tesseract_aligned_vector(VectorVector2d, Eigen::Vector2d);
9091
%tesseract_aligned_vector(VectorVector4d, Eigen::Vector4d);
9192
%tesseract_aligned_map(TransformMap, std::string, Eigen::Isometry3d);
9293

@@ -106,6 +107,7 @@ using name = std::map<Key, Value, std::less<Key>, Eigen::aligned_allocator<std::
106107
namespace tesseract_common
107108
{
108109
%tesseract_aligned_vector_using(VectorIsometry3d, Eigen::Isometry3d);
110+
%tesseract_aligned_vector_using(VectorVector2d, Eigen::Vector2d);
109111
%tesseract_aligned_vector_using(VectorVector4d, Eigen::Vector4d);
110112
%tesseract_aligned_map_using(TransformMap, std::string, Eigen::Isometry3d);
111113
}

tesseract_python/swig/tesseract_geometry_python.i

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,81 @@
4242
#include <tesseract_geometry/mesh_parser.h>
4343
%}
4444

45+
// Define typemaps for types used by Mesh classes
46+
47+
%define %tesseract_vector_eigen_shared_ptr_adaptor(TYPE)
48+
%typemap(in, noblock=0) std::shared_ptr<const TYPE > (void *argp = 0, int res = 0, TYPE* temp1) {
49+
50+
// Override for "in" std::shared_ptr<const TYPE> by value instead of shared_ptr
51+
res = SWIG_ConvertPtr($input, &argp,$descriptor(TYPE*), $disown | %convertptr_flags);
52+
if (!SWIG_IsOK(res)) {
53+
%argument_fail(res, "$type", $symname, $argnum);
54+
}
55+
temp1 = %reinterpret_cast(argp, TYPE*);
56+
57+
$1 = std::make_shared< TYPE >(*temp1);
58+
}
59+
60+
%typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER,noblock=1) std::shared_ptr<const TYPE > {
61+
void *vptr = 0;
62+
int res = SWIG_ConvertPtr($input, &vptr, $descriptor(TYPE&), SWIG_POINTER_NO_NULL);
63+
$1 = SWIG_CheckState(res);
64+
}
65+
66+
%typemap(out) std::shared_ptr<const TYPE> const & {
67+
// Override to return std::shared_ptr<const TYPE> by value instead of shared_ptr
68+
if (!*$1)
69+
{
70+
%set_output(SWIG_Py_Void());
71+
}
72+
else
73+
{
74+
const TYPE& temp_out = **$1;
75+
%set_output(SWIG_NewPointerObj(%new_copy(temp_out,TYPE), $descriptor(TYPE&), SWIG_POINTER_OWN | %newpointer_flags));
76+
}
77+
}
78+
%enddef
79+
80+
%tesseract_vector_eigen_shared_ptr_adaptor(%arg(std::vector< Eigen::Vector2d, Eigen::aligned_allocator<Eigen::Vector2d> >))
81+
%tesseract_vector_eigen_shared_ptr_adaptor(std::vector< Eigen::Vector3d >)
82+
%tesseract_vector_eigen_shared_ptr_adaptor(%arg(std::vector< Eigen::Vector4d, Eigen::aligned_allocator<Eigen::Vector4d> >))
83+
%tesseract_vector_eigen_shared_ptr_adaptor(std::vector< std::shared_ptr<tesseract_geometry::MeshTexture> >)
84+
85+
%define %tesseract_eigen_shared_ptr_adaptor(TYPE)
86+
87+
%typemap(in, fragment="Eigen_Fragments") std::shared_ptr<const TYPE > (TYPE temp)
88+
{
89+
// Override for "in" TYPE by value instead of shared_ptr
90+
if (!ConvertFromNumpyToEigenMatrix< TYPE >(&temp, $input))
91+
SWIG_fail;
92+
$1 = std::make_shared< TYPE >(temp);
93+
}
94+
95+
%typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER,noblock=1) std::shared_ptr<const TYPE >
96+
{
97+
$1 = is_array($input);
98+
}
99+
100+
%typemap(out, fragment="Eigen_Fragments") std::shared_ptr<const TYPE > const & {
101+
102+
// Override to return TYPE by value instead of shared_ptr
103+
if (!*$1)
104+
{
105+
%set_output(SWIG_Py_Void());
106+
}
107+
else
108+
{
109+
TYPE temp_out = **$1;
110+
if (!ConvertFromEigenToNumPyMatrix< TYPE >(&$result, &temp_out))
111+
SWIG_fail;
112+
}
113+
}
114+
%enddef
115+
116+
%tesseract_eigen_shared_ptr_adaptor( Eigen::VectorXi )
117+
118+
119+
45120
// tesseract_geometry
46121
#define TESSERACT_GEOMETRY_PUBLIC
47122
%include "tesseract_geometry/geometry.h"

tesseract_viewer_python/tesseract_viewer/resources/static/tesseract_viewer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class TesseractViewer {
4545
this._camera.setPosition(new BABYLON.Vector3(2.5, 1.5, -1));
4646
// Add lights to the scene
4747
this._light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, -1, 0), this._scene);
48+
this._light.intensity = 0.5
4849
this._root = new BABYLON.TransformNode("root0");
4950
this._root.rotation.x = -1.5707963267948966;
5051
yield this.updateScene();

tesseract_viewer_python/tesseract_viewer/resources/static/tesseract_viewer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class TesseractViewer {
5757

5858
// Add lights to the scene
5959
this._light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, -1, 0), this._scene);
60+
this._light.intensity = 0.5
6061

6162
this._root = new BABYLON.TransformNode("root0");
6263

tesseract_viewer_python/tesseract_viewer/tesseract_env_to_babylon_json.py

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
from tesseract import tesseract_geometry
2222
from tesseract.tesseract_common import Quaterniond
2323
import pkgutil
24+
import re
25+
import base64
2426

2527
def tesseract_env_to_babylon_json(t_env, origin_offset=[0,0,0]):
2628
return json.dumps(tesseract_env_to_babylon_json_dict(t_env,origin_offset))
@@ -74,8 +76,12 @@ def _process_link_recursive(link_map, joint_map, link_name, parent_joint_name):
7476
tf_link["parentId"] = "root"
7577
transform_nodes.append(tf_link)
7678

79+
visual_i = 0
80+
7781
for visual in link.visual:
78-
visual_name = "link_" + link_name + "_visual_" + visual.name
82+
visual_i += 1
83+
visual_u_name = visual.name + str(visual_i)
84+
visual_name = "link_" + link_name + "_visual_" + visual_u_name
7985
np_tf_visual = visual.origin
8086
visual_p, visual_q = _np_transform_to_babylon(np_tf_visual)
8187
tf_visual = {"name": visual_name, "isVisible": "true", "isEnabled": "true",
@@ -84,6 +90,8 @@ def _process_link_recursive(link_map, joint_map, link_name, parent_joint_name):
8490
tf_visual["rotationQuaternion"] = visual_q
8591
tf_visual["billboardMode"] = 0
8692

93+
tf_material = None
94+
8795
visual_geom = visual.geometry
8896
if (isinstance(visual_geom,tesseract_geometry.Mesh)):
8997

@@ -115,6 +123,57 @@ def _process_link_recursive(link_map, joint_map, link_name, parent_joint_name):
115123
submesh["indexStart"] = 0
116124
submesh["indexCount"] = len(indices)
117125
tf_visual["subMeshes"] = [submesh]
126+
127+
if not mesh.getResource().getUrl().lower().endswith('.stl'):
128+
mesh_material = mesh.getMaterial()
129+
if mesh_material is not None:
130+
131+
tf_material = {"name": "material_" + visual_name}
132+
133+
color = mesh_material.getBaseColorFactor().flatten()
134+
tf_color = [color[0], color[1], color[2]]
135+
tf_color2 = [color[0]*0.5, color[1]*0.5, color[2]*0.5]
136+
137+
"""tf_material["ambient"] = tf_color
138+
tf_material["diffuse"] = tf_color
139+
tf_material["specular"] = tf_color2
140+
tf_material["alpha"] = 1
141+
tf_material["backFaceCulling"] = True"""
142+
143+
tf_material["customType"] = "BABYLON.PBRMaterial"
144+
tf_material["albedo"] = tf_color
145+
tf_material["alpha"] = color[3]
146+
tf_material["alphaCutOff"] = 0.4
147+
tf_material["backFaceCulling"] = True
148+
tf_material["roughness"] = mesh_material.getRoughnessFactor()
149+
tf_material["metallic"] = mesh_material.getMetallicFactor()
150+
tf_material["maxSimultaneousLights"] = 4
151+
tf_material["environmentIntensity"] = 0.1
152+
153+
mesh_textures = mesh.getTextures()
154+
if mesh_textures is not None and len(mesh_textures) > 0:
155+
mesh_tex = mesh_textures[0]
156+
mesh_tex_image = mesh_tex.getTextureImage()
157+
tex_name = mesh_tex_image.getUrl()
158+
tex_mimetype = "image/jpg"
159+
if tex_name.endswith('png'):
160+
tex_mimetype = "image/png"
161+
tex_data = base64.b64encode(bytearray(mesh_tex_image.getResourceContents())).decode('ascii')
162+
tex_data_url = "data:" + tex_mimetype + ";base64," + tex_data
163+
164+
tf_texture = {"name": "material_texture_" + visual_name, "url": "material_texture_" + visual_name, "level": 1,"hasAlpha": True,"coordinatesMode":0,"uOffset":0,"vOffset":0,"uScale":1,\
165+
"vScale":1,"uAng":0,"vAng":0,"wAng":0,"wrapU":0,"wrapV":0,"coordinatesIndex":0, "isRenderTarget":False, \
166+
"base64String": tex_data_url}
167+
168+
#tf_material["useAlphaFromAlbedoTexture"] = True
169+
tf_material["albedoTexture"] = tf_texture
170+
mesh_uvs = mesh_tex.getUVs()
171+
tf_uvs = [0]*(len(mesh_uvs)*2)
172+
for i in range(len(mesh_uvs)):
173+
mesh_uv = mesh_uvs[i].flatten()
174+
tf_uvs[i*2] = mesh_uv[0]
175+
tf_uvs[i*2+1] = mesh_uv[1]
176+
tf_visual["uvs"] = tf_uvs
118177

119178

120179
elif (isinstance(visual_geom,tesseract_geometry.Box)):
@@ -160,21 +219,22 @@ def _process_link_recursive(link_map, joint_map, link_name, parent_joint_name):
160219

161220
meshes.append(tf_visual)
162221

163-
tf_material = {"name": "material_" + visual_name}
222+
if tf_material is None:
223+
tf_material = {"name": "material_" + visual_name}
164224

165-
material = visual.material
225+
material = visual.material
166226

167-
if material is None:
168-
tf_color = [0.5,0.5,0.5]
169-
else:
170-
color = material.color.flatten()
171-
tf_color = [color[0], color[1], color[2]]
172-
173-
tf_material["ambient"] = tf_color
174-
tf_material["diffuse"] = tf_color
175-
tf_material["specular"] = tf_color
176-
tf_material["alpha"] = 1
177-
tf_material["backFaceCulling"] = True
227+
if material is None:
228+
tf_color = [0.5,0.5,0.5]
229+
else:
230+
color = material.color.flatten()
231+
tf_color = [color[0], color[1], color[2]]
232+
233+
tf_material["ambient"] = tf_color
234+
tf_material["diffuse"] = tf_color
235+
tf_material["specular"] = tf_color
236+
tf_material["alpha"] = 1
237+
tf_material["backFaceCulling"] = True
178238

179239
materials.append(tf_material)
180240

tesseract_viewer_python/tesseract_viewer/tesseract_viewer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def update_joint_positions(self, joint_names, joint_positions):
131131
# Create "infinite" animation with constant joint angles
132132

133133
trajectory_json = dict()
134-
trajectory_json["use_time"] = False
134+
trajectory_json["use_time"] = True
135135
trajectory_json["loop_time"] = 10000
136136

137137
assert joint_names and all(isinstance(s,str) for s in joint_names), "Joint names must all be strings"

0 commit comments

Comments
 (0)