Commit f1e55106 authored by Andrew Wilson's avatar Andrew Wilson
Browse files

REFAC: SceneObjects and VisualModels can now be both added AND removed to the...

REFAC: SceneObjects and VisualModels can now be both added AND removed to the Renderer during runtime, new event based scene modification/observer pattern
parent f61d1121
......@@ -20,6 +20,7 @@
=========================================================================*/
#include "imstkCamera.h"
#include "imstkKeyboardDeviceClient.h"
#include "imstkKeyboardSceneControl.h"
#include "imstkLight.h"
#include "imstkLogger.h"
......@@ -34,6 +35,7 @@
#include "imstkSurfaceMesh.h"
#include "imstkVisualModel.h"
#include "imstkVTKViewer.h"
#include "imstkMeshIO.h"
using namespace imstk;
......@@ -90,7 +92,18 @@ makeClothGeometry(const double width,
}
}
imstkNew<VecDataArray<float, 2>> uvCoordsPtr(nRows * nCols);
VecDataArray<float, 2>& uvCoords = *uvCoordsPtr.get();
for (int i = 0; i < nRows; ++i)
{
for (int j = 0; j < nCols; j++)
{
uvCoords[i * nCols + j] = Vec2f(static_cast<float>(i) / nRows, static_cast<float>(j) / nCols);
}
}
clothMesh->initialize(verticesPtr, indicesPtr);
clothMesh->setVertexTCoords("uvs", uvCoordsPtr);
return clothMesh;
}
......@@ -133,7 +146,12 @@ makeClothObj(const std::string& name,
// Setup the VisualModel
imstkNew<RenderMaterial> material;
material->setBackFaceCulling(false);
material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
material->setShadingModel(RenderMaterial::ShadingModel::PBR);
material->setRoughness(0.5);
material->setMetalness(0.1);
material->addTexture(std::make_shared<Texture>("C:/Users/Andx_/Pictures/MyTextures/carpet.jpg", Texture::Type::Diffuse));
//material->addTexture(std::make_shared<Texture>("C:/Users/Andx_/Pictures/MyTextures/carpetN.png", Texture::Type::Normal));
imstkNew<VisualModel> visualModel(clothMesh);
visualModel->setRenderMaterial(material);
......@@ -157,26 +175,12 @@ main()
Logger::startLogger();
// Setup a scene
imstkNew<Scene> scene("PBDCloth");
imstkNew<Scene> scene("PBDCloth");
std::shared_ptr<PbdObject> clothObj = nullptr;
{
std::shared_ptr<PbdObject> clothObj = makeClothObj("Cloth", 10.0, 10.0, 16, 16);
clothObj = makeClothObj("Cloth", 10.0, 10.0, 16, 16);
scene->addSceneObject(clothObj);
// Light (white)
imstkNew<DirectionalLight> whiteLight("whiteLight");
whiteLight->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
whiteLight->setIntensity(1.0);
scene->addLight(whiteLight);
// Light (red)
imstkNew<SpotLight> colorLight("colorLight");
colorLight->setPosition(Vec3d(-5.0, -3.0, 5.0));
colorLight->setFocalPoint(Vec3d(0.0, -5.0, 5.0));
colorLight->setIntensity(100.);
colorLight->setColor(Color::Red);
colorLight->setSpotAngle(30.0);
scene->addLight(colorLight);
// Adjust camera
scene->getActiveCamera()->setFocalPoint(0.0, -5.0, 5.0);
scene->getActiveCamera()->setPosition(-15.0, -5.0, 25.0);
......@@ -190,12 +194,14 @@ main()
// Setup a scene manager to advance the scene
imstkNew<SceneManager> sceneManager("Scene Manager");
sceneManager->setExecutionType(Module::ExecutionType::ADAPTIVE);
sceneManager->setActiveScene(scene);
sceneManager->pause(); // Start simulation paused
imstkNew<SimulationManager> driver;
driver->addModule(viewer);
driver->addModule(sceneManager);
driver->setDesiredDt(0.001);
// Add mouse and keyboard controls to the viewer
{
......@@ -209,6 +215,14 @@ main()
viewer->addControl(keyControl);
}
queueConnect<KeyEvent>(viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress, sceneManager, [&](KeyEvent* e)
{
if (e->m_key == 'i')
{
clothObj->getVisualModel(0)->getRenderMaterial()->addTexture(std::make_shared<Texture>("C:/Users/Andx_/Pictures/MyTextures/carpetN.png", Texture::Type::Normal));
}
});
driver->start();
}
......
......@@ -338,15 +338,15 @@ SurfaceMesh::computeVertexTangents()
// First we need per triangle tangents
this->computeTriangleTangents();
VecDataArray<double, 3> temp_tangents(vertexTangents.size());
VecDataArray<double, 3> temp_vertex_tangents(vertexTangents.size());
std::shared_ptr<VecDataArray<double, 3>> triangleTangentsPtr = getCellTangents();
const VecDataArray<double, 3>& triangleTangents = *triangleTangentsPtr;
for (int vertexId = 0; vertexId < triangleTangents.size(); ++vertexId)
for (int vertexId = 0; vertexId < vertexTangents.size(); ++vertexId)
{
temp_tangents[vertexId] = Vec3d(0.0, 0.0, 0.0);
temp_vertex_tangents[vertexId] = Vec3d(0.0, 0.0, 0.0);
for (const size_t& triangleId : m_vertexNeighborTriangles.at(vertexId))
{
temp_tangents[vertexId] += triangleTangents[triangleId];
temp_vertex_tangents[vertexId] += triangleTangents[triangleId];
}
}
......@@ -354,7 +354,7 @@ SurfaceMesh::computeVertexTangents()
Vec3d tangent;
for (size_t vertexId = 0; vertexId < vertexTangents.size(); ++vertexId)
{
tangent = temp_tangents[vertexId];
tangent = temp_vertex_tangents[vertexId];
tangent.normalize();
vertexTangents[vertexId] = tangent.cast<float>();
}
......
......@@ -127,8 +127,6 @@ VTKSurfaceMeshRenderDelegate::VTKSurfaceMeshRenderDelegate(std::shared_ptr<Visua
// When index buffer internals are modified
queueConnect<Event>(m_geometry->getVertexNormals(), &VecDataArray<double, 3>::modified, this, &VTKSurfaceMeshRenderDelegate::normalDataModified);
// When the index buffer internals are modified,
// Setup mapper
{
vtkNew<vtkPolyDataMapper> mapper;
......
......@@ -65,18 +65,9 @@ VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) :
vtkOpenVRRenderer::SafeDownCast(m_vtkRenderer)->SetLightFollowCamera(false);
}
sceneModifed(nullptr);
this->updateRenderDelegates();
// Initialize textures for surface mesh render delegates
for (const auto& renderDelegate : m_renderDelegates)
{
auto smRenderDelegate = std::dynamic_pointer_cast<VTKSurfaceMeshRenderDelegate>(renderDelegate);
if (smRenderDelegate)
{
smRenderDelegate->initializeTextures(m_textureManager);
}
}
// Lights and light actors
for (const auto& light : scene->getLights())
{
......@@ -186,6 +177,9 @@ VTKRenderer::VTKRenderer(std::shared_ptr<Scene> scene, const bool enableVR) :
m_vtkRenderer->RemoveCuller(culler);
}
// Observe changes to the scene
connect<Event>(m_scene, &Scene::modified, this, &VTKRenderer::sceneModifed);
{
// Add the benchmarking chart
m_timeTableChart = vtkSmartPointer<vtkChartXY>::New();
......@@ -411,36 +405,123 @@ VTKRenderer::updateCamera()
void
VTKRenderer::updateRenderDelegates()
{
// Object actors
for (const auto& obj : m_scene->getSceneObjects())
// Call visual update on every scene object
m_scene->updateVisuals();
// Update their render delegates
for (auto delegate : m_renderDelegates)
{
delegate.second->update();
}
for (auto delegate : m_debugRenderDelegates)
{
delegate->update();
}
}
void
VTKRenderer::removeActors(const std::vector<vtkSmartPointer<vtkProp>>& actorList)
{
for (const auto& actor : actorList)
{
m_vtkRenderer->RemoveActor(actor);
}
}
void
VTKRenderer::addActors(const std::vector<vtkSmartPointer<vtkProp>>& actorList)
{
for (const auto& actor : actorList)
{
m_vtkRenderer->AddActor(actor);
}
}
void
VTKRenderer::addSceneObject(std::shared_ptr<SceneObject> sceneObject)
{
m_renderedObjects.insert(sceneObject);
m_renderedVisualModels[sceneObject] = std::unordered_set<std::shared_ptr<VisualModel>>();
sceneObjectModified(sceneObject);
// Observe changes on this SceneObject
connect<Event>(sceneObject, &SceneObject::modified, this, &VTKRenderer::sceneObjectModified);
}
void
VTKRenderer::addVisualModel(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<VisualModel> visualModel)
{
// Create a delegate for the visual m odel
auto renderDelegate = m_renderDelegates[visualModel] = VTKRenderDelegate::makeDelegate(visualModel);
if (renderDelegate == nullptr)
{
LOG(WARNING) << "Renderer::Renderer error: Could not create render delegate for '"
<< sceneObject->getName() << "'.";
return;
}
m_renderedVisualModels[sceneObject].insert(visualModel);
m_objectVtkActors.push_back(renderDelegate->getVtkActor());
m_vtkRenderer->AddActor(renderDelegate->getVtkActor());
auto smRenderDelegate = std::dynamic_pointer_cast<VTKSurfaceMeshRenderDelegate>(renderDelegate);
if (smRenderDelegate)
{
smRenderDelegate->initializeTextures(m_textureManager);
}
visualModel->setRenderDelegateCreated(this, true);
}
std::unordered_set<std::shared_ptr<VisualModel>>::iterator
VTKRenderer::removeVisualModel(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<VisualModel> visualModel)
{
auto renderDelegate = m_renderDelegates[visualModel];
auto iter = std::find(m_objectVtkActors.begin(), m_objectVtkActors.end(), renderDelegate->getVtkActor());
if (iter != m_objectVtkActors.end())
{
for (auto visualModel : obj->getVisualModels())
m_objectVtkActors.erase(iter);
}
m_vtkRenderer->RemoveActor(renderDelegate->getVtkActor());
m_renderDelegates.erase(visualModel);
return m_renderedVisualModels[sceneObject].erase(m_renderedVisualModels[sceneObject].find(visualModel));
}
std::unordered_set<std::shared_ptr<SceneObject>>::iterator
VTKRenderer::removeSceneObject(std::shared_ptr<SceneObject> sceneObject)
{
auto iter = m_renderedObjects.erase(m_renderedObjects.find(sceneObject));
// Remove every delegate associated and remove its actors from the scene
for (auto visualModel : sceneObject->getVisualModels())
{
removeVisualModel(sceneObject, visualModel);
}
m_renderedVisualModels.erase(sceneObject);
// Stop observing changes on the scene object
disconnect(sceneObject, this, &SceneObject::modified);
return iter;
}
void
VTKRenderer::sceneModifed(Event* imstkNotUsed(e))
{
// If the SceneObject is in the scene but not being rendered
for (auto sceneObject : m_scene->getSceneObjects())
{
if (m_renderedObjects.count(sceneObject) == 0)
{
auto geom = visualModel->getGeometry();
if (visualModel && !visualModel->getRenderDelegateCreated(this))
{
auto renderDelegate = VTKRenderDelegate::makeDelegate(visualModel);
if (renderDelegate == nullptr)
{
LOG(WARNING) << "Renderer::Renderer error: Could not create render delegate for '"
<< obj->getName() << "'.";
continue;
}
m_renderDelegates.push_back(renderDelegate);
m_objectVtkActors.push_back(renderDelegate->getVtkActor());
m_vtkRenderer->AddActor(renderDelegate->getVtkActor());
auto smRenderDelegate = std::dynamic_pointer_cast<VTKSurfaceMeshRenderDelegate>(renderDelegate);
if (smRenderDelegate)
{
smRenderDelegate->initializeTextures(m_textureManager);
}
//((vtkActor*)delegate->getVtkActor())->GetProperty()->PrintSelf(std::cout, vtkIndent());
visualModel->setRenderDelegateCreated(this, true);
}
addSceneObject(sceneObject);
}
}
// If the SceneObject is being rendered but not in the scene
for (auto i = m_renderedObjects.begin(); i != m_renderedObjects.end(); i++)
{
if (!m_scene->hasSceneObject(*i))
{
i = removeSceneObject(*i);
}
}
......@@ -464,36 +545,52 @@ VTKRenderer::updateRenderDelegates()
dbgVizModel->setRenderDelegateCreated(this, true);
}
}
// Call visual update on every scene object
m_scene->updateVisuals();
// Update their render delegates
for (auto delegate : m_renderDelegates)
{
delegate->update();
}
for (auto delegate : m_debugRenderDelegates)
{
delegate->update();
}
}
void
VTKRenderer::removeActors(const std::vector<vtkSmartPointer<vtkProp>>& actorList)
VTKRenderer::sceneObjectModified(Event* e)
{
for (const auto& actor : actorList)
SceneObject* sceneObject = static_cast<SceneObject*>(e->m_sender);
if (sceneObject != nullptr)
{
m_vtkRenderer->RemoveActor(actor);
// Note: All other solutions lead to some ugly variant, I went with this one
auto iter = std::find_if(m_renderedObjects.begin(), m_renderedObjects.end(),
[sceneObject](const std::shared_ptr<SceneObject>& i) { return i.get() == sceneObject; });
if (iter != m_renderedObjects.end())
{
sceneObjectModified(*iter);
}
}
}
void
VTKRenderer::addActors(const std::vector<vtkSmartPointer<vtkProp>>& actorList)
VTKRenderer::sceneObjectModified(std::shared_ptr<SceneObject> sceneObject)
{
for (const auto& actor : actorList)
// Only diff a sceneObject being rendered
if (m_renderedObjects.count(sceneObject) == 0 || m_renderedVisualModels.count(sceneObject) == 0)
{
m_vtkRenderer->AddActor(actor);
return;
}
// Now check for added/removed VisualModels
// If the VisualModel of the SceneObject is in the SceneObject but not being rendered
for (auto visualModel : sceneObject->getVisualModels())
{
if (m_renderedVisualModels[sceneObject].count(visualModel) == 0)
{
addVisualModel(sceneObject, visualModel);
}
}
// If the VisualModel of the SceneObject is being rendered but not part of the SceneObject anymore
const auto& visualModels = sceneObject->getVisualModels();
for (auto i = m_renderedVisualModels[sceneObject].begin(); i != m_renderedVisualModels[sceneObject].end(); i++)
{
auto iter = std::find(visualModels.begin(), visualModels.end(), *i);
if (iter == visualModels.end()) // If end, it is not part of the SceneObject anymore
{
i = removeVisualModel(sceneObject, *i);
}
}
}
......
......@@ -24,9 +24,11 @@
#include "imstkRenderer.h"
#include "imstkTextureManager.h"
#include "imstkVTKTextureDelegate.h"
#include "imstkEventObject.h"
#include <vtkSmartPointer.h>
#include <unordered_map>
#include <unordered_set>
class vtkAxesActor;
class vtkCamera;
......@@ -42,8 +44,10 @@ class vtkTable;
namespace imstk
{
class Scene;
class SceneObject;
class Camera;
class VTKRenderDelegate;
class VisualModel;
///
/// \class VTKRenderer
......@@ -134,6 +138,45 @@ protected:
///
void addActors(const std::vector<vtkSmartPointer<vtkProp>>& actorList);
protected:
///
/// \brief Adds a SceneObject to be rendered
///
void addSceneObject(std::shared_ptr<SceneObject> sceneObject);
///
/// \brief Removes a SceneObject to be rendered
///
std::unordered_set<std::shared_ptr<SceneObject>>::iterator removeSceneObject(std::shared_ptr<SceneObject> sceneObject);
///
/// \brief Callback for when the scene this renderer renders is modified
/// This involves adding/removing scene objects to render lists
///
void sceneModifed(Event* e);
protected:
///
/// \brief Add a VisualModel to be rendered, creates a delegate for it
///
void addVisualModel(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<VisualModel> visualModel);
///
/// \brief Remove a VisualModel from rendering
///
std::unordered_set<std::shared_ptr<VisualModel>>::iterator removeVisualModel(std::shared_ptr<SceneObject> sceneObject, std::shared_ptr<VisualModel> visualModel);
///
/// \brief Callback for when a SceneObject is modified
/// This involves adding/removing visual models to render lists
///
void sceneObjectModified(Event* e);
///
/// \brief Function call for proccessing diffs on a SceneObject
///
void sceneObjectModified(std::shared_ptr<SceneObject> sceneObject);
protected:
vtkSmartPointer<vtkRenderer> m_vtkRenderer;
......@@ -148,13 +191,17 @@ protected:
std::vector<vtkSmartPointer<vtkProp>> m_debugVtkActors;
vtkSmartPointer<vtkAxesActor> m_AxesActor;
// Render delegates for the props
std::vector<std::shared_ptr<VTKRenderDelegate>> m_renderDelegates;
std::vector<std::shared_ptr<VTKRenderDelegate>> m_debugRenderDelegates;
// imstk scene
std::shared_ptr<Scene> m_scene;
// Rendered Objects, this gives whats currently being rendered
std::unordered_set<std::shared_ptr<SceneObject>> m_renderedObjects;
std::unordered_map<std::shared_ptr<SceneObject>, std::unordered_set<std::shared_ptr<VisualModel>>> m_renderedVisualModels;
// Render Delegates
std::unordered_map<std::shared_ptr<VisualModel>, std::shared_ptr<VTKRenderDelegate>> m_renderDelegates;
std::vector<std::shared_ptr<VTKRenderDelegate>> m_debugRenderDelegates;
TextureManager<VTKTextureDelegate> m_textureManager;
vtkSmartPointer<vtkChartXY> m_timeTableChart;
......
......@@ -21,6 +21,7 @@
#pragma once
#include "imstkEventObject.h"
#include "imstkMath.h"
#include "imstkColor.h"
......@@ -39,7 +40,7 @@ struct rendererConfig
///
/// \brief Rendering window manager and contains user API to configure the rendering with various backends
///
class Renderer
class Renderer : public EventObject
{
public:
///
......
......@@ -67,10 +67,9 @@ bool
Scene::initialize()
{
// Initialize all the SceneObjects
for (auto const& it : m_sceneObjectsMap)
for (const auto& obj : m_sceneObjects)
{
auto sceneObject = it.second;
CHECK(sceneObject->initialize()) << "Error initializing scene object: " << sceneObject->getName();
CHECK(obj->initialize()) << "Error initializing scene object: " << obj->getName();
}
// Build the compute graph
......@@ -87,9 +86,8 @@ Scene::initialize()
{
Vec3d globalMin = Vec3d(IMSTK_DOUBLE_MAX, IMSTK_DOUBLE_MAX, IMSTK_DOUBLE_MAX);
Vec3d globalMax = Vec3d(IMSTK_DOUBLE_MIN, IMSTK_DOUBLE_MIN, IMSTK_DOUBLE_MIN);
for (auto i : m_sceneObjectsMap)
for (const auto& obj : m_sceneObjects)
{
std::shared_ptr<SceneObject> obj = i.second;
for (auto visualModels : obj->getVisualModels())
{
Vec3d min = Vec3d(IMSTK_DOUBLE_MAX, IMSTK_DOUBLE_MAX, IMSTK_DOUBLE_MAX);
......@@ -120,15 +118,14 @@ Scene::buildTaskGraph()
// Setup all SceneObject compute graphs (and segment the rigid bodies)
std::list<std::shared_ptr<SceneObject>> rigidBodies;
for (auto const& it : m_sceneObjectsMap)
for (const auto& obj : m_sceneObjects)
{
auto sceneObject = it.second;
if (sceneObject->getTypeName() == "RigidObject")
if (obj->getTypeName() == "RigidObject")
{
rigidBodies.push_back(sceneObject);
rigidBodies.push_back(obj);
}
sceneObject->initGraphEdges();
obj->initGraphEdges();
}
// Apply all the interaction graph element operations to the SceneObject graphs
......@@ -139,9 +136,9 @@ Scene::buildTaskGraph()
}
// Nest all the SceneObject graphs within this Scene's ComputeGraph
for (auto const& it : m_sceneObjectsMap)
for (const auto& obj : m_sceneObjects)
{
std::shared_ptr<TaskGraph> objComputeGraph = it.second->getTaskGraph();
std::shared_ptr<TaskGraph> objComputeGraph = obj->getTaskGraph();
if (objComputeGraph != nullptr)
{
// Add edges between any nodes that are marked critical and running simulatenously
......@@ -215,12 +212,6 @@ Scene::initTaskGraph()
m_taskGraphController->initialize();
}
bool
Scene::isObjectRegistered(const std::string& sceneObjectName) const
{
return m_sceneObjectsMap.find(sceneObjectName) != m_sceneObjectsMap.end();
}
void
Scene::setEnableTaskTiming(bool enabled)
{
......@@ -232,27 +223,26 @@ Scene::setEnableTaskTiming(bool enabled)
}
}
const std::vector<std::shared_ptr<SceneObject>>
Scene::getSceneObjects() const
std::shared_ptr<SceneObject>
Scene::getSceneObject(const std::string& name) const
{
std::vector<std::shared_ptr<SceneObject>> v;
for (auto it : m_sceneObjectsMap)
{
v.push_back(it.second);
}
return v;
auto iter = std::find_if(m_sceneObjects.begin(), m_sceneObjects.end(),
[name](const std::shared_ptr<SceneObject>& i) { return i->getName() == name; });
return (iter == m_sceneObjects.end()) ? nullptr : *iter;
}
std::shared_ptr<SceneObject>
Scene::getSceneObject(const std::string& sceneObjectName) const
bool
Scene::hasSceneObject(std::shared_ptr<SceneObject> sceneObject)