iMSTK
Interactive Medical Simulation Toolkit
RenderingColonExample.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 "imstkImageData.h"
9 #include "imstkKeyboardDeviceClient.h"
10 #include "imstkKeyboardSceneControl.h"
11 #include "imstkLineMesh.h"
12 #include "imstkMeshIO.h"
13 #include "imstkMouseDeviceClient.h"
14 #include "imstkMouseSceneControl.h"
15 #include "imstkNew.h"
16 #include "imstkRenderMaterial.h"
17 #include "imstkScene.h"
18 #include "imstkSceneManager.h"
19 #include "imstkSceneObject.h"
20 #include "imstkSimulationManager.h"
21 #include "imstkSimulationUtils.h"
22 #include "imstkSpotLight.h"
23 #include "imstkSurfaceMesh.h"
24 #include "imstkVecDataArray.h"
25 #include "imstkVisualModel.h"
26 #include "imstkVTKRenderer.h"
27 #include "imstkVTKViewer.h"
28 
29 #include <vtkImageData.h>
30 #include <vtkJPEGReader.h>
31 #include <vtkOpenGLRenderer.h>
32 #include <vtkSkybox.h>
33 #include <vtkTexture.h>
34 
35 using namespace imstk;
36 
41 static Vec3d
42 catmullRom(
43  const Vec3d& p0, const Vec3d& p1,
44  const Vec3d& p2, const Vec3d& p3,
45  const double t)
46 {
47  const double t2 = t * t;
48  const double t3 = t2 * t;
49  return p1 + 0.5 * ((-p0 + p2) * t
50  + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2
51  + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
52 }
53 
58 static Vec3d
59 getSplinePositionFromLineMesh(double dist, std::shared_ptr<LineMesh> lineMesh)
60 {
61  std::shared_ptr<VecDataArray<double, 3>> verticesPtr = lineMesh->getVertexPositions();
62  const VecDataArray<double, 3>& vertices = *verticesPtr;
63  CHECK(vertices.size() >= 2) << "Must have at least 2 vertices";
64  auto vertexDistPtr = std::dynamic_pointer_cast<DataArray<double>>(lineMesh->getVertexAttribute("distances"));
65  const DataArray<double>& vertexDist = *vertexDistPtr;
66  const double startLength = vertexDist[0];
67  const double endLength = vertexDist[vertexDist.size() - 1];
68 
69  // Extrapolates
70  if (dist <= startLength)
71  {
72  const Vec3d m = (vertices[1] - vertices[0]).normalized();
73  return vertices[0] + m * -dist;
74  }
75  if (dist >= endLength)
76  {
77  const Vec3d m = (vertices[vertices.size() - 1] - vertices[vertices.size() - 2]).normalized();
78  return vertices[vertices.size() - 1] + m * dist;
79  }
80 
81  // Find the corresponding segment we are in
82  int j = 0;
83  for (int i = 0; i < vertices.size() - 1; i++)
84  {
85  if (dist > vertexDist[i] && dist <= vertexDist[i + 1])
86  {
87  j = i;
88  break;
89  }
90  }
91 
92  // If the user wants a position at either end make sure to clamp
93  const int i0 = std::max(std::min(j - 1, vertices.size() - 1), 0);
94  const int i1 = std::max(std::min(j, vertices.size() - 1), 0);
95  const int i2 = std::max(std::min(j + 1, vertices.size() - 1), 0);
96  const int i3 = std::max(std::min(j + 2, vertices.size() - 1), 0);
97 
98  // Get the 4 points on the line, with sample
99  // point fractionally between b & c
100  const Vec3d a = vertices[i0];
101  const Vec3d b = vertices[i1];
102  const Vec3d c = vertices[i2];
103  const Vec3d d = vertices[i3];
104 
105  // Compute the fractional distance between b & c
106  const double distb = vertexDist[j];
107  const double distc = vertexDist[j + 1];
108  const double frac = (dist - distb) / (distc - distb);
109 
110  const Vec3d results = catmullRom(a, b, c, d, frac);
111  return results;
112 }
113 
118 int
119 main()
120 {
121  // Write log to stdout and file
123 
124  imstkNew<Scene> scene("RenderingColon");
125  auto colonObject = std::make_shared<SceneObject>("colon");
126  {
127  imstkNew<RenderMaterial> colonMaterial;
128  colonMaterial->setDisplayMode(RenderMaterial::DisplayMode::Surface);
129  colonMaterial->setShadingModel(RenderMaterial::ShadingModel::PBR);
130  auto diffuseTexImg =
131  MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/Organs/Colon/colon_BaseColor.png");
132  colonMaterial->addTexture(std::make_shared<Texture>(diffuseTexImg, Texture::Type::Diffuse));
133  auto normalTexImg =
134  MeshIO::read<ImageData>(iMSTK_DATA_ROOT "/Organs/Colon/colon_Normal.png");
135  colonMaterial->addTexture(std::make_shared<Texture>(normalTexImg, Texture::Type::Normal));
136  colonMaterial->setRecomputeVertexNormals(true);
137  colonMaterial->setBackFaceCulling(true);
138  colonMaterial->setMetalness(0.0);
139  colonMaterial->setRoughness(0.26);
140  colonMaterial->setNormalStrength(5.0);
141  colonMaterial->setOcclusionStrength(0.0);
142 
143  colonMaterial->addTexture(std::make_shared<Texture>(normalTexImg, Texture::Type::CoatNormal));
144  colonMaterial->setCoatRoughness(0.1);
145  colonMaterial->setCoatStrength(1.0);
146  colonMaterial->setCoatColor(Color::White);
147  colonMaterial->setCoatIOR(3.0);
148  colonMaterial->setBaseIOR(3.0);
149  colonMaterial->setCoatNormalScale(0.5);
150  colonMaterial->setEdgeTint(Color::White);
151 
152  auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/Organs/Colon/colon.obj");
153 
154  imstkNew<VisualModel> visualModel;
155  visualModel->setGeometry(surfMesh);
156  visualModel->setRenderMaterial(colonMaterial);
157  colonObject->addVisualModel(visualModel);
158  }
159  scene->addSceneObject(colonObject);
160 
161  auto colonMedialMesh = MeshIO::read<LineMesh>(iMSTK_DATA_ROOT "/Organs/Colon/colonMedialMesh.obj");
162  double totalLength = 0.0;
163  {
164  // Compute lengths to each vertex along the line
165  std::shared_ptr<VecDataArray<double, 3>> verticesPtr = colonMedialMesh->getVertexPositions();
166  const VecDataArray<double, 3>& vertices = *verticesPtr;
167  auto vertexDistPtr = std::make_shared<DataArray<double>>(verticesPtr->size());
168  DataArray<double>& vertexDist = *vertexDistPtr;
169  colonMedialMesh->setVertexScalars("distances", vertexDistPtr);
170  vertexDist[0] = 0.0;
171  for (int i = 1; i < vertices.size(); i++)
172  {
173  const double length = (vertices[i] - vertices[i - 1]).norm();
174  vertexDist[i] = vertexDist[i - 1] + length;
175  }
176  totalLength = vertexDist[vertexDist.size() - 1];
177  }
178 
179  // Lights
180  // Here we use a falloff on the light (via quadratic function)
181  imstkNew<SpotLight> light;
182  light->setSpotAngle(40.0);
183  light->setAttenuationValues(3000.0, 1.0, 0.01);
184  light->setIntensity(10.0);
185  scene->addLight("light", light);
186 
187  // Run the simulation
188  {
189  // Setup a viewer to render in its own thread
190  imstkNew<VTKViewer> viewer;
191  viewer->setActiveScene(scene);
192  viewer->setBackgroundColors(Color::Black);
193  // Enable SSAO
194  Vec3d l, u;
195  scene->computeBoundingBox(l, u);
196  const double sceneSize = (u - l).norm();
197 
198  auto renderConfig = std::make_shared<RendererConfig>();
199  renderConfig->m_ssaoConfig.m_enableSSAO = true;
200  renderConfig->m_ssaoConfig.m_SSAOBlur = true;
201  renderConfig->m_ssaoConfig.m_SSAORadius = 50.0 * sceneSize;
202  renderConfig->m_ssaoConfig.m_SSAOBias = 0.03 * sceneSize;
203  renderConfig->m_ssaoConfig.m_KernelSize = 128;
204  viewer->getActiveRenderer()->setConfig(renderConfig);
205 
206  // Setup a scene manager to advance the scene in its own thread
207  imstkNew<SceneManager> sceneManager;
208  sceneManager->setActiveScene(scene);
209  sceneManager->pause(); // Start simulation paused
210 
212  driver->addModule(viewer);
213  driver->addModule(sceneManager);
214 
215  // Add default mouse and keyboard controls to the viewer
216  std::shared_ptr<Entity> mouseAndKeyControls =
217  SimulationUtils::createDefaultSceneControl(driver);
218  scene->addSceneObject(mouseAndKeyControls);
219 
220  double t = 0.0;
221  std::shared_ptr<Camera> cam = scene->getActiveCamera();
222  {
223  // Initialize the camera
224  const Vec3d eyePos = getSplinePositionFromLineMesh(0.0, colonMedialMesh);
225  const Vec3d focalPt = getSplinePositionFromLineMesh(0.07, colonMedialMesh);
226  cam->setPosition(eyePos);
227  cam->setFocalPoint(focalPt);
228  light->setPosition(eyePos);
229  light->setFocalPoint(focalPt);
230  }
231 
232  // Advance the camera along the line
233  connect<Event>(sceneManager, &SceneManager::postUpdate,
234  [&](Event*)
235  {
236  t += sceneManager->getDt();
237 
238  const double velocity = 0.1;
239  const double dist = std::min(t * velocity, totalLength);
240  const Vec3d eyePos = getSplinePositionFromLineMesh(dist, colonMedialMesh);
241  const Vec3d focalPt = getSplinePositionFromLineMesh(dist + 0.07, colonMedialMesh);
242 
243  cam->setPosition(eyePos);
244  cam->setFocalPoint(focalPt);
245  light->setPosition(eyePos);
246  light->setFocalPoint(focalPt);
247  });
248 
249  connect<Event>(driver, &SimulationManager::starting, [&](Event*)
250  {
251  vtkSmartPointer<vtkRenderer> ren = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer())->getVtkRenderer();
252  vtkSmartPointer<vtkOpenGLRenderer> oRen = vtkOpenGLRenderer::SafeDownCast(ren);
253  vtkNew<vtkJPEGReader> reader;
254  reader->SetFileName(iMSTK_DATA_ROOT "/Organs/Colon/colon_irradiance_environment_map.jpg");
255  reader->Update();
256 
257  vtkNew<vtkTexture> texture;
258  // Enable mipmapping to handle HDR image
259  texture->MipmapOn();
260  texture->InterpolateOn();
261  texture->SetInputData(reader->GetOutput());
262  texture->SetColorModeToDirectScalars();
263  texture->SetCubeMap(false);
264  texture->Update();
265 
266  /* vtkNew<vtkSkybox> skybox;
267  skybox->SetTexture(texture);
268  ren->AddActor(skybox);*/
269 
270  ren->AutomaticLightCreationOff();
271  oRen->UseSphericalHarmonicsOff();
272  ren->UseImageBasedLightingOn();
273  ren->SetEnvironmentTexture(texture);
274  });
275 
276  driver->start();
277  }
278 
279  return 0;
280 }
void addTexture(std::shared_ptr< Texture > texture)
Add/Remove/Get texture.
void setActiveScene(std::shared_ptr< Scene > scene) override
Set scene to be rendered.
Base class for events which contain a type, priority, and data priority defaults to 0 and uses a grea...
void setAttenuationValues(const double a, const double b, const double c)
Sets the attenuation values. Quadratic, linear, and constant c (ax^2+bx+c) (a,b,c) = {0...
Definition: imstkLight.h:77
Compound Geometry.
void addModule(std::shared_ptr< Module > module) override
Add a module to run.
virtual void setBackgroundColors(const Color color1, const Color color2=Color(0.0, 0.0, 0.0), const bool gradientBackground=false) override
Set the coloring of the screen background If &#39;gradientBackground&#39; is false or not supplied color1 wil...
void setIntensity(const double intensity)
Set the light intensity. This value is unbounded.
Definition: imstkLight.h:71
double getDt() const
Get/Set the time step.
Definition: imstkModule.h:63
std::shared_ptr<T> obj = std::make_shared<T>(); equivalent, convenience class for STL shared allocati...
Definition: imstkNew.h:29
std::shared_ptr< Renderer > getActiveRenderer() const
Retrieve the renderer associated with the current scene.
Definition: imstkViewer.cpp:38
static Color White
Various commonly used colors.
Definition: imstkColor.h:112
void setSpotAngle(const double angle)
Set the spotlight angle in degrees.
void setFocalPoint(const Vec3d &p)
Get/Set the light focal point.
Definition: imstkLight.h:33
void setActiveScene(std::string newSceneName)
Sets the currently updating scene.
Physically based rendering.
Wraps a vtkRenderer.
static LoggerG3 & startLogger()
Starts logger with default sinks, use getInstance to create a logger with no sinks.