Commit d9e125e4 authored by Sreekanth Arikatla's avatar Sreekanth Arikatla

Merge branch 'lineMeshRendering' into 'master'

Line mesh rendering

See merge request iMSTK/iMSTK!232
parents e7eacc0a 38041705
###########################################################################
#
# Copyright (c) Kitware, Inc.
#
# 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.
#
###########################################################################
project(Example-LineMesh)
#-----------------------------------------------------------------------------
# Create executable
#-----------------------------------------------------------------------------
add_executable(${PROJECT_NAME} LineMesh.cpp)
#-----------------------------------------------------------------------------
# Add shaders
#-----------------------------------------------------------------------------
include(imstkCopyAndCompileShaders)
CopyAndCompileShaders()
#-----------------------------------------------------------------------------
# Link libraries to executable
#-----------------------------------------------------------------------------
target_link_libraries(${PROJECT_NAME} SimulationManager)
\ No newline at end of file
/*=========================================================================
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 "imstkSimulationManager.h"
#include "imstkMeshIO.h"
#include "imstkPbdObject.h"
#include "imstkPbdSolver.h"
#include "imstkOneToOneMap.h"
#include "imstkAPIUtilities.h"
#include "imstkLineMesh.h"
using namespace imstk;
///
/// \brief This example demonstrates line mesh rendering
///
int main()
{
// SDK and Scene
auto sdk = std::make_shared<SimulationManager>();
auto scene = sdk->createNewScene("LineMeshRenderingTest");
// Construct line mesh
auto lineMesh = std::make_shared<LineMesh>();
auto lineMeshMaterial = std::make_shared<RenderMaterial>();
lineMeshMaterial->setLineWidth(3);
auto lineObject = std::make_shared<VisualObject>("lineMesh");
std::vector<LineMesh::LineArray> lines;
StdVectorOfVec3d points;
std::vector<Color> colors;
size_t resolution = 16;
size_t numVoxels = resolution * resolution * resolution;
points.resize(numVoxels * 8);
colors.resize(numVoxels * 8);
lines.resize(numVoxels * 12);
size_t index = 0;
size_t lineIndex = 0;
for (int z = 0; z < resolution; z++)
{
for (int y = 0; y < resolution; y++)
{
for (int x = 0; x < resolution; x++)
{
Color color = Color((float)x / resolution, (float)y / resolution, (float)z / resolution);
points[index + 0] = Vec3d(x, y, z);
points[index + 1] = Vec3d(x, y, z+1);
points[index + 2] = Vec3d(x, y+1, z);
points[index + 3] = Vec3d(x, y+1, z+1);
points[index + 4] = Vec3d(x+1, y, z);
points[index + 5] = Vec3d(x+1, y, z+1);
points[index + 6] = Vec3d(x+1, y+1, z);
points[index + 7] = Vec3d(x+1, y+1, z+1);
colors[index + 0] = color;
colors[index + 1] = color;
colors[index + 2] = color;
colors[index + 3] = color;
colors[index + 4] = color;
colors[index + 5] = color;
colors[index + 6] = color;
colors[index + 7] = color;
lines[lineIndex + 0][0] = index + 0;
lines[lineIndex + 0][1] = index + 1;
lines[lineIndex + 1][0] = index + 2;
lines[lineIndex + 1][1] = index + 3;
lines[lineIndex + 2][0] = index + 4;
lines[lineIndex + 2][1] = index + 5;
lines[lineIndex + 3][0] = index + 6;
lines[lineIndex + 3][1] = index + 7;
lines[lineIndex + 4][0] = index + 0;
lines[lineIndex + 4][1] = index + 2;
lines[lineIndex + 5][0] = index + 1;
lines[lineIndex + 5][1] = index + 3;
lines[lineIndex + 6][0] = index + 4;
lines[lineIndex + 6][1] = index + 6;
lines[lineIndex + 7][0] = index + 5;
lines[lineIndex + 7][1] = index + 7;
lines[lineIndex + 8][0] = index + 0;
lines[lineIndex + 8][1] = index + 4;
lines[lineIndex + 9][0] = index + 1;
lines[lineIndex + 9][1] = index + 5;
lines[lineIndex + 10][0] = index + 2;
lines[lineIndex + 10][1] = index + 6;
lines[lineIndex + 11][0] = index + 3;
lines[lineIndex + 11][1] = index + 7;
index += 8;
lineIndex += 12;
}
}
}
lineMesh->initialize(points, lines);
lineMesh->setVertexColors(colors);
lineMesh->setRenderMaterial(lineMeshMaterial);
auto camera = scene->getCamera();
camera->setPosition(resolution / 2.0, resolution / 2.0, resolution * 4.0);
camera->setFocalPoint(resolution / 2.0, resolution / 2.0, resolution / 2.0);
lineObject->setVisualGeometry(lineMesh);
scene->addSceneObject(lineObject);
// Start simulation
sdk->setActiveScene(scene);
sdk->startSimulation();
}
......@@ -91,7 +91,7 @@ int main()
auto material = std::make_shared<RenderMaterial>();
material->setBackFaceCulling(false);
material->setDiffuseColor(Color::LightGray);
material->setColor(Color::LightGray);
material->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE);
surfMesh->setRenderMaterial(material);
......
......@@ -51,7 +51,7 @@ int main()
fluidMesh->initialize(tetMesh->getInitialVertexPositions());
auto material1 = std::make_shared<RenderMaterial>();
material1->setDiffuseColor(Color::Blue);
material1->setColor(Color::Blue);
material1->setSphereGlyphSize(.15);
fluidMesh->setRenderMaterial(material1);
......
......@@ -85,7 +85,7 @@ int main()
// Plane
auto planeObj = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Plane, scene, "VisualPlane", 10);
auto planeMaterial = std::make_shared<RenderMaterial>();
planeMaterial->setDiffuseColor(Color::DarkGray);
planeMaterial->setColor(Color::DarkGray);
planeObj->getVisualGeometry()->setRenderMaterial(planeMaterial);
// Run
......
......@@ -46,7 +46,7 @@ int main()
// set configure Obj1 rendering
auto matObj1 = std::make_shared<RenderMaterial>();
matObj1->setBackFaceCulling(false);
matObj1->setDiffuseColor(Color::Green);
matObj1->setColor(Color::Green);
matObj1->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE);
mesh1->setRenderMaterial(matObj1);
......@@ -59,7 +59,7 @@ int main()
// set configure Obj2 rendering
auto matObj2 = std::make_shared<RenderMaterial>();
matObj2->setBackFaceCulling(false);
matObj2->setDiffuseColor(Color::Green);
matObj2->setColor(Color::Green);
matObj2->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE);
mesh2->setRenderMaterial(matObj2);
......
......@@ -107,7 +107,7 @@ PbdInteractionPair::doNarrowPhaseCollision()
for (int k = 0; k < nL1; ++k)
{
auto nodes = mesh1->getLine(k);
auto nodes = mesh1->getLinesVertices()[k];
unsigned int i1 = nodes[0];
unsigned int i2 = nodes[1];
......
......@@ -25,9 +25,22 @@
namespace imstk
{
void
LineMesh::initialize(const StdVectorOfVec3d& vertices,
const std::vector<LineArray>& lines)
{
this->clear();
PointSet::initialize(vertices);
this->setLinesVertices(lines);
}
void
LineMesh::clear()
{
m_lines.clear();
m_vertexColors.clear();
}
void
......@@ -43,9 +56,37 @@ LineMesh::getVolume() const
}
void
LineMesh::setConnectivity(const std::vector<std::vector<int>>& lines)
LineMesh::setVertexColors(const std::vector<Color>& colors)
{
m_lines = lines;
if (colors.size() <= m_maxNumVertices)
{
m_vertexColors = colors;
}
else
{
LOG(WARNING) << "Vertex colors not set, exceeded maximum number of vertices";
}
}
void
LineMesh::setLinesVertices(const std::vector<LineArray>& lines)
{
if (m_originalNumLines == 0)
{
m_originalNumLines = lines.size();
m_maxNumLines = (size_t)(m_originalNumLines * m_loadFactor);
m_lines.reserve(m_maxNumLines);
}
if (lines.size() <= m_maxNumLines)
{
m_topologyChanged = true;
m_lines = lines;
}
else
{
LOG(WARNING) << "Lines not set, exceeded maximum number of lines";
}
}
size_t
......@@ -54,15 +95,15 @@ LineMesh::getNumLines()
return m_lines.size();
}
std::vector<std::vector<int>>
LineMesh::getLines() const
std::vector<LineMesh::LineArray>
LineMesh::getLinesVertices() const
{
return m_lines;
}
std::vector<int>
LineMesh::getLine(int index) const
std::vector<Color>
LineMesh::getVertexColors() const
{
return m_lines[index];
return m_vertexColors;
}
} // imstk
......@@ -23,6 +23,7 @@
#define imstkLineMesh_h
#include <memory>
#include <array>
#include "imstkPointSet.h"
......@@ -38,6 +39,8 @@ class LineMesh : public PointSet
{
public:
using LineArray = std::array<size_t, 2>;
///
/// \brief Constructor
///
......@@ -48,6 +51,13 @@ public:
///
~LineMesh() = default;
///
/// \brief Initializes the rest of the data structures given vertex positions and
/// line connectivity
///
void initialize(const StdVectorOfVec3d& vertices,
const std::vector<LineArray>& lines);
///
/// \brief
///
......@@ -66,7 +76,12 @@ public:
///
/// \brief
///
void setConnectivity(const std::vector<std::vector<int>>& lines);
void setVertexColors(const std::vector<Color>& colors);
///
/// \brief
///
void setLinesVertices(const std::vector<LineArray>& lines);
///
/// \brief
......@@ -76,18 +91,22 @@ public:
///
/// \brief
///
std::vector<std::vector<int>> getLines() const;
std::vector<LineArray> getLinesVertices() const;
///
/// \brief
///
std::vector<int> getLine(int index) const;
std::vector<Color> getVertexColors() const;
private:
friend class VTKLineMeshRenderDelegate;
std::vector<std::vector<int>> m_lines; ///> line connectivity
size_t m_originalNumLines = 0;
size_t m_maxNumLines = 0;
std::vector<LineArray> m_lines; ///> line connectivity
std::vector<Color> m_vertexColors;
};
} // imstk
......
......@@ -218,6 +218,17 @@ PointSet::getPointDataArray(const std::string& arrayName) const
return &(it->second);
}
bool
PointSet::hasPointDataArray(const std::string& arrayName) const
{
auto it = m_pointDataMap.find(arrayName);
if (it == m_pointDataMap.end())
{
return false;
}
return true;
}
size_t
PointSet::getNumVertices() const
{
......
......@@ -144,6 +144,11 @@ public:
///
const StdVectorOfVectorf* getPointDataArray(const std::string& arrayName) const;
///
/// \brief Check if a specific data array exists.
///
bool hasPointDataArray(const std::string& arrayName) const;
///
/// \brief Returns the number of total vertices in the mesh
///
......
......@@ -62,6 +62,7 @@ SurfaceMesh::clear()
m_vertexNeighborVertices.clear();
m_triangleNormals.clear();
m_vertexNormals.clear();
m_triangleTangents.clear();
}
void
......@@ -135,6 +136,7 @@ void
SurfaceMesh::computeTrianglesNormals()
{
m_triangleNormals.resize(m_trianglesVertices.size());
m_triangleTangents.resize(m_trianglesVertices.size());
for (size_t triangleId = 0; triangleId < m_triangleNormals.size(); ++triangleId)
{
......@@ -145,6 +147,35 @@ SurfaceMesh::computeTrianglesNormals()
m_triangleNormals.at(triangleId) = ((p1 - p0).cross(p2 - p0)).normalized();
}
bool hasUVs = this->hasPointDataArray(m_defaultTCoords);
const StdVectorOfVectorf* UVs;
if (hasUVs)
{
UVs = this->getPointDataArray(m_defaultTCoords);
}
if (hasUVs)
{
for (size_t triangleId = 0; triangleId < m_triangleNormals.size(); ++triangleId)
{
const auto& t = m_trianglesVertices.at(triangleId);
const auto& p0 = m_vertexPositions.at(t.at(0));
const auto& p1 = m_vertexPositions.at(t.at(1));
const auto& p2 = m_vertexPositions.at(t.at(2));
const auto& uv0 = (*UVs)[t.at(0)];
const auto& uv1 = (*UVs)[t.at(1)];
const auto& uv2 = (*UVs)[t.at(2)];
auto diffPos1 = p1 - p0;
auto diffPos2 = p2 - p0;
float diffUV1[2] = { uv1[0] - uv0[0], uv1[1] - uv0[1] };
float diffUV2[2] = { uv2[0] - uv0[0], uv2[1] - uv0[1] };
m_triangleTangents.at(triangleId) = (diffPos1 * diffUV2[1] - diffPos2 * diffUV1[0]) / (diffUV1[0] * diffUV2[1] - diffUV1[1] * diffUV2[0]);
}
}
}
void
......@@ -158,21 +189,33 @@ SurfaceMesh::computeVertexNormals()
}
m_vertexNormals.resize(m_vertexPositions.size());
m_vertexTangents.resize(m_vertexPositions.size());
this->computeTrianglesNormals();
StdVectorOfVec3d temp_normals(m_vertexNormals.size());
StdVectorOfVec3d temp_tangents(m_vertexTangents.size());
for (size_t vertexId = 0; vertexId < m_vertexNormals.size(); ++vertexId)
{
temp_normals[vertexId] = Vec3d(0, 0, 0);
temp_tangents[vertexId] = Vec3d(0, 0, 0);
for (const size_t& triangleId : m_vertexNeighborTriangles.at(vertexId))
{
temp_normals[vertexId] += m_triangleNormals[triangleId];
temp_tangents[vertexId] += m_triangleTangents[triangleId];
}
}
// Correct for UV seams
Vec3d normal;
Vec3d normal, tangent;
bool hasUVs = this->hasPointDataArray(m_defaultTCoords);
const StdVectorOfVectorf* UVs;
if (hasUVs)
{
UVs = this->getPointDataArray(m_defaultTCoords);
}
for (size_t vertexId = 0; vertexId < m_vertexNormals.size(); ++vertexId)
{
NormalGroup group = {m_vertexPositions[vertexId], m_vertexNormals[vertexId]};
......@@ -195,6 +238,13 @@ SurfaceMesh::computeVertexNormals()
normal.normalize();
m_vertexNormals[vertexId] = normal;
if (hasUVs)
{
tangent = temp_tangents[vertexId];
tangent.normalize();
m_vertexTangents[vertexId] = tangent;
}
}
}
......
......@@ -236,6 +236,7 @@ protected:
std::vector<NeighborsType> m_vertexNeighborVertices; ///> Neighbor vertices to vertices
StdVectorOfVec3d m_triangleNormals; ///> Normals to the triangles
StdVectorOfVec3d m_triangleTangents; ///> Tangents to the triangles
StdVectorOfVec3d m_vertexNormals; ///> Normals of the vertices
StdVectorOfVec3d m_vertexTangents; ///> Tangents of the vertices
......
......@@ -173,6 +173,8 @@ public:
protected:
friend class VTKRenderer;
friend class VTKRenderDelegate;
friend class VulkanLineMeshRenderDelegate;
friend class VulkanRenderDelegate;
friend class VulkanSurfaceMeshRenderDelegate;
friend class VulkanRenderer;
......
......@@ -135,15 +135,15 @@ RenderMaterial::backfaceCullingOff()
}
const Color&
RenderMaterial::getDiffuseColor() const
RenderMaterial::getColor() const
{
return m_diffuseColor;
return m_color;
}
void
RenderMaterial::setDiffuseColor(const Color color)
RenderMaterial::setColor(const Color color)
{
m_diffuseColor = color;
m_color = color;
m_modified = true;
}
......@@ -290,4 +290,10 @@ RenderMaterial::isDecal()
{
return m_isDecal;
}
bool
RenderMaterial::isLineMesh()
{
return m_isLineMesh;
}
}
......@@ -82,10 +82,11 @@ public:
void backfaceCullingOff();
///
/// \brief Get/Set the diffuse color
/// \brief Get/Set the color. This affects the diffuse color directly, but
/// it affects the specular color in the case of metals.
///
const Color& getDiffuseColor() const;
void setDiffuseColor(const Color color);
const Color& getColor() const;
void setColor(const Color color);
///
/// \brief Get/Set the color of the wireframe and points
......@@ -153,10 +154,13 @@ public:
///
bool isDecal();
bool isLineMesh();
protected:
friend class VTKRenderDelegate;
friend class VulkanRenderDelegate;
friend class VulkanDecalRenderDelegate;
friend class VulkanLineMeshRenderDelegate;
// State
DisplayMode m_displayMode = DisplayMode::SURFACE;
......@@ -165,12 +169,13 @@ protected:
float m_pointSize = 1.0;
bool m_backfaceCulling = true; ///< For performance, uncommon for this to be false
bool m_isDecal = false;
bool m_isLineMesh = false;
// Sphere size used for glyph in rendering (valid only for point set)
double m_sphereGlyphSize = 0.05;
// Colors
Color m_diffuseColor = Color::White;
Color m_color = Color::White;
Color m_debugColor = Color::Black;
// Classical values
......
......@@ -39,6 +39,7 @@ set(VULKAN_H_FILES
VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.h
VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.h
VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.h
VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.h
VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.h
VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.h
VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.h
......@@ -61,6 +62,7 @@ set(VULKAN_CPP_FILES
VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.cpp
VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.cpp
VulkanRenderer/RenderDelegate/imstkVulkanDecalRenderDelegate.cpp
VulkanRenderer/RenderDelegate/imstkVulkanLineMeshRenderDelegate.cpp
VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.cpp
VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp
VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.cpp
......
......@@ -27,6 +27,9 @@
#include <vtkPolyDataMapper.h>
#include <vtkPoints.h>
#include <vtkDoubleArray.h>
#include <vtkFloatArray.h>
#include <vtkLine.h>
#include <vtkTrivialProducer.h>
namespace imstk
{
......@@ -45,16 +48,50 @@ VTKLineMeshRenderDelegate::VTKLineMeshRenderDelegate(std::shared_ptr<LineMesh> l
points->SetNumberOfPoints(m_geometry->getNumVertices());
points->SetData(m_mappedVertexArray);
// Create index
auto lineIndices = vtkSmartPointer<vtkCellArray>::New();
for (auto line : m_geometry->getLinesVertices())
{
auto l = vtkSmartPointer<vtkLine>::New();
l->GetPointIds()->SetId(0, line[0]);
l->GetPointIds()->SetId(1, line[1]);
lineIndices->InsertNextCell(l);
}
// Create line
auto lines = vtkSmartPointer<vtkLineSource>::New();
auto lines = vtkSmartPointer<vtkPolyData>::New();
lines->SetPoints(points);
m_geometry->m_dataModified = false;
lines->SetLines(lineIndices);
// Setup Mapper & Actor
this->setUpMapper(lines->GetOutputPort(), true, m_geometry);
// Add colors
if (m_geometry->getVertexColors().size() == m_geometry->getNumVertices())
{
auto colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
colors->SetNumberOfComponents(3);
colors->SetName("Colors");
for (auto color : m_geometry->getVertexColors())
{
unsigned char c[3] = { (unsigned char)(color.r * 255),
(unsigned char)(color.g * 255),
(unsigned char)(color.b * 255) };
colors->InsertNextTypedTuple(c);
}
lines->GetPointData()->SetScalars(colors);
}
// Create connection source
auto source = vtkSmartPointer<vtkTrivialProducer>::New();
source->SetOutput(lines);
m_geometry->m_dataModified = false;
// Update Transform, Render Properties
this->update();
// Setup Mapper & Actor
this->setUpMapper(source->GetOutputPort(), true, m_geometry);
}
void
......
......@@ -193,7 +193,7 @@ VTKRenderDelegate::updateActorProperties()
auto actorProperty = m_actor->GetProperty();
// Colors & Light
auto diffuseColor = material->m_diffuseColor;
auto diffuseColor = material->m_color;
actorProperty->SetDiffuseColor(diffuseColor.r, diffuseColor.g, diffuseColor.b);