Commit 614e296e authored by Andrew Wilson's avatar Andrew Wilson
Browse files

ENH: RenderDelegate to render face normals from windings

parent f3fa0d62
......@@ -112,17 +112,21 @@ makeClothObj(const std::string& name, double width, double height, int nRows, in
pbdModel->setModelGeometry(clothMesh);
pbdModel->configure(pbdParams);
// Setup the VisualModel
imstkNew<RenderMaterial> material;
material->setBackFaceCulling(false);
material->setColor(Color::LightGray);
material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
auto clothVisualModel = std::make_shared<VisualModel>(clothMesh);
clothVisualModel->setRenderMaterial(material);
// Setup visual models
imstkNew<VisualModel> clothModel;
clothModel->setGeometry(clothMesh);
clothModel->getRenderMaterial()->setBackFaceCulling(false);
clothModel->getRenderMaterial()->setColor(Color::LightGray);
clothModel->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
imstkNew<VisualModel> clothSurfaceNormals;
clothSurfaceNormals->setGeometry(clothMesh);
clothSurfaceNormals->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::SurfaceNormals);
clothSurfaceNormals->getRenderMaterial()->setPointSize(0.5);
// Setup the Object
clothObj->addVisualModel(clothVisualModel);
clothObj->addVisualModel(clothModel);
clothObj->addVisualModel(clothSurfaceNormals);
clothObj->setPhysicsGeometry(clothMesh);
clothObj->setDynamicalModel(pbdModel);
......
......@@ -13,6 +13,7 @@ set(VTK_H_FILES
VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h
VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h
VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h
VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.h
VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h
VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h
VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h
......@@ -34,6 +35,7 @@ set(VTK_CPP_FILES
VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.cpp
VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp
VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp
VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
......
......@@ -49,7 +49,8 @@ public:
WireframeSurface,
VolumeRendering,
Fluid, ///< Renders a set of points using a screen-space fluid renderer
Image
Image,
SurfaceNormals
};
/// surface shading model. Defaults to Phong
......
......@@ -36,6 +36,7 @@
#include "imstkVTKCubeRenderDelegate.h"
#include "imstkVTKCylinderRenderDelegate.h"
#include "imstkVTKFluidRenderDelegate.h"
#include "imstkVTKSurfaceNormalRenderDelegate.h"
#include "imstkVTKHexahedralMeshRenderDelegate.h"
#include "imstkVTKImageDataRenderDelegate.h"
#include "imstkVTKLineMeshRenderDelegate.h"
......@@ -73,6 +74,7 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
{
const std::string geomType = visualModel->getGeometry()->getTypeName();
// Two edge cases
if (visualModel->getRenderMaterial()->getDisplayMode() == RenderMaterial::DisplayMode::Fluid)
{
if (std::dynamic_pointer_cast<PointSet>(visualModel->getGeometry()) != nullptr)
......@@ -80,14 +82,17 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
return std::make_shared<VTKFluidRenderDelegate>(visualModel);
}
}
if (visualModel->getGeometry()->isMesh())
if (visualModel->getRenderMaterial()->getDisplayMode() == RenderMaterial::DisplayMode::SurfaceNormals)
{
if (geomType == "PointSet")
if (std::dynamic_pointer_cast<PointSet>(visualModel->getGeometry()) != nullptr)
{
return std::make_shared<VTKPointSetRenderDelegate>(visualModel);
return std::make_shared<VTKSurfaceNormalRenderDelegate>(visualModel);
}
else if (geomType == "SurfaceMesh")
}
if (visualModel->getGeometry()->isMesh())
{
if (geomType == "SurfaceMesh")
{
return std::make_shared<VTKSurfaceMeshRenderDelegate>(visualModel);
}
......@@ -106,7 +111,11 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
}
else
{
if (geomType == "Plane")
if (geomType == "PointSet")
{
return std::make_shared<VTKPointSetRenderDelegate>(visualModel);
}
else if (geomType == "Plane")
{
return std::make_shared<VTKPlaneRenderDelegate>(visualModel);
}
......@@ -161,7 +170,7 @@ VTKRenderDelegate::makeDebugDelegate(std::shared_ptr<VisualModel> dbgVizModel)
}
default:
{
LOG(FATAL) << "error: Geometry type incorrect/unsupported";
LOG(FATAL) << "RenderDelegate::makeDebugDelegate error: Geometry type incorrect.";
return nullptr; // will never be reached
}
}
......
/*=========================================================================
Library: iMSTK
Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
& Imaging in Medicine, Rensselaer Polytechnic Institute.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.txt
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/
#include "imstkVTKSurfaceNormalRenderDelegate.h"
#include "imstkPointSet.h"
#include "imstkVisualModel.h"
#include "imstkGeometryUtilities.h"
#include "imstkRenderMaterial.h"
#include "imstkLogger.h"
#include "imstkSurfaceMesh.h"
#include <vtkActor.h>
#include <vtkDataArray.h>
#include <vtkPointData.h>
#include <vtkTransform.h>
#include <vtkArrowSource.h>
#include <vtkOpenGLGlyph3DMapper.h>
namespace imstk
{
VTKSurfaceNormalRenderDelegate::VTKSurfaceNormalRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel),
m_polydata(vtkSmartPointer<vtkPolyData>::New())
{
auto surfMesh = std::static_pointer_cast<SurfaceMesh>(visualModel->getGeometry());
m_surfMeshVertices = surfMesh->getVertexPositions();
m_surfMeshIndices = surfMesh->getTriangleIndices();
// Compute the centers of the triangle
m_triangleCenterVertices = computeTriangleCenters(m_surfMeshVertices, m_surfMeshIndices);
m_triangleNormals = computeTriangleNormals(m_surfMeshVertices, m_surfMeshIndices);
// Map vertices to VTK point data
if (m_surfMeshVertices != nullptr)
{
m_mappedVertexArray = GeometryUtils::coupleVtkDataArray(m_triangleCenterVertices);
auto points = vtkSmartPointer<vtkPoints>::New();
points->SetNumberOfPoints(m_triangleCenterVertices->size());
points->SetData(m_mappedVertexArray);
m_polydata->SetPoints(points);
}
m_mappedNormalsArray = GeometryUtils::coupleVtkDataArray(m_triangleNormals);
m_mappedNormalsArray->SetName("ImageScalars");
m_polydata->GetPointData()->SetVectors(m_mappedNormalsArray);
// When geometry is modified, update data source, mostly for when an entirely new array/buffer was set
queueConnect<Event>(surfMesh, &Geometry::modified, this, &VTKSurfaceNormalRenderDelegate::geometryModified);
// When the vertex buffer internals are modified, ie: a single or N elements
queueConnect<Event>(m_surfMeshVertices, &AbstractDataArray::modified, this, &VTKSurfaceNormalRenderDelegate::vertexDataModified);
// Setup mapper
{
vtkNew<vtkArrowSource> arrowSource;
arrowSource->Update();
m_glyphPolyData = arrowSource->GetOutput();
vtkNew<vtkOpenGLGlyph3DMapper> mapper;
mapper->OrientOn();
mapper->SetInputData(m_polydata);
mapper->SetSourceData(m_glyphPolyData);
mapper->SetOrientationArray(m_mappedNormalsArray->GetName());
mapper->ScalingOn();
mapper->SetScaleFactor(visualModel->getRenderMaterial()->getPointSize());
mapper->Update();
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
actor->SetUserTransform(m_transform);
m_mapper = mapper;
m_actor = actor;
}
update();
updateRenderProperties();
}
void
VTKSurfaceNormalRenderDelegate::processEvents()
{
// Custom handling of events
std::shared_ptr<PointSet> geom = std::dynamic_pointer_cast<PointSet>(m_visualModel->getGeometry());
std::shared_ptr<VecDataArray<double, 3>> vertices = geom->getVertexPositions();
// Only use the most recent event from respective sender
std::list<Command> cmds;
bool contains[4] = { false, false, false, false };
rforeachEvent([&](Command cmd)
{
if (cmd.m_event->m_sender == m_visualModel.get() && !contains[0])
{
cmds.push_back(cmd);
contains[0] = true;
}
else if (cmd.m_event->m_sender == m_material.get() && !contains[1])
{
cmds.push_back(cmd);
contains[1] = true;
}
else if (cmd.m_event->m_sender == geom.get() && !contains[2])
{
cmds.push_back(cmd);
contains[2] = true;
}
else if (cmd.m_event->m_sender == vertices.get() && !contains[3])
{
cmds.push_back(cmd);
contains[3] = true;
}
});
// Now do each event in order recieved
for (std::list<Command>::reverse_iterator i = cmds.rbegin(); i != cmds.rend(); i++)
{
i->invoke();
}
}
void
VTKSurfaceNormalRenderDelegate::vertexDataModified(Event* imstkNotUsed(e))
{
auto geometry = std::static_pointer_cast<SurfaceMesh>(m_visualModel->getGeometry());
m_surfMeshVertices = geometry->getVertexPositions();
// Compute the centers of the triangle
m_triangleCenterVertices = computeTriangleCenters(m_surfMeshVertices, m_surfMeshIndices);
m_triangleNormals = computeTriangleNormals(m_surfMeshVertices, m_surfMeshIndices);
m_mappedVertexArray->SetNumberOfComponents(3);
m_mappedVertexArray->SetVoidArray(reinterpret_cast<double*>(m_triangleCenterVertices->getPointer()), m_triangleCenterVertices->size() * 3, 1);
m_mappedVertexArray->Modified();
m_mappedNormalsArray->SetNumberOfComponents(3);
m_mappedNormalsArray->SetVoidArray(reinterpret_cast<double*>(m_triangleNormals->getPointer()), m_triangleNormals->size() * 3, 1);
m_mappedNormalsArray->Modified();
}
void
VTKSurfaceNormalRenderDelegate::geometryModified(Event* imstkNotUsed(e))
{
// Called when the geometry posts modified
auto geometry = std::static_pointer_cast<PointSet>(m_visualModel->getGeometry());
// Test if the vertex buffer changed
//if (m_surfMeshVertices != geometry->getVertexPositions())
{
vertexDataModified(nullptr);
}
}
void
VTKSurfaceNormalRenderDelegate::updateRenderProperties()
{
VTKPolyDataRenderDelegate::updateRenderProperties();
vtkOpenGLGlyph3DMapper::SafeDownCast(m_mapper)->SetScaleFactor(m_visualModel->getRenderMaterial()->getPointSize());
}
std::shared_ptr<VecDataArray<double, 3>>
VTKSurfaceNormalRenderDelegate::computeTriangleCenters(
std::shared_ptr<VecDataArray<double, 3>> verticesPtr,
std::shared_ptr<VecDataArray<int, 3>> indicesPtr)
{
auto newVerticesPtr = std::make_shared<VecDataArray<double, 3>>(indicesPtr->size());
VecDataArray<double, 3>& newVertices = *newVerticesPtr;
VecDataArray<double, 3>& vertices = *verticesPtr;
VecDataArray<int, 3>& indices = *indicesPtr;
const double ratio = 1.0 / 3.0;
for (int i = 0; i < indices.size(); i++)
{
const Vec3d& a = vertices[indices[i][0]];
const Vec3d& b = vertices[indices[i][1]];
const Vec3d& c = vertices[indices[i][2]];
newVertices[i] = (a + b + c) * ratio;
}
return newVerticesPtr;
}
std::shared_ptr<VecDataArray<double, 3>>
VTKSurfaceNormalRenderDelegate::computeTriangleNormals(
std::shared_ptr<VecDataArray<double, 3>> verticesPtr,
std::shared_ptr<VecDataArray<int, 3>> indicesPtr)
{
auto orientationsPtr = std::make_shared<VecDataArray<double, 3>>(indicesPtr->size());
VecDataArray<double, 3>& orientations = *orientationsPtr;
VecDataArray<double, 3>& vertices = *verticesPtr;
VecDataArray<int, 3>& indices = *indicesPtr;
for (int i = 0; i < indices.size(); i++)
{
const Vec3d& a = vertices[indices[i][0]];
const Vec3d& b = vertices[indices[i][1]];
const Vec3d& c = vertices[indices[i][2]];
orientations[i] = (c - a).cross(c - b).normalized();
}
return orientationsPtr;
}
} // imstk
/*=========================================================================
Library: iMSTK
Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
& Imaging in Medicine, Rensselaer Polytechnic Institute.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.txt
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/
#pragma once
#include "imstkVTKPolyDataRenderDelegate.h"
class vtkDataArray;
class vtkPolyData;
namespace imstk
{
class PointSet;
template<typename T, int N> class VecDataArray;
///
/// \class VTKSurfaceNormalRenderDelegate
///
/// \brief Renders normals as vectors from a surface mesh
///
class VTKSurfaceNormalRenderDelegate : public VTKPolyDataRenderDelegate
{
public:
///
/// \brief Constructor
///
VTKSurfaceNormalRenderDelegate(std::shared_ptr<VisualModel> visualModel);
///
/// \brief Destructor
///
virtual ~VTKSurfaceNormalRenderDelegate() override = default;
///
/// \brief Update polydata source based on the mesh geometry
///
void processEvents() override;
protected:
///
/// \brief Callback for when vertex data changes
///
void vertexDataModified(Event* e);
///
/// \brief Callback for when geometry changes
///
void geometryModified(Event* e);
///
/// \brief Updates the actor and mapper properties from the currently set VisualModel
///
virtual void updateRenderProperties() override;
///
/// \brief Computes triangle centers from the current geometry
///
std::shared_ptr<VecDataArray<double, 3>> computeTriangleCenters(
std::shared_ptr<VecDataArray<double, 3>> verticesPtr,
std::shared_ptr<VecDataArray<int, 3>> indicesPtr);
std::shared_ptr<VecDataArray<double, 3>> computeTriangleNormals(
std::shared_ptr<VecDataArray<double, 3>> verticesPtr,
std::shared_ptr<VecDataArray<int, 3>> indicesPtr);
protected:
std::shared_ptr<VecDataArray<double, 3>> m_surfMeshVertices;
std::shared_ptr<VecDataArray<int, 3>> m_surfMeshIndices;
std::shared_ptr<VecDataArray<double, 3>> m_triangleCenterVertices;
std::shared_ptr<VecDataArray<double, 3>> m_triangleNormals;
vtkSmartPointer<vtkPolyData> m_polydata;
vtkSmartPointer<vtkPolyData> m_glyphPolyData;
vtkSmartPointer<vtkDataArray> m_mappedVertexArray; ///> Mapped array of vertices
vtkSmartPointer<vtkDataArray> m_mappedNormalsArray; ///> Mapped array of orientations
};
}
......@@ -46,6 +46,10 @@ VisualModel::VisualModel(std::shared_ptr<DebugRenderGeometry> geometry,
{
}
VisualModel::VisualModel() : m_renderMaterial(std::make_shared<RenderMaterial>())
{
}
bool
VisualModel::getRenderDelegateCreated(Renderer* ren)
{
......
......@@ -51,7 +51,7 @@ public:
VisualModel(std::shared_ptr<DebugRenderGeometry> geometry);
VisualModel(std::shared_ptr<DebugRenderGeometry> geometry,
std::shared_ptr<RenderMaterial> renderMaterial);
VisualModel() = default;
VisualModel();
virtual ~VisualModel() override = default;
public:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment