iMSTK
Interactive Medical Simulation Toolkit
PBDThinTissueContactExample.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 "imstkDirectionalLight.h"
9 #include "imstkGeometryUtilities.h"
10 #include "imstkImageData.h"
11 #include "imstkKeyboardDeviceClient.h"
12 #include "imstkKeyboardSceneControl.h"
13 #include "imstkMeshIO.h"
14 #include "imstkMouseDeviceClient.h"
15 #include "imstkMouseSceneControl.h"
16 #include "imstkPbdModel.h"
17 #include "imstkPbdModelConfig.h"
18 #include "imstkPbdObject.h"
19 #include "imstkPbdObjectCollision.h"
20 #include "imstkRenderMaterial.h"
21 #include "imstkScene.h"
22 #include "imstkSceneManager.h"
23 #include "imstkSimulationManager.h"
24 #include "imstkSimulationUtils.h"
25 #include "imstkVisualModel.h"
26 #include "imstkVTKViewer.h"
27 
28 #ifdef iMSTK_USE_HAPTICS
29 #include "imstkDeviceManager.h"
30 #include "imstkDeviceManagerFactory.h"
31 #endif
32 
33 using namespace imstk;
34 
38 static std::shared_ptr<PbdObject>
39 makeTissueObj(const std::string& name,
40  const double width,
41  const double height,
42  const int rowCount,
43  const int colCount)
44 {
45  // Setup the Geometry
46  std::shared_ptr<SurfaceMesh> clothMesh =
47  GeometryUtils::toTriangleGrid(Vec3d::Zero(),
48  Vec2d(width, height), Vec2i(rowCount, colCount));
49 
50  // Setup the Parameters
51  auto pbdParams = std::make_shared<PbdModelConfig>();
52  pbdParams->enableConstraint(PbdModelConfig::ConstraintGenType::Distance, 5000.0);
53  pbdParams->enableConstraint(PbdModelConfig::ConstraintGenType::Dihedral, 5000.0);
54  pbdParams->m_gravity = Vec3d(0.0, -20.0, 0.0); // Slightly larger gravity to compensate viscosity
55  pbdParams->m_dt = 0.005;
56  pbdParams->m_iterations = 2;
57  pbdParams->m_linearDampingCoeff = 0.0;
58 
59  // Setup the Model
60  auto pbdModel = std::make_shared<PbdModel>();
61  pbdModel->configure(pbdParams);
62 
63  // Setup the VisualModel
64  auto material = std::make_shared<RenderMaterial>();
65  material->setBackFaceCulling(false);
66  material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
67  material->setShadingModel(RenderMaterial::ShadingModel::PBR);
68  auto diffuseTex = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/textures/fleshDiffuse.jpg");
69  material->addTexture(std::make_shared<Texture>(diffuseTex, Texture::Type::Diffuse));
70  auto normalTex = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/textures/fleshNormal.jpg");
71  material->addTexture(std::make_shared<Texture>(normalTex, Texture::Type::Normal));
72  auto ormTex = MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/textures/fleshORM.jpg");
73  material->addTexture(std::make_shared<Texture>(ormTex, Texture::Type::ORM));
74 
75  auto visualModel = std::make_shared<VisualModel>();
76  visualModel->setGeometry(clothMesh);
77  visualModel->setRenderMaterial(material);
78 
79  // Setup the Object
80  auto pbdObject = std::make_shared<PbdObject>(name);
81  pbdObject->addVisualModel(visualModel);
82  pbdObject->setPhysicsGeometry(clothMesh);
83  pbdObject->setCollidingGeometry(clothMesh);
84  pbdObject->setDynamicalModel(pbdModel);
85  pbdObject->getPbdBody()->uniformMassValue = width * height / (rowCount * colCount);
86  for (int x = 0; x < rowCount; x++)
87  {
88  for (int y = 0; y < colCount; y++)
89  {
90  if (x == 0 || y == 0 || x == rowCount - 1 || y == colCount - 1)
91  {
92  pbdObject->getPbdBody()->fixedNodeIds.push_back(x * colCount + y);
93  }
94  }
95  }
96 
97  return pbdObject;
98 }
99 
104 int
105 main()
106 {
107  // Setup logger (write to file and stdout)
109 
110  // Setup the scene
111  auto scene = std::make_shared<Scene>("PbdThinTissueContact");
112  scene->getActiveCamera()->setPosition(0.12, 4.51, 16.51);
113  scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
114  scene->getActiveCamera()->setViewUp(0.0, 0.96, -0.28);
115 
116  // Setup a tissue
117  std::shared_ptr<PbdObject> tissueObj = makeTissueObj("Tissue", 10.0, 10.0, 16, 16);
118  scene->addSceneObject(tissueObj);
119 
120  // Setup the tool to press the tissue
121  auto toolGeom = std::make_shared<LineMesh>();
122  VecDataArray<double, 3> vertices = { Vec3d(0.0, 0.0, 0.0), Vec3d(0.0, 2.0, 0.0) };
123  VecDataArray<int, 2> cells = { Vec2i(0, 1) };
124  toolGeom->initialize(
125  std::make_shared<VecDataArray<double, 3>>(vertices),
126  std::make_shared<VecDataArray<int, 2>>(cells));
127 
128  auto toolObj = std::make_shared<CollidingObject>("Tool");
129  toolObj->setVisualGeometry(toolGeom);
130  toolObj->setCollidingGeometry(toolGeom);
131  toolObj->getVisualModel(0)->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::Wireframe);
132  toolObj->getVisualModel(0)->getRenderMaterial()->setLineWidth(5.0);
133  toolObj->getVisualModel(0)->getRenderMaterial()->setRecomputeVertexNormals(false);
134  toolObj->getVisualModel(0)->getRenderMaterial()->setBackFaceCulling(false);
135  scene->addSceneObject(toolObj);
136 
137  // Add a collision interaction between the tools
138  scene->addInteraction(std::make_shared<PbdObjectCollision>(tissueObj, toolObj));
139 
140  // Light
141  auto light = std::make_shared<DirectionalLight>();
142  light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
143  light->setIntensity(1.0);
144  scene->addLight("Light", light);
145 
146  // Run the simulation
147  {
148  // Setup a viewer to render
149  auto viewer = std::make_shared<VTKViewer>();
150  viewer->setVtkLoggerMode(VTKViewer::VTKLoggerMode::MUTE);
151  viewer->setActiveScene(scene);
152 
153  // Setup a scene manager to advance the scene
154  auto sceneManager = std::make_shared<SceneManager>();
155  sceneManager->setActiveScene(scene);
156  sceneManager->pause(); // Start simulation paused
157 
158  auto driver = std::make_shared<SimulationManager>();
159  driver->setDesiredDt(0.005);
160  driver->addModule(viewer);
161  driver->addModule(sceneManager);
162 
163 #ifdef iMSTK_USE_HAPTICS
164  // Setup default haptics manager
165  std::shared_ptr<DeviceManager> hapticManager = DeviceManagerFactory::makeDeviceManager();
166  std::shared_ptr<DeviceClient> deviceClient = hapticManager->makeDeviceClient();
167  driver->addModule(hapticManager);
168 
169  Mat3d rotationalOffset = Mat3d::Identity();
170  connect<Event>(sceneManager, SceneManager::preUpdate, [&](Event*)
171  {
172  const Quatd deviceOrientation = (Quatd(rotationalOffset) * deviceClient->getOrientation()).normalized();
173  const Vec3d devicePosition = (rotationalOffset * deviceClient->getPosition()) * 50.0 + Vec3d(0.0, 0.0, 0.0);
174  toolGeom->setRotation(deviceOrientation);
175  toolGeom->setTranslation(devicePosition);
176  toolGeom->postModified();
177  });
178 #else
179  connect<Event>(sceneManager, &SceneManager::preUpdate, [&](Event*)
180  {
181  const Vec2d mousePos = viewer->getMouseDevice()->getPos();
182  const Vec3d worldPos = Vec3d(mousePos[0] - 0.5, mousePos[1] - 0.5, 0.0) * 10.0 + Vec3d(0.5, 2.0, 0.5);
183 
184  toolGeom->setTranslation(worldPos);
185  toolGeom->postModified();
186  });
187 #endif
188 
189  // Add default mouse and keyboard controls to the viewer
190  std::shared_ptr<Entity> mouseAndKeyControls =
191  SimulationUtils::createDefaultSceneControl(driver);
192  scene->addSceneObject(mouseAndKeyControls);
193 
194  driver->start();
195  }
196 
197  return 0;
198 }
std::shared_ptr< SurfaceMesh > toTriangleGrid(const Vec3d &center, const Vec2d &size, const Vec2i &dim, const Quatd orientation=Quatd::Identity(), const double uvScale=1.0)
Produces a triangle grid on a plane given the imstkPlane.
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
Compound Geometry.
static std::shared_ptr< DeviceManager > makeDeviceManager()
Attempts to create a new DeviceManager by whichever is default If multiple haptic managers are built ...
Physically based rendering.
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.