qbhf2's picture
added NvidiaWarp and GarmentCode repos
66c9c8a
# Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
###########################################################################
# Example Mesh
#
# Shows how to implement a PBD particle simulation with collision against
# a deforming triangle mesh. The mesh collision uses wp.mesh_query_point_sign_normal()
# to compute the closest point, and wp.Mesh.refit() to update the mesh
# object after deformation.
#
###########################################################################
import os
import numpy as np
from pxr import Usd, UsdGeom
import warp as wp
import warp.render
wp.init()
@wp.kernel
def deform(positions: wp.array(dtype=wp.vec3), t: float):
tid = wp.tid()
x = positions[tid]
offset = -wp.sin(x[0]) * 0.02
scale = wp.sin(t)
x = x + wp.vec3(0.0, offset * scale, 0.0)
positions[tid] = x
@wp.kernel
def simulate(
positions: wp.array(dtype=wp.vec3),
velocities: wp.array(dtype=wp.vec3),
mesh: wp.uint64,
margin: float,
dt: float,
):
tid = wp.tid()
x = positions[tid]
v = velocities[tid]
v = v + wp.vec3(0.0, 0.0 - 9.8, 0.0) * dt - v * 0.1 * dt
xpred = x + v * dt
face_index = int(0)
face_u = float(0.0)
face_v = float(0.0)
sign = float(0.0)
max_dist = 1.5
if wp.mesh_query_point_sign_normal(mesh, xpred, max_dist, sign, face_index, face_u, face_v):
p = wp.mesh_eval_position(mesh, face_index, face_u, face_v)
delta = xpred - p
dist = wp.length(delta) * sign
err = dist - margin
# mesh collision
if err < 0.0:
n = wp.normalize(delta) * sign
xpred = xpred - n * err
# pbd update
v = (xpred - x) * (1.0 / dt)
x = xpred
positions[tid] = x
velocities[tid] = v
class Example:
def __init__(self, stage):
self.num_particles = 1000
self.sim_steps = 500
self.sim_dt = 1.0 / 60.0
self.sim_time = 0.0
self.sim_timers = {}
self.sim_margin = 0.1
self.renderer = wp.render.UsdRenderer(stage)
usd_stage = Usd.Stage.Open(os.path.join(os.path.dirname(__file__), "assets/bunny.usd"))
usd_geom = UsdGeom.Mesh(usd_stage.GetPrimAtPath("/bunny/bunny"))
usd_scale = 10.0
# create collision mesh
self.mesh = wp.Mesh(
points=wp.array(usd_geom.GetPointsAttr().Get() * usd_scale, dtype=wp.vec3),
indices=wp.array(usd_geom.GetFaceVertexIndicesAttr().Get(), dtype=int),
)
# random particles
init_pos = (np.random.rand(self.num_particles, 3) - np.array([0.5, -1.5, 0.5])) * 10.0
init_vel = np.random.rand(self.num_particles, 3) * 0.0
self.positions = wp.from_numpy(init_pos, dtype=wp.vec3)
self.velocities = wp.from_numpy(init_vel, dtype=wp.vec3)
def update(self):
with wp.ScopedTimer("simulate", detailed=False, dict=self.sim_timers):
wp.launch(kernel=deform, dim=len(self.mesh.points), inputs=[self.mesh.points, self.sim_time])
# refit the mesh BVH to account for the deformation
self.mesh.refit()
wp.launch(
kernel=simulate,
dim=self.num_particles,
inputs=[self.positions, self.velocities, self.mesh.id, self.sim_margin, self.sim_dt],
)
self.sim_time += self.sim_dt
def render(self, is_live=False):
with wp.ScopedTimer("render", detailed=False):
time = 0.0 if is_live else self.sim_time
self.renderer.begin_frame(time)
self.renderer.render_mesh(name="mesh", points=self.mesh.points.numpy(), indices=self.mesh.indices.numpy())
self.renderer.render_points(name="points", points=self.positions.numpy(), radius=self.sim_margin)
self.renderer.end_frame()
if __name__ == "__main__":
stage_path = os.path.join(os.path.dirname(__file__), "outputs/example_mesh.usd")
example = Example(stage_path)
for i in range(example.sim_steps):
example.update()
example.render()
example.renderer.save()