Commit 7bdfdbb5 authored by Sreekanth Arikatla's avatar Sreekanth Arikatla

Merge branch 'OctreeDataStructure' into 'master'

Octree Data Structure

See merge request !342
parents d3f7e50b 5e964bcb
Pipeline #141932 passed with stage
in 0 seconds
......@@ -142,9 +142,9 @@ main()
}
++mode;
debugPoints->turnDataModifiedFlagON();
debugLines->turnDataModifiedFlagON();
debugTriangles->turnDataModifiedFlagON();
debugPoints->setDataModified(true);
debugLines->setDataModified(true);
debugTriangles->setDataModified(true);
// Must call to update render data
for (auto& delegate : renderer->getDebugRenderDelegates())
......
This source diff could not be displayed because it is too large. You can view the blob instead.
###########################################################################
#
# 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-Octree)
#-----------------------------------------------------------------------------
# Create executable
#-----------------------------------------------------------------------------
add_executable(${PROJECT_NAME} OctreeExample.cpp BunnyMesh.cpp)
#-----------------------------------------------------------------------------
# Add shaders
#-----------------------------------------------------------------------------
include(imstkCopyAndCompileShaders)
CopyAndCompileShaders()
#-----------------------------------------------------------------------------
# Link libraries to executable
#-----------------------------------------------------------------------------
target_link_libraries(${PROJECT_NAME} SimulationManager)
/*=========================================================================
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 "imstkSceneObject.h"
#include "imstkDebugGeometry.h"
#include "imstkAPIUtilities.h"
#include "imstkLooseOctree.h"
#include "imstkVTKViewer.h"
#include "imstkTimer.h"
#include "imstkVTKTextStatusManager.h"
#include <thread>
#include <chrono>
#include <sstream>
using namespace imstk;
//#define NUM_MESHES 4u
#define NUM_MESHES 10u
// Load bunny mesh data (vertex positions and triangle faces)
std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> getBunny();
static std::pair<StdVectorOfVec3d, std::vector<std::array<size_t, 3>>> g_BunnyData = getBunny();
///
/// \brief Read a mesh, create a visual scene object and add to the scene
///
std::shared_ptr<VisualObject>
createMeshObject(const std::shared_ptr<imstk::Scene>& scene,
const std::string& objectName,
Color color)
{
// Create a surface mesh for the bunny
auto meshObj = std::make_shared<SurfaceMesh>();
meshObj->initialize(g_BunnyData.first, g_BunnyData.second);
// Create a visiual model
auto visualModel = std::make_shared<VisualModel>(meshObj);
auto material = std::make_shared<RenderMaterial>();
material->setDebugColor(color); // Wireframe color
material->setLineWidth(4);
material->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE);
visualModel->setRenderMaterial(material);
auto visualObject = std::make_shared<VisualObject>(objectName);
visualObject->addVisualModel(visualModel);
scene->addSceneObject(visualObject);
return visualObject;
}
///
/// \brief Generate a random color
///
Color
getRandomColor()
{
Color color(0, 0, 0, 1);
while (true)
{
for (unsigned int i = 0; i < 3; ++i)
{
color.rgba[i] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
}
if (color.rgba[0] > 0.95
|| color.rgba[1] > 0.95
|| color.rgba[2] > 0.95)
{
break;
}
}
return color;
}
///
/// \brief This example demonstrates the usage of octree
///
int
main()
{
// SDK and Scene
auto sdk = std::make_shared<SimulationManager>();
auto scene = sdk->createNewScene("Octree Example");
sdk->setActiveScene(scene);
// Get the VTKViewer
auto viewer = std::dynamic_pointer_cast<VTKViewer>(sdk->getViewer());
viewer->getVtkRenderWindow()->SetSize(1920, 1080);
auto statusManager = viewer->getTextStatusManager();
statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30);
statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Orange);
// Get VTK Renderer
auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer());
LOG_IF(FATAL, (!renderer)) << "Invalid renderer: Only VTKRenderer is supported for debug rendering";
// srand(123456); // Deterministic random generation, for random colors
srand(static_cast<unsigned int>(time(nullptr)));
// Create meshes
std::vector<std::shared_ptr<SurfaceMesh>> triMeshes;
for (unsigned int i = 0; i < NUM_MESHES; ++i)
{
const auto sceneObj = createMeshObject(scene, "Mesh-" + std::to_string(triMeshes.size()), getRandomColor());
triMeshes.push_back(std::dynamic_pointer_cast<SurfaceMesh>(sceneObj->getVisualGeometry()));
}
// Compute the scale factor to scale meshes such that meshes with different sizes are still visualized consistently
Vec3d lowerCorner, upperCorner;
const auto pointset = std::dynamic_pointer_cast<PointSet>(triMeshes.front());
ParallelUtils::ParallelReduce::findAABB(pointset->getVertexPositions(), lowerCorner, upperCorner);
const auto scaleFactor = 20.0 / (upperCorner - lowerCorner).norm();
for (const auto& mesh: triMeshes)
{
mesh->scale(scaleFactor, Geometry::TransformType::ApplyToData);
}
StopWatch timer;
timer.start();
// Create octree
LooseOctree octree(Vec3d(0, 0, 0), 100.0, 0.125, 2.0, "TestOctree");
// Add all meshes to the octree
for (const auto& mesh: triMeshes)
{
octree.addTriangleMesh(mesh);
}
// Build octree after adding all geometries
octree.build();
LOG(INFO) << "Build octree time: " << timer.getTimeElapsed() << " ms";
// Always rebuild tree from scratch in each update (default update is incremental update)
// This is significantly slower than incremental update!
// octree.setAlwaysRebuild(true);
// Create debug geometry for the octree (render up to 8 levels, and render all non-emtpy nodes)
const auto debugOctree = octree.getDebugGeometry(8, true);
scene->addDebugGeometry(debugOctree);
// Data for animation
const double translation = 15.0;
StdVectorOfVec3d centers;
StdVectorOfVec3d dirs;
for (unsigned int i = 0; i < NUM_MESHES; ++i)
{
centers.push_back(Vec3d(translation, 0, 0));
dirs.push_back(Vec3d(-1, 0, 0));
}
// Transform the mesh objects
const double angle = 2.0 * PI / NUM_MESHES;
for (unsigned int i = 0; i < NUM_MESHES; ++i)
{
const auto rotation = angle * static_cast<double>(i);
triMeshes[i]->translate(translation, 0, 1, Geometry::TransformType::ApplyToData);
triMeshes[i]->rotate(Vec3d(0, 1, 0), rotation, Geometry::TransformType::ApplyToData);
auto t = centers[i][0];
centers[i][0] = std::cos(rotation) * t;
centers[i][2] = -std::sin(rotation) * t;
t = dirs[i][0];
dirs[i][0] = std::cos(rotation) * t;
dirs[i][2] = -std::sin(rotation) * t;
}
auto updateFunc =
[&](Module*) {
// Move objects
for (size_t i = 0; i < triMeshes.size(); ++i)
{
triMeshes[i]->translate(dirs[i][0], dirs[i][1], dirs[i][2], Geometry::TransformType::ApplyToData);
centers[i] += dirs[i];
}
Vec3d lowerCorners, upperCorner;
ParallelUtils::ParallelReduce::findAABB(centers, lowerCorners, upperCorner);
if ((lowerCorners - upperCorner).norm() > 70.0)
{
for (size_t i = 0; i < dirs.size(); ++i)
{
dirs[i] = -dirs[i]; // Change moving direction to move the objects back if they have moved too far
}
}
StopWatch timer;
timer.start();
octree.update();
const auto updateTime = timer.getTimeElapsed();
const auto numActiveNodes = octree.getNumActiveNodes();
const auto numAllocatedNodes = octree.getNumAllocatedNodes();
const auto maxNumPrimitivesInNodes = octree.getMaxNumPrimitivesInNodes();
std::stringstream ss;
ss << "Octree update time: " << updateTime << " ms\n"
<< "Active nodes: " << numActiveNodes
<< " (" << static_cast<double>(numActiveNodes) / static_cast<double>(numAllocatedNodes) * 100.0
<< " % usage / total allocated nodes: " << numAllocatedNodes << ")\n"
<< "Max number of primitives in tree nodes: " << maxNumPrimitivesInNodes;
statusManager->setCustomStatus(ss.str());
// Update debug rendering data
octree.updateDebugGeometry();
for (auto& delegate : renderer->getDebugRenderDelegates())
{
delegate->updateDataSource();
}
// Pause for a while
std::this_thread::sleep_for(std::chrono::milliseconds(100));
};
sdk->getSceneManager(scene)->setPostUpdateCallback(updateFunc);
// Set Camera configuration
auto cam = scene->getCamera();
cam->setPosition(Vec3d(0, 15, 50));
cam->setFocalPoint(Vec3d(0, 0, 0));
// Light
{
auto light = std::make_shared<DirectionalLight>("Light 1");
light->setFocalPoint(Vec3d(-1, -1, -1));
light->setIntensity(1);
scene->addLight(light);
}
{
auto light = std::make_shared<DirectionalLight>("Light 2");
light->setFocalPoint(Vec3d(1, -1, -1));
light->setIntensity(1);
scene->addLight(light);
}
// Run
sdk->startSimulation(SimulationStatus::PAUSED);
return 0;
}
......@@ -5,6 +5,7 @@ include(imstkAddLibrary)
imstk_add_library( Datastructures
DEPENDS
Core
Geometry
)
#-----------------------------------------------------------------------------
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -114,6 +114,7 @@ PointSet::setVertexPositions(const StdVectorOfVec3d& vertices)
m_vertexPositions = vertices;
m_dataModified = true;
m_transformApplied = false;
this->updatePostTransformData();
}
else
{
......@@ -282,7 +283,6 @@ PointSet::updatePostTransformData()
if (m_vertexPositionsPostTransform.size() != m_vertexPositions.size())
{
m_vertexPositionsPostTransform.clear();
m_vertexPositionsPostTransform.resize(m_vertexPositions.size());
}
for (size_t i = 0; i < m_vertexPositions.size(); ++i)
......
......@@ -103,12 +103,11 @@ public:
///
/// \brief Return m_isModified flag, used to communicate with the render engine
/// For performance reason, the only way to change this flag is to manually call to turnDataModifiedFlagON() or turnDataModifiedFlagOFF
/// Thus, we must call turnDataModifiedFlagON() explicity after finished data manipulation
/// For performance reason, the only way to change this flag is to manually call to setDataModified(true)
/// Thus, we must call setDataModified(true) explicity after finished data manipulation
///
bool isModified() const { return m_isModified; }
void turnDataModifiedFlagON() { m_isModified = true; }
void turnDataModifiedFlagOFF() { m_isModified = false; }
void setDataModified(const bool bState) { m_isModified = bState; }
///
/// \brief Set/Get render material
......
......@@ -20,6 +20,7 @@
=========================================================================*/
#include "imstkGeometry.h"
#include "imstkLogUtility.h"
namespace imstk
{
......@@ -35,6 +36,12 @@ Geometry::print() const
LOG(INFO) << "Rotation:\n" << r;
}
void
Geometry::computeBoundingBox(Vec3d& /*min*/, Vec3d& /*max*/, const double /* paddingPercent = 0.0*/) const
{
LOG(FATAL) << "Call to unimplemented function";
}
void
Geometry::translate(const Vec3d& t, TransformType type)
{
......@@ -240,4 +247,22 @@ Geometry::isMesh() const
|| this->m_type == Type::LineMesh
) ? true : false;
}
// Static counter
unsigned int
Geometry::s_NumGeneratedGegometries;
// Static counter mutex lock
ParallelUtils::SpinLock
Geometry::s_RegistryLock;
unsigned int
Geometry::getUniqueID()
{
s_RegistryLock.lock();
const auto idx = s_NumGeneratedGegometries;
++s_NumGeneratedGegometries;
s_RegistryLock.unlock();
return idx;
}
} // imstk
......@@ -25,6 +25,7 @@
#include "imstkMath.h"
#include "imstkRenderMaterial.h"
#include "imstkParallelUtils.h"
namespace imstk
{
......@@ -81,12 +82,12 @@ public:
///
/// \brief Constructor
///
Geometry(Type type) : m_type(type) {}
Geometry(const Type type) : m_geometryIdx(Geometry::getUniqueID()), m_type(type) {}
///
/// \brief Destructor
///
virtual ~Geometry() {}
virtual ~Geometry() = default;
///
/// \brief Print
......@@ -98,6 +99,11 @@ public:
///
virtual double getVolume() const = 0;
///
/// \brief Compute the bounding box for the geometry
///
virtual void computeBoundingBox(Vec3d& min, Vec3d& max, const double paddingPercent = 0.0) const;
///
/// \brief Translate the geometry in Cartesian space
///
......@@ -164,7 +170,25 @@ public:
///
bool isMesh() const;
///
/// \brief Get the global (unique) index of the geometry
///
unsigned int getGlobalIndex() const { return m_geometryIdx; }
///
/// \brief Get a pointer to geometry that has been registered globally
///
static unsigned int getTotalNumberGeometries() { return s_NumGeneratedGegometries; }
protected:
///
/// \brief Get a unique ID for the object
///
static unsigned int getUniqueID();
static ParallelUtils::SpinLock s_RegistryLock; ///> Mutex lock for thread-safe registry modification
static unsigned int s_NumGeneratedGegometries; ///> Total number of geometries that have been created in this program
friend class VTKRenderer;
friend class VTKRenderDelegate;
......@@ -178,8 +202,11 @@ protected:
virtual void applyScaling(const double s) = 0;
virtual void updatePostTransformData() = 0;
Type m_type; ///> Geometry type
const unsigned int m_geometryIdx = 0; ///> Unique ID assigned to each geometry upon construction
const Type m_type; ///> Type of geometry
ParallelUtils::SpinLock m_dataLock;
ParallelUtils::SpinLock m_transformLock;
bool m_dataModified = false;
bool m_transformModified = false;
bool m_transformApplied = true;
......
......@@ -71,7 +71,7 @@ VTKdbgLinesRenderDelegate::updateDataSource()
{
if (m_RenderGeoData->isModified())
{
m_RenderGeoData->turnDataModifiedFlagOFF();
m_RenderGeoData->setDataModified(false);
m_mappedVertexArray->SetArray(m_RenderGeoData->getVertexBufferPtr(),
m_RenderGeoData->getNumVertices() * 3, 1);
......
......@@ -71,7 +71,7 @@ VTKdbgPointsRenderDelegate::updateDataSource()
{
if (m_RenderGeoData->isModified())
{
m_RenderGeoData->turnDataModifiedFlagOFF();
m_RenderGeoData->setDataModified(false);
m_mappedVertexArray->SetArray(m_RenderGeoData->getVertexBufferPtr(),
m_RenderGeoData->getNumVertices() * 3, 1);
......
......@@ -67,7 +67,7 @@ VTKdbgTrianglesRenderDelegate::updateDataSource()
{
if (m_RenderGeoData->isModified())
{
m_RenderGeoData->turnDataModifiedFlagOFF();
m_RenderGeoData->setDataModified(false);
m_pappedVertexArray->SetArray(m_RenderGeoData->getVertexBufferPtr(),
m_RenderGeoData->getNumVertices() * 3, 1);
......
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