Skip to content

Commit

Permalink
Switch to ClothPrimView and fix some bugs in cloth generation
Browse files Browse the repository at this point in the history
Revert "Switch to ClothPrimView and fix some bugs in cloth generation"

This reverts commit a4f865b.

Revert "Revert "Switch to ClothPrimView and fix some bugs in cloth generation""

This reverts commit ed5d8b9b72a8fdb6766ce98e3141adaeb79fb991.
  • Loading branch information
cgokmen committed Dec 12, 2023
1 parent 0a22f5d commit 9d3012c
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 21 deletions.
56 changes: 36 additions & 20 deletions omnigibson/systems/micro_particle_system.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import uuid
import omnigibson as og
from omnigibson.macros import gm, create_module_macros
from omnigibson.prims.prim_base import BasePrim
Expand Down Expand Up @@ -43,6 +44,7 @@

# TODO: Tune these default values!
# TODO (eric): figure out whether one offset can fit all
m.MAX_CLOTH_PARTICLES = 20000
m.CLOTH_PARTICLE_CONTACT_OFFSET = 0.0075
m.CLOTH_REMESHING_ERROR_THRESHOLD = 0.05
m.CLOTH_STRETCH_STIFFNESS = 10000.0
Expand Down Expand Up @@ -1540,44 +1542,58 @@ def clothify_mesh_prim(cls, mesh_prim, remesh=True, particle_distance=None):
# we convert our mesh into a trimesh mesh, then export it to a temp file, then load it into pymeshlab
tm = mesh_prim_to_trimesh_mesh(mesh_prim=mesh_prim, include_normals=True, include_texcoord=True)
# Tmp file written to: {tmp_dir}/{tmp_fname}/{tmp_fname}.obj
tmp_name = f"{mesh_prim.GetName()}_{datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}"
tmp_name = str(uuid.uuid4())
tmp_dir = os.path.join(tempfile.gettempdir(), tmp_name)
tmp_fpath = os.path.join(tmp_dir, f"{tmp_name}.obj")
Path(tmp_dir).mkdir(parents=True, exist_ok=True)
tm.export(tmp_fpath)
ms = pymeshlab.MeshSet()
ms.load_new_mesh(tmp_fpath)

# Re-mesh based on @particle_distance - distance chosen such that at rest particles should be just touching
# each other. The 1.5 magic number comes from the particle cloth demo from omni
# Note that this means that the particles will overlap with each other, since at dist = 2 * contact_offset
# the particles are just touching each other at rest
# Start with the default particle distance
particle_distance = cls.particle_contact_offset * 2 / (1.5 * np.mean(mesh_prim.GetAttribute("xformOp:scale").Get())) \
if particle_distance is None else particle_distance
avg_edge_percentage_mismatch = 1.0
iters = 0
# Loop re-meshing until average edge percentage is within error threshold or we reach the max number of tries
while avg_edge_percentage_mismatch > m.CLOTH_REMESHING_ERROR_THRESHOLD:
ms.meshing_isotropic_explicit_remeshing(iterations=5, targetlen=pymeshlab.AbsoluteValue(particle_distance))
avg_edge_percentage_mismatch = abs(1.0 - particle_distance / ms.get_geometric_measures()["avg_edge_length"])
iters += 1
if iters > 5:

# Repetitively re-mesh at lower resolution until we have a mesh that has less than MAX_CLOTH_PARTICLES vertices
for _ in range(3):
ms = pymeshlab.MeshSet()
ms.load_new_mesh(tmp_fpath)

# Re-mesh based on @particle_distance - distance chosen such that at rest particles should be just touching
# each other. The 1.5 magic number comes from the particle cloth demo from omni
# Note that this means that the particles will overlap with each other, since at dist = 2 * contact_offset
# the particles are just touching each other at rest

avg_edge_percentage_mismatch = 1.0
# Loop re-meshing until average edge percentage is within error threshold or we reach the max number of tries
for _ in range(5):
if avg_edge_percentage_mismatch <= m.CLOTH_REMESHING_ERROR_THRESHOLD:
break

ms.meshing_isotropic_explicit_remeshing(iterations=5, targetlen=pymeshlab.AbsoluteValue(particle_distance))
avg_edge_percentage_mismatch = abs(1.0 - particle_distance / ms.get_geometric_measures()["avg_edge_length"])
else:
# Terminate anyways, but don't fail
log.warn("The generated cloth may not have evenly distributed particles.")

# Check if we have too many vertices
cm = ms.current_mesh()
if cm.vertex_number() > m.MAX_CLOTH_PARTICLES:
# We have too many vertices, so we will re-mesh again
particle_distance *= 1.47 # halve the number of vertices
else:
break
else:
raise ValueError("Could not remesh with less than MAX_CLOTH_PARTICLES vertices!")

# Re-write data to @mesh_prim
cm = ms.current_mesh()
new_face_vertex_ids = cm.face_matrix().flatten()
new_texcoord = cm.wedge_tex_coord_matrix()
new_vertices = cm.vertex_matrix()[new_face_vertex_ids]
new_normals = cm.vertex_normal_matrix()[new_face_vertex_ids]
n_vertices = len(new_vertices)
new_vertices = cm.vertex_matrix()
new_normals = cm.vertex_normal_matrix()
n_faces = len(cm.face_matrix())

mesh_prim.GetAttribute("faceVertexCounts").Set(np.ones(n_faces, dtype=int) * 3)
mesh_prim.GetAttribute("points").Set(Vt.Vec3fArray.FromNumpy(new_vertices))
mesh_prim.GetAttribute("faceVertexIndices").Set(np.arange(n_vertices))
mesh_prim.GetAttribute("faceVertexIndices").Set(new_face_vertex_ids)
mesh_prim.GetAttribute("normals").Set(Vt.Vec3fArray.FromNumpy(new_normals))
mesh_prim.GetAttribute("primvars:st").Set(Vt.Vec2fArray.FromNumpy(new_texcoord))

Expand Down
2 changes: 1 addition & 1 deletion omnigibson/utils/usd_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ def sample_mesh_keypoints(mesh_prim, n_keypoints, n_keyfaces, seed=None):
n_vertices = len(faces_flat)

# Sample vertices
unique_vertices = np.unique(faces_flat, return_index=True)[1]
unique_vertices = np.unique(faces_flat)
assert len(unique_vertices) == n_unique_vertices
keypoint_idx = np.random.choice(unique_vertices, size=n_keypoints, replace=False) if \
n_unique_vertices > n_keypoints else unique_vertices
Expand Down

0 comments on commit 9d3012c

Please sign in to comment.