I would like to control position of single particle of cloth element in Isaac Sim. I am using physx preview extension and would like to control particle position of cloth with python API like shift+left click and drug as in the video below.
This feature is now available or future release? That is my question.
This is my code that is creating particle cloth.
from curses import erasechar
from dis import dis
from socket import gaierror
import omni
from locale import currency
from tokenize import Triple
from construct import Tunnel
import numpy as np
import math
import time
import copy
from omni.isaac.kit import SimulationApp
simulation_app = SimulationApp({"headless": False})
from pxr import Usd, UsdGeom, Sdf, Gf, Vt, PhysxSchema, UsdPhysics
def addPhysxParticleSystem(
stage,
particle_system_path,
contact_offset,
rest_offset,
particle_contact_offset,
solid_rest_offset,
fluid_rest_offset,
solver_position_iterations,
solver_velocity_iterations,
wind,
scenePath,
):
particle_system = PhysxSchema.PhysxParticleSystem.Define(stage, particle_system_path)
if particle_system:
particle_system.CreateContactOffsetAttr().Set(contact_offset)
particle_system.CreateRestOffsetAttr().Set(rest_offset)
particle_system.CreateParticleContactOffsetAttr().Set(particle_contact_offset)
particle_system.CreateSolidRestOffsetAttr().Set(solid_rest_offset)
particle_system.CreateFluidRestOffsetAttr().Set(fluid_rest_offset)
particle_system.CreateSolverPositionIterationCountAttr().Set(solver_position_iterations)
particle_system.CreateSolverVelocityIterationCountAttr().Set(solver_velocity_iterations)
particle_system.CreateWindAttr().Set(wind)
# Reference simulation owner using PhysxPhysicsAPI
physics_api = PhysxSchema.PhysxPhysicsAPI.Apply(particle_system.GetPrim())
physics_api.CreateSimulationOwnerRel().SetTargets([scenePath])
return particle_system
else:
return None
def addSpringConstraint(springConnections, i, j, springStiffnesses, stiffness, springDampings, damping, springRestLengths, distance):
springConnections.append(Gf.Vec2i(i, j))
springStiffnesses.append(stiffness)
springDampings.append(damping)
springRestLengths.append(distance.GetLength())
def gridIndex(x, y, dx):
return y * dx + x
def CreateSpringGrid(
lower,
dx,
dy,
radius,
positions,
normals,
restPositions,
velocities,
invMasses,
triangleIndices,
springConnections,
springStiffnesses,
springDampings,
springRestLengths,
stretchStiffness,
stretchDamping,
bendStiffness,
bendDamping,
shearStiffness,
shearDamping,
invMass,
staticEdges=False,
):
for y in range(dy):
for x in range(dx):
pos_offset = Gf.Vec3f(radius * x, radius * y, radius * 1.0)
positions.append(lower + pos_offset)
normals.append(Gf.Vec3f(0.0, 0.0, 1.0))
restPositions.append(lower + pos_offset)
velocities.append(Gf.Vec3f(0.0, 0.0, 0.0))
if staticEdges is True:
if x == 0 or x == (dx - 1):
invMasses.append(0.0)
else:
invMasses.append(invMass)
else:
invMasses.append(invMass)
if x > 0 and y > 0:
triangleIndices.append(gridIndex(x - 1, y - 1, dx))
triangleIndices.append(gridIndex(x, y - 1, dx))
triangleIndices.append(gridIndex(x, y, dx))
triangleIndices.append(gridIndex(x - 1, y - 1, dx))
triangleIndices.append(gridIndex(x, y, dx))
triangleIndices.append(gridIndex(x - 1, y, dx))
# horizontal
for y in range(dy):
for x in range(dx):
i = y * dx + x
if x > 0:
j = y * dx + x - 1
addSpringConstraint(
springConnections,
i,
j,
springStiffnesses,
stretchStiffness,
springDampings,
stretchDamping,
springRestLengths,
positions[i] - positions[j],
)
if x > 1 and bendStiffness > 0.0:
j = y * dx + x - 2
addSpringConstraint(
springConnections,
i,
j,
springStiffnesses,
bendStiffness,
springDampings,
bendDamping,
springRestLengths,
positions[i] - positions[j],
)
if y > 0 and x < dx - 1 and shearStiffness > 0.0:
j = (y - 1) * dx + x + 1
addSpringConstraint(
springConnections,
i,
j,
springStiffnesses,
shearStiffness,
springDampings,
shearDamping,
springRestLengths,
positions[i] - positions[j],
)
if y > 0 and x > 0 and shearStiffness > 0.0:
j = (y - 1) * dx + x - 1
addSpringConstraint(
springConnections,
i,
j,
springStiffnesses,
shearStiffness,
springDampings,
shearDamping,
springRestLengths,
positions[i] - positions[j],
)
def addPhysxClothWithConstraints(
stage,
path,
positions,
normals,
rest_positions,
velocities,
inv_masses,
triangle_indices,
spring_connections,
spring_stiffnesses,
spring_dampings,
spring_rest_lengths,
self_collision,
self_collision_filter,
inv_gravity,
particle_group,
particle_system_path,
):
mesh = UsdGeom.Mesh.Define(stage, path)
prim = mesh.GetPrim()
mesh.CreateDoubleSidedAttr().Set(True)
vertex_count_attr = mesh.CreateFaceVertexCountsAttr()
vertex_indices_attr = mesh.CreateFaceVertexIndicesAttr()
norm_attr = mesh.CreateNormalsAttr()
point_attr = mesh.CreatePointsAttr()
# Triangle array's vertex count per face is always 3
vertex_count = 3
array_size = int(len(triangle_indices) / 3)
index_array = Vt.IntArray(array_size, vertex_count)
vertex_count_attr.Set(index_array)
vertex_indices_attr.Set(triangle_indices)
norm_attr.Set(normals)
point_attr.Set(positions)
cloth_api = PhysxSchema.PhysxClothAPI.Apply(prim)
cloth_api.CreateSelfCollisionAttr().Set(self_collision)
cloth_api.CreateSelfCollisionFilterAttr().Set(self_collision_filter)
cloth_api.CreateParticleGroupAttr().Set(particle_group)
# Reference simulation owner using PhysxPhysicsAPI
physics_api = PhysxSchema.PhysxPhysicsAPI.Apply(prim)
physics_api.CreateSimulationOwnerRel().SetTargets([particle_system_path])
# Custom attributes
prim.CreateAttribute("invGravity", Sdf.ValueTypeNames.Bool).Set(inv_gravity)
prim.CreateAttribute("springConnections", Sdf.ValueTypeNames.Int2Array).Set(spring_connections)
prim.CreateAttribute("springStiffnesses", Sdf.ValueTypeNames.FloatArray).Set(spring_stiffnesses)
prim.CreateAttribute("springDampings", Sdf.ValueTypeNames.FloatArray).Set(spring_dampings)
prim.CreateAttribute("springRestLengths", Sdf.ValueTypeNames.FloatArray).Set(spring_rest_lengths)
prim.CreateAttribute("restPositions", Sdf.ValueTypeNames.Point3fArray).Set(rest_positions)
prim.CreateAttribute("velocities", Sdf.ValueTypeNames.Point3fArray).Set(velocities)
prim.CreateAttribute("inverseMasses", Sdf.ValueTypeNames.FloatArray).Set(inv_masses)
return point_attr
from omni.isaac.core import World
_my_world = World()
_my_world.scene.add_default_ground_plane()
_stage = _my_world.scene.stage
from omni.isaac.core import PhysicsContext
physics_context = _my_world.get_physics_context()
physics_context.enable_gpu_dynamics(True)
physics_context.enable_ccd(False)
physics_context.set_solver_type("TGS")
physics_context.enable_stablization(False)
from omni.isaac.core.utils.extensions import enable_extension
enable_extension("omni.physx.preview")
dimX = 16
dimY = 16
radius = 1.5
particleSystemPath = Sdf.Path("/particleSystem0")
restOffset = radius
contactOffset = radius + 0.1
defaultPrimPath = str(_stage.GetDefaultPrim().GetPath())
scene = UsdPhysics.Scene.Define(_stage, defaultPrimPath + "/physicsScene")
addPhysxParticleSystem(
_stage,
particleSystemPath,
contactOffset,
restOffset,
contactOffset,
restOffset,
0.0,
16,
1,
Gf.Vec3f(0, 0, 0),
scene.GetPath(),
)
clothPath = Sdf.Path("/cloth0")
positions_list = []
normals_list = []
restPositions_list = []
velocities_list = []
invMasses_list = []
triangleIndices_list = []
springConnections_list = []
springStiffnesses_list = []
springDampings_list = []
springRestLengths_list = []
lower = Gf.Vec3f(-radius * dimX / 2, -radius * dimY / 2, 0.0)
stretchStiffness = 500.0
bendStiffness = 300.0
shearStiffness = 300.0
damping = 20.0
invMass = 400.0
CreateSpringGrid(
lower,
dimX,
dimY,
radius,
positions_list,
normals_list,
restPositions_list,
velocities_list,
invMasses_list,
triangleIndices_list,
springConnections_list,
springStiffnesses_list,
springDampings_list,
springRestLengths_list,
stretchStiffness,
damping,
bendStiffness,
damping,
shearStiffness,
damping,
invMass,
False,
)
invMasses_list[0] = 0.0
invMasses_list[240] = 0.0
positions = Vt.Vec3fArray(positions_list)
normals = Vt.Vec3fArray(normals_list)
restPositions = Vt.Vec3fArray(restPositions_list)
velocities = Vt.Vec3fArray(velocities_list)
invMasses = Vt.FloatArray(invMasses_list)
triangleIndices = Vt.IntArray(triangleIndices_list)
springConnections = Vt.Vec2iArray(springConnections_list)
springStiffnesses = Vt.FloatArray(springStiffnesses_list)
springDampings = Vt.FloatArray(springDampings_list)
springRestLengths = Vt.FloatArray(springRestLengths_list)
point_attr = addPhysxClothWithConstraints(
_stage,
clothPath,
positions,
normals,
restPositions,
velocities,
invMasses,
triangleIndices,
springConnections,
springStiffnesses,
springDampings,
springRestLengths,
True,
True,
False,
0,
particleSystemPath,
)
tissue_color = Vt.Vec3fArray([Gf.Vec3f(71.0 / 255.0, 165.0 / 255.0, 1.0)])
tissue_prim = UsdGeom.Mesh.Define(_stage, Sdf.Path("/tissue"))
tissue_prim.CreateDisplayColorAttr(tissue_color)
translation = Gf.Vec3f(0.0, 0.0, 0.0)
tissue_prim.AddTranslateOp().Set(translation)
from omni.isaac.core.utils.viewports import set_camera_view
from pxr import UsdLux
from omni.isaac.synthetic_utils import SyntheticDataHelper
import os
set_camera_view(eye=np.array([53.0, 0.0, 30.0]), target=np.array([0.0, 0.0, 0.0]))
light_prim = UsdLux.DistantLight.Define(_my_world.scene.stage, Sdf.Path("/DistantLight"))
light_prim.CreateIntensityAttr(500)
_my_world.reset()
while True:
_my_world.step(render=True)
# points = np.array(point_attr.Get())
# points[255][2] = 5.0
# point_attr.Set(points)
Thank you.
Sugita