iMSTK
Interactive Medical Simulation Toolkit
pbdRigidInDeformableGraspingExample.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkCamera.h"
8 #include "imstkCapsule.h"
9 #include "imstkControllerForceText.h"
10 #include "imstkDirectionalLight.h"
11 #include "imstkKeyboardDeviceClient.h"
12 #include "imstkMeshIO.h"
13 #include "imstkMouseDeviceClient.h"
14 #include "imstkMouseSceneControl.h"
15 #include "imstkPbdModel.h"
16 #include "imstkPbdModelConfig.h"
17 #include "imstkPbdObject.h"
18 #include "imstkPbdObjectCollision.h"
19 #include "imstkPbdObjectController.h"
20 #include "imstkPbdObjectGrasping.h"
21 #include "imstkRenderMaterial.h"
22 #include "imstkScene.h"
23 #include "imstkSceneManager.h"
24 #include "imstkSimulationManager.h"
25 #include "imstkSimulationUtils.h"
26 #include "imstkTextVisualModel.h"
27 #include "imstkVTKViewer.h"
28 
29 #ifdef iMSTK_USE_HAPTICS
30 #include "imstkDeviceManager.h"
31 #include "imstkDeviceManagerFactory.h"
32 #else
33 #include "imstkDummyClient.h"
34 #endif
35 
36 using namespace imstk;
37 
38 int
39 main()
40 {
41  // Write log to stdout and file
43 
44  // Setup a scene
45  auto scene = std::make_shared<Scene>("PbdRigidInDeformableGrasping");
46  scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
47  scene->getActiveCamera()->setPosition(0.0, 0.004, 0.1);
48  scene->getActiveCamera()->setViewUp(0.0, 1.0, 0.0);
49 
50  auto pbdModel = std::make_shared<PbdModel>();
51  auto pbdConfig = std::make_shared<PbdModelConfig>();
52  pbdConfig->m_gravity = Vec3d(0.0, 0.0, 0.0);
53  pbdConfig->m_dt = 0.001;
54  pbdConfig->m_iterations = 5;
55  pbdConfig->m_linearDampingCoeff = 0.03;
56  pbdConfig->m_angularDampingCoeff = 0.01;
57  pbdConfig->m_doPartitioning = false;
58  pbdModel->configure(pbdConfig);
59 
60  auto tissueObj = std::make_shared<PbdObject>("tissue");
61  {
62  auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Organs/Vessels/vessel_test.obj");
63 
64  // Setup the Parameters
65  pbdModel->getConfig()->enableConstraint(PbdModelConfig::ConstraintGenType::Distance, 10000.0);
66  pbdModel->getConfig()->enableConstraint(PbdModelConfig::ConstraintGenType::Dihedral, 0.1);
67 
68  // Setup the VisualModel
69  auto material = std::make_shared<RenderMaterial>();
70  material->setBackFaceCulling(false);
71  material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
72  material->setShadingModel(RenderMaterial::ShadingModel::PBR);
73  material->setOpacity(0.5);
74 
75  // Setup the Object
76  tissueObj->setVisualGeometry(surfMesh);
77  tissueObj->getVisualModel(0)->setRenderMaterial(material);
78  tissueObj->setPhysicsGeometry(surfMesh);
79  tissueObj->setCollidingGeometry(surfMesh);
80  tissueObj->setDynamicalModel(pbdModel);
81 
82  tissueObj->getPbdBody()->uniformMassValue = 1.0;
83  }
84  scene->addSceneObject(tissueObj);
85 
86  auto capsule0Obj = std::make_shared<PbdObject>("capsule0");
87  {
88  //auto rigidGeom = std::make_shared<Sphere>(Vec3d(0.0, 0.0, 0.0), 0.0018);
89  auto rigidGeom = std::make_shared<Capsule>(Vec3d(0.0, 0.0, 0.0), 0.004, 0.01);
90  capsule0Obj->setVisualGeometry(rigidGeom);
91  capsule0Obj->setCollidingGeometry(rigidGeom);
92  capsule0Obj->setPhysicsGeometry(rigidGeom);
93 
94  // Setup material
95  capsule0Obj->getVisualModel(0)->getRenderMaterial()->setColor(Color(1.0, 0.0, 0.0));
96  capsule0Obj->getVisualModel(0)->getRenderMaterial()->setShadingModel(RenderMaterial::ShadingModel::PBR);
97  capsule0Obj->getVisualModel(0)->getRenderMaterial()->setRoughness(0.5);
98  capsule0Obj->getVisualModel(0)->getRenderMaterial()->setMetalness(1.0);
99  capsule0Obj->getVisualModel(0)->getRenderMaterial()->setIsDynamicMesh(false);
100 
101  capsule0Obj->setDynamicalModel(pbdModel);
102 
103  // Setup body
104  const Quatd orientation = Quatd::FromTwoVectors(Vec3d(0.0, 1.0, 0.0), Vec3d(0.0067, 0.0027, 0.0));
105  capsule0Obj->getPbdBody()->setRigid(
106  Vec3d(0.0085, 0.0037, 0.0),
107  100.0,
108  orientation,
109  Mat3d::Identity() * 0.005);
110  }
111  scene->addSceneObject(capsule0Obj);
112 
113  auto collision0 = std::make_shared<PbdObjectCollision>(tissueObj, capsule0Obj);
114  collision0->setRigidBodyCompliance(0.00001);
115  scene->addInteraction(collision0);
116 
117  auto lapTool = std::make_shared<PbdObject>("lapTool");
118  {
119  const double capsuleLength = 0.3;
120  auto toolGeom = std::make_shared<Capsule>(Vec3d(0.0, 0.0, 0.0),
121  0.002, capsuleLength, Quatd::FromTwoVectors(Vec3d(0.0, 1.0, 0.0), Vec3d(0.0, 0.0, 1.0)));
122 
123  lapTool->setDynamicalModel(pbdModel);
124  lapTool->setPhysicsGeometry(toolGeom);
125  lapTool->setCollidingGeometry(toolGeom);
126  lapTool->setVisualGeometry(toolGeom);
127 
128  std::shared_ptr<RenderMaterial> material = lapTool->getVisualModel(0)->getRenderMaterial();
129  material->setIsDynamicMesh(false);
130  material->setMetalness(1.0);
131  material->setRoughness(0.2);
132  material->setShadingModel(RenderMaterial::ShadingModel::PBR);
133 
134  lapTool->getPbdBody()->setRigid(
135  Vec3d(0.0, 0.0, capsuleLength * 0.5), // Position
136  6.0, // Mass
137  Quatd::Identity(), Mat3d::Identity() * 10000.0);
138 
139  auto controller = lapTool->addComponent<PbdObjectController>();
140  controller->setControlledObject(lapTool);
141  controller->setLinearKs(1000000.0);
142  controller->setAngularKs(100000000.0);
143  controller->setForceScaling(0.003);
144  controller->setSmoothingKernelSize(15);
145  controller->setUseForceSmoothening(true);
146 
147  // Add something to display controller force
148  auto controllerForceTxt = lapTool->addComponent<ControllerForceText>();
149  controllerForceTxt->setController(controller);
150  }
151  scene->addSceneObject(lapTool);
152 
153  // Add picking interaction for both jaws of the tool
154  auto grasping = std::make_shared<PbdObjectGrasping>(tissueObj, lapTool);
155  grasping->setStiffness(0.05);
156  scene->addInteraction(grasping);
157 
158  // Light
159  auto light = std::make_shared<DirectionalLight>();
160  light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
161  light->setIntensity(1.0);
162  scene->addLight("Light", light);
163 
164  // Run the simulation
165  {
166  // Setup a viewer to render
167  auto viewer = std::make_shared<VTKViewer>();
168  viewer->setVtkLoggerMode(VTKViewer::VTKLoggerMode::MUTE);
169  viewer->setActiveScene(scene);
170  viewer->setDebugAxesLength(0.01, 0.01, 0.01);
171 
172  // Setup a scene manager to advance the scene
173  auto sceneManager = std::make_shared<SceneManager>();
174  sceneManager->setActiveScene(scene);
175  sceneManager->pause(); // Start simulation paused
176 
177  auto driver = std::make_shared<SimulationManager>();
178  driver->addModule(viewer);
179  driver->addModule(sceneManager);
180  driver->setDesiredDt(0.001);
181 
182 #ifdef iMSTK_USE_HAPTICS
183  std::shared_ptr<DeviceManager> hapticManager = DeviceManagerFactory::makeDeviceManager();
184  driver->addModule(hapticManager);
185  if (hapticManager->getTypeName() == "HaplyDeviceManager")
186  {
187  auto rightController = lapTool->getComponent<PbdObjectController>();
188  rightController->setTranslationOffset((*lapTool->getPbdBody()->vertices)[0] +
189  Vec3d(0.1, 0.0, -0.1));
190  }
191 
192  std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
193 
194  connect<ButtonEvent>(deviceClient, &DeviceClient::buttonStateChanged,
195  [&](ButtonEvent* e)
196  {
197  if (e->m_button == 1 && e->m_buttonState == BUTTON_PRESSED)
198  {
199  LOG(INFO) << "Grasp!";
200  grasping->beginVertexGrasp(std::dynamic_pointer_cast<AnalyticalGeometry>(lapTool->getCollidingGeometry()));
201  }
202  });
203  connect<ButtonEvent>(deviceClient, &DeviceClient::buttonStateChanged,
204  [&](ButtonEvent* e)
205  {
206  if (e->m_button == 1 && e->m_buttonState == BUTTON_RELEASED)
207  {
208  LOG(INFO) << "Release!";
209  grasping->endGrasp();
210  }
211  });
212 #else
213  auto deviceClient = std::make_shared<DummyClient>();
214  auto dummyClientMovement = lapTool->addComponent<LambdaBehaviour>("DummyClientMovement");
215  dummyClientMovement->setUpdate([ = ](const double&)
216  {
217  const Vec2d mousePos = viewer->getMouseDevice()->getPos();
218  const Vec3d worldPos = Vec3d(mousePos[0] - 0.5, mousePos[1] - 0.5, 0.0) * 0.1;
219  deviceClient->setPosition(worldPos);
220  });
221  connect<MouseEvent>(viewer->getMouseDevice(), &MouseDeviceClient::mouseButtonPress,
222  [&](MouseEvent* e)
223  {
224  if (e->m_buttonId == 0)
225  {
226  LOG(INFO) << "Grasp!";
227  grasping->beginVertexGrasp(std::dynamic_pointer_cast<AnalyticalGeometry>(lapTool->getCollidingGeometry()));
228  }
229  });
230  connect<MouseEvent>(viewer->getMouseDevice(), &MouseDeviceClient::mouseButtonRelease,
231  [&](MouseEvent* e)
232  {
233  if (e->m_buttonId == 0)
234  {
235  LOG(INFO) << "Release!";
236  grasping->endGrasp();
237  }
238  });
239 #endif
240  auto rightController = lapTool->getComponent<PbdObjectController>();
241  rightController->setDevice(deviceClient);
242  rightController->setTranslationOffset((*lapTool->getPbdBody()->vertices)[0]);
243 
244  // Add default mouse and keyboard controls to the viewer
245  std::shared_ptr<Entity> mouseAndKeyControls =
246  SimulationUtils::createDefaultSceneControl(driver);
247  auto instructText = mouseAndKeyControls->getComponent<TextVisualModel>();
248  instructText->setText(instructText->getText() +
249  "\nPress Haptic Button or Click to grasp" +
250  "\nPress 1 to toggle gravity");
251  scene->addSceneObject(mouseAndKeyControls);
252 
253  if (auto mouseControl = mouseAndKeyControls->getComponent<MouseSceneControl>())
254  {
255  mouseControl->setEnabled(true);
256  }
257 
258  // Add mouse and keyboard controls to the viewer
259  {
260  connect<KeyEvent>(viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress, [&](KeyEvent* e)
261  {
262  if (e->m_key == '1')
263  {
264  if (pbdModel->getConfig()->m_gravity[1] == 0.0)
265  {
266  pbdModel->getConfig()->m_gravity = Vec3d(0.0, -1.0, 0.0);
267  }
268  else
269  {
270  pbdModel->getConfig()->m_gravity = Vec3d::Zero();
271  }
272  }
273  else if (e->m_key == 'u')
274  {
275  scene->advance(sceneManager->getDt());
276  viewer->update();
277  }
278  });
279  }
280 
281  driver->start();
282  }
283 }
This class uses the provided device to control the provided rigid object via virtual coupling...
Compound Geometry.
static std::shared_ptr< DeviceManager > makeDeviceManager()
Attempts to create a new DeviceManager by whichever is default If multiple haptic managers are built ...
void setText(const std::string &text)
Text to be plotted.
Provides the information of a key event (press, release, & which key)
Color in RGB space.
Definition: imstkColor.h:24
Provides the information of a mouse event, this includes button presses/releases and scrolling...
A SceneBehaviour that can update via a lambda function.
Controls the camera using trackball controls Left click rotate, middle click pan. ...
Renders text to the screen.
Physically based rendering.
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.
void setController(std::shared_ptr< PbdObjectController > controller)
Get/Set the controller to display the device force of.
Displays virtual coupling force text in the top right.