Adding logic to include meshes using MjModel

This commit is contained in:
Abhishek Joshi
2023-09-09 16:37:45 -05:00
parent 4e58b0619b
commit 0412f98df1
4 changed files with 131 additions and 36 deletions
BIN
View File
Binary file not shown.
+98 -31
View File
@@ -1,7 +1,17 @@
from enum import Enum from enum import Enum
import mujoco import mujoco
from pxr import Usd, UsdGeom, Vt from pxr import Usd, UsdGeom, UsdLux, Vt, Gf
from scipy.spatial.transform import Rotation as R
def create_usd_geom_primitive(geom, stage):
geom_type = geom.type
if geom_type==USDGeomType.Plane.value:
return USDPlane(geom, stage)
elif geom_type==USDGeomType.Sphere.value:
return USDSphere(geom, stage)
elif geom_type==USDGeomType.Cube.value:
return USDCube(geom, stage)
class USDGeomType(Enum): class USDGeomType(Enum):
""" """
@@ -12,6 +22,7 @@ class USDGeomType(Enum):
Plane = 0 Plane = 0
Sphere = 2 Sphere = 2
Cube = 6 Cube = 6
Mesh = 7
class USDGeom(object): class USDGeom(object):
""" """
@@ -28,12 +39,22 @@ class USDGeom(object):
self.ref = None self.ref = None
def update_geom(self, new_geom): def update_geom(self, new_geom):
raise NotImplementedError self.update_pos(new_geom.pos)
self.update_rotation(new_geom.mat)
self.update_size(new_geom.size)
self.update_color(new_geom.rgba)
def update_pos(self, new_pos): def update_pos(self, new_pos):
pos = tuple([float(x) for x in new_pos]) pos = tuple([float(x) for x in new_pos])
self.xform.AddTranslateOp().Set(pos) self.xform.AddTranslateOp().Set(pos)
def update_rotation(self, new_mat):
r = R.from_matrix(new_mat)
euler_rotation = r.as_euler('xyz', degrees=True)
rotation = Gf.Vec3f(float(euler_rotation[0]), float(euler_rotation[1]), float(euler_rotation[2]))
self.xform.AddRotateXYZOp().Set(rotation)
# TODO: check to make sure scale and size are the same thing
def update_size(self, new_size): def update_size(self, new_size):
size = tuple([float(x) for x in new_size]) size = tuple([float(x) for x in new_size])
self.xform.AddScaleOp().Set(value=size) self.xform.AddScaleOp().Set(value=size)
@@ -41,8 +62,7 @@ class USDGeom(object):
def update_color(self, new_color): def update_color(self, new_color):
# new_color is the rgba (we extract first three) # new_color is the rgba (we extract first three)
rgba = [(float(x) for x in new_color[:3])] rgba = [(float(x) for x in new_color[:3])]
color = self.prim.GetDisplayColorAttr() color = self.prim.GetDisplayColorAttr().Set(rgba)
color.Set(rgba)
# TODO: create another method for transparency # TODO: create another method for transparency
def update_transparency(self, new_transparency): def update_transparency(self, new_transparency):
@@ -70,10 +90,10 @@ class USDPlane(USDGeom):
self.prim = UsdGeom.Plane.Define(stage, plane_path) self.prim = UsdGeom.Plane.Define(stage, plane_path)
self.ref = stage.GetPrimAtPath(plane_path) self.ref = stage.GetPrimAtPath(plane_path)
def update_geom(self, new_geom): def update_size(self, new_size):
self.update_pos(new_geom.pos) self.prim.GetAxisAttr().Set("Z")
self.update_size(new_geom.size) self.prim.GetWidthAttr().Set(float(new_size[0]))
self.update_color(new_geom.rgba) self.prim.GetLengthAttr().Set(float(new_size[1]))
class USDSphere(USDGeom): class USDSphere(USDGeom):
""" """
@@ -83,8 +103,8 @@ class USDSphere(USDGeom):
sphere_count = 0 sphere_count = 0
def __init__(self, def __init__(self,
geom=None, geom,
stage=None): stage):
super().__init__(geom, stage) super().__init__(geom, stage)
self.type = 2 self.type = 2
USDSphere.sphere_count += 1 USDSphere.sphere_count += 1
@@ -94,11 +114,6 @@ class USDSphere(USDGeom):
self.prim = UsdGeom.Sphere.Define(stage, sphere_path) self.prim = UsdGeom.Sphere.Define(stage, sphere_path)
self.ref = stage.GetPrimAtPath(sphere_path) self.ref = stage.GetPrimAtPath(sphere_path)
def update_geom(self, new_geom):
self.update_pos(new_geom.pos)
self.update_size(new_geom.size)
self.update_color(new_geom.rgba)
class USDCube(USDGeom): class USDCube(USDGeom):
""" """
Stores information regarding a cube geom in USD Stores information regarding a cube geom in USD
@@ -107,8 +122,8 @@ class USDCube(USDGeom):
cube_count = 0 cube_count = 0
def __init__(self, def __init__(self,
geom=None, geom,
stage=None): stage):
super().__init__(geom, stage) super().__init__(geom, stage)
self.type = 6 self.type = 6
USDCube.cube_count += 1 USDCube.cube_count += 1
@@ -118,24 +133,76 @@ class USDCube(USDGeom):
self.prim = UsdGeom.Cube.Define(stage, cube_path) self.prim = UsdGeom.Cube.Define(stage, cube_path)
self.ref = stage.GetPrimAtPath(cube_path) self.ref = stage.GetPrimAtPath(cube_path)
class USDMesh(USDGeom):
"""
Stores information regarding a mesh geom in USD
"""
mesh_count = 0
def __init__(self,
mesh_idx,
geom,
stage,
model,
mesh_vertex_ranges,
mesh_face_ranges):
super().__init__(geom, stage)
self.type = 7
USDMesh.mesh_count += 1
xform_path = f'/Mesh_Xform_{USDMesh.mesh_count}'
mesh_path= f'{xform_path}/Mesh_{USDMesh.mesh_count}'
self.xform = UsdGeom.Xform.Define(stage, xform_path)
self.prim = UsdGeom.Mesh.Define(stage, mesh_path)
self.ref = stage.GetPrimAtPath(mesh_path)
self.vertices = model.mesh_vert[mesh_vertex_ranges[mesh_idx]:mesh_vertex_ranges[mesh_idx+1]]
self.prim.GetPointsAttr().Set(self.vertices)
self.prim.GetFaceVertexCountsAttr().Set([3 for _ in range(model.mesh_facenum[mesh_idx])])
self.faces = model.mesh_face[mesh_face_ranges[mesh_idx]:mesh_face_ranges[mesh_idx+1]]
self.prim.GetFaceVertexIndicesAttr().Set(self.faces)
def update_geom(self, new_geom): def update_geom(self, new_geom):
self.update_pos(new_geom.pos) self.update_pos(new_geom.pos)
self.update_size(new_geom.size) self.update_rotation(new_geom.mat)
self.update_color(new_geom.rgba)
def create_usd_geom(geom, stage): # TODO: remove this, temporary
geom_type = geom.type self.xform.AddScaleOp().Set(value=(10.0, 10.0, 10.0))
if geom_type==USDGeomType.Plane.value:
return USDPlane(geom, stage)
elif geom_type==USDGeomType.Sphere.value:
return USDSphere(geom, stage)
elif geom_type==USDGeomType.Cube.value:
return USDCube(geom, stage)
class USDLight(object): class USDLight(object):
def __init__(self): """
pass Class for the created lights
"""
light_count = 0
def __init__(self,
stage):
self.stage = stage
USDLight.light_count += 1
xform_path = f'/Light_Xform_{USDLight.light_count}'
light_path = f'{xform_path}/Light_{USDLight.light_count}'
self.xform = UsdGeom.Xform.Define(stage, xform_path)
self.prim = UsdLux.SphereLight.Define(stage, light_path)
self.ref = stage.GetPrimAtPath(light_path)
def update_light(self, new_light): def update_light(self, new_light):
pass pos = tuple([float(x) for x in new_light.pos])
self.xform.AddTranslateOp().Set(pos)
# TODO attributes:
# - direction
# - intensity
# - exposure
# - radius
# - specular
self.prim.GetIntensityAttr().Set(5000);
+25 -5
View File
@@ -2,6 +2,7 @@
import mujoco import mujoco
import mujoco.viewer as viewer import mujoco.viewer as viewer
from mujoco.usd_component import * from mujoco.usd_component import *
from mujoco.usd_utilities import *
from pxr import Usd, UsdGeom from pxr import Usd, UsdGeom
class USDRenderer(object): class USDRenderer(object):
@@ -47,13 +48,29 @@ class USDRenderer(object):
""" """
Loads and initializes the necessary objects to render the scene Loads and initializes the necessary objects to render the scene
""" """
if self.model.nmesh > 0:
mesh_vertex_ranges = get_mesh_ranges(self.model.nmesh, self.model.mesh_vertnum)
mesh_face_ranges = get_mesh_ranges(self.model.nmesh, self.model.mesh_facenum)
current_mesh_idx = 0
# initializes an array to store all the geoms in the scene # initializes an array to store all the geoms in the scene
# populates with "empty" USDGeom objects # populates with "empty" USDGeom objects
self.usd_geoms = [] self.usd_geoms = []
geoms = self.scene.geoms geoms = self.scene.geoms
self.ngeom = self.scene.ngeom self.ngeom = self.scene.ngeom
for i in range(self.ngeom): for i in range(self.ngeom):
self.usd_geoms.append(create_usd_geom(geoms[i], self.stage)) if geoms[i].type == USDGeomType.Mesh.value:
self.usd_geoms.append(USDMesh(current_mesh_idx,
geoms[i],
self.stage,
self.model,
mesh_vertex_ranges,
mesh_face_ranges))
current_mesh_idx += 1
else:
self.usd_geoms.append(create_usd_geom_primitive(geoms[i], self.stage))
# initializes an array to store all the lights in the scene # initializes an array to store all the lights in the scene
# populates with "empty" USDLight objects # populates with "empty" USDLight objects
@@ -61,7 +78,7 @@ class USDRenderer(object):
lights = self.scene.lights lights = self.scene.lights
self.nlight = self.scene.nlight self.nlight = self.scene.nlight
for i in range(self.nlight): for i in range(self.nlight):
self.usd_lights.append(USDLight()) self.usd_lights.append(USDLight(self.stage))
def _update(self): def _update(self):
self._update_geoms() self._update_geoms()
@@ -83,9 +100,12 @@ class USDRenderer(object):
lights = self.scene.lights lights = self.scene.lights
nlight = self.scene.nlight nlight = self.scene.nlight
for i in range(nlight): for i in range(nlight):
print(self.usd_lights[i]) self.usd_lights[i].update_light(lights[i])
def _update_camera(self): def _update_camera(self):
"""
Updates the camera to match the current scene
"""
pass pass
def start_viewer(self): def start_viewer(self):
@@ -94,11 +114,11 @@ class USDRenderer(object):
def render(self): def render(self):
# should render the usd file given a particular renderer that # should render the usd file given a particular renderer that
# works with USD files? # works with USD files
# TODO: determine if this is valid functionality # TODO: determine if this is valid functionality
pass pass
# TODO: remove later, this is only for debuggin purposes # TODO: remove later, this is only for debugging purposes
def print_geom_information(self): def print_geom_information(self):
for i in range(self.ngeom): for i in range(self.ngeom):
print(self.usd_geoms[i]) print(self.usd_geoms[i])
+8
View File
@@ -0,0 +1,8 @@
def get_mesh_ranges(nmesh, arr):
mesh_ranges = [0]
running_sum = 0
for i in range(nmesh):
running_sum += arr[i]
mesh_ranges.append(running_sum)
return mesh_ranges