diff --git a/Sofa/Component/Collision/Detection/Algorithm/CMakeLists.txt b/Sofa/Component/Collision/Detection/Algorithm/CMakeLists.txt index cc503bf09d6..b59238f8a65 100644 --- a/Sofa/Component/Collision/Detection/Algorithm/CMakeLists.txt +++ b/Sofa/Component/Collision/Detection/Algorithm/CMakeLists.txt @@ -6,10 +6,12 @@ set(SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR "src/sofa/component/coll set(HEADER_FILES ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/config.h.in ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/init.h + ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BaseSubCollisionPipeline.h ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BVHNarrowPhase.h ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BruteForceBroadPhase.h ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BruteForceDetection.h ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CollisionPM.h + ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CompositeCollisionPipeline.h ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DSAPBox.h ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CollisionPipeline.h ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DirectSAP.h @@ -19,20 +21,24 @@ set(HEADER_FILES ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/MirrorIntersector.h ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/RayTraceDetection.h ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/RayTraceNarrowPhase.h + ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/SubCollisionPipeline.h ) set(SOURCE_FILES ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/init.cpp + ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BaseSubCollisionPipeline.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BVHNarrowPhase.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BruteForceBroadPhase.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/BruteForceDetection.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DSAPBox.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CollisionPipeline.cpp + ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/CompositeCollisionPipeline.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DirectSAP.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/DirectSAPNarrowPhase.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/IncrSAP.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/RayTraceDetection.cpp ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/RayTraceNarrowPhase.cpp + ${SOFACOMPONENTCOLLISIONDETECTIONALGORITHM_SOURCE_DIR}/SubCollisionPipeline.cpp ) sofa_find_package(Sofa.Simulation.Core REQUIRED) diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.cpp new file mode 100644 index 00000000000..60f226299f3 --- /dev/null +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.cpp @@ -0,0 +1,77 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include +#include + +namespace sofa::component::collision::detection::algorithm +{ + +BaseSubCollisionPipeline::BaseSubCollisionPipeline() +: sofa::core::objectmodel::BaseObject() +{ + +} + +void BaseSubCollisionPipeline::doBwdInit() +{ + +} + +void BaseSubCollisionPipeline::doDraw(const core::visual::VisualParams* vparams) +{ + SOFA_UNUSED(vparams); + +} + +void BaseSubCollisionPipeline::init() +{ + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Loading); + + doInit(); +} + +std::set< std::string > BaseSubCollisionPipeline::getResponseList() +{ + std::set< std::string > listResponse; + for (const auto& [key, creatorPtr] : *core::collision::Contact::Factory::getInstance()) + { + listResponse.insert(key); + } + return listResponse; +} + +void BaseSubCollisionPipeline::draw(const core::visual::VisualParams* vparams) +{ + const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); + + doDraw(vparams); +} + +void BaseSubCollisionPipeline::handleEvent(sofa::core::objectmodel::Event* e) +{ + doHandleEvent(e); +} + +} // namespace sofa::component::collision::detection::algorithm diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.h new file mode 100644 index 00000000000..f1ff039fcf2 --- /dev/null +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/BaseSubCollisionPipeline.h @@ -0,0 +1,65 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include + +#include +#include + +namespace sofa::core +{ +class CollisionModel; +} + +namespace sofa::component::collision::detection::algorithm +{ + +class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API BaseSubCollisionPipeline : public sofa::core::objectmodel::BaseObject +{ +public: + SOFA_ABSTRACT_CLASS(BaseSubCollisionPipeline, sofa::core::objectmodel::BaseObject); + +protected: + BaseSubCollisionPipeline(); + + virtual void doInit() = 0; + virtual void doBwdInit(); + virtual void doHandleEvent(sofa::core::objectmodel::Event* e) = 0; + virtual void doDraw(const core::visual::VisualParams* vparams); + +public: + virtual void computeCollisionReset() = 0; + virtual void computeCollisionDetection() = 0; + virtual void computeCollisionResponse() = 0; + + virtual std::vector getCollisionModels() = 0; + + void init() override final; + void draw(const core::visual::VisualParams* vparams) override final; + void handleEvent(sofa::core::objectmodel::Event* e) override final; + + static std::set< std::string > getResponseList(); +}; + +} // namespace sofa::component::collision::detection::algorithm diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.cpp index 4af2b8fb932..fe92271992c 100644 --- a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.cpp +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.cpp @@ -66,33 +66,57 @@ CollisionPipeline::CollisionPipeline() , d_depth(initData(&d_depth, defaultDepthValue, "depth", ("Max depth of bounding trees. (default=" + std::to_string(defaultDepthValue) + ", min=?, max=?)").c_str())) { + } -#ifdef SOFA_DUMP_VISITOR_INFO -typedef simulation::Visitor::ctime_t ctime_t; -#endif - void CollisionPipeline::init() { - Inherit1::init(); - - if (broadPhaseDetection == nullptr) - { - msg_warning() << "A BroadPhase component is required to compute collision detection and was not found in the current scene"; - } - - if (narrowPhaseDetection == nullptr) - { - msg_warning() << "A NarrowPhase component is required to compute collision detection and was not found in the current scene"; - } - - if (contactManager == nullptr) - { - msg_warning() << "A ContactManager component is required to compute collision response and was not found in the current scene"; - } - + msg_info() << "CollisionPipeline is now a wrapper to CompositeCollisionPipeline with a single SubCollisionPipeline."; + msg_info() << "If you want more flexibility, use directly the components CompositeCollisionPipeline and SubCollisionPipeline, with their respective Data."; + + auto context = this->getContext(); + assert(context); + + m_subCollisionPipeline = sofa::core::objectmodel::New(); + m_subCollisionPipeline->d_depth.setParent(&this->d_depth); + + // set the whole collision models list to the sub collision pipeline + sofa::type::vector collisionModels; + context->get>(&collisionModels, BaseContext::SearchDown); + for(auto collisionModel : collisionModels) + { + m_subCollisionPipeline->l_collisionModels.add(collisionModel.get()); + } + + // set the other components to the sub collision pipeline + // intersection + sofa::core::collision::Intersection* intersectionMethod = nullptr; + context->get(intersectionMethod, BaseContext::SearchDown); + m_subCollisionPipeline->l_intersectionMethod.set(intersectionMethod); + + // broad phase + sofa::core::collision::BroadPhaseDetection* broadPhaseDetection = nullptr; + context->get(broadPhaseDetection, BaseContext::SearchDown); + m_subCollisionPipeline->l_broadPhaseDetection.set(broadPhaseDetection); + + // narrow phase + sofa::core::collision::NarrowPhaseDetection* narrowPhaseDetection = nullptr; + context->get(narrowPhaseDetection, BaseContext::SearchDown); + m_subCollisionPipeline->l_narrowPhaseDetection.set(narrowPhaseDetection); + + // contact manager + sofa::core::collision::ContactManager* contactManager = nullptr; + context->get(contactManager, BaseContext::SearchDown); + m_subCollisionPipeline->l_contactManager.set(contactManager); + + m_subCollisionPipeline->init(); + this->l_subCollisionPipelines.add(m_subCollisionPipeline.get()); + this->addSlave(m_subCollisionPipeline.get()); + /// Insure that all the value provided by the user are valid and report message if it is not. checkDataValues() ; + + Inherit1::init(); } void CollisionPipeline::checkDataValues() @@ -105,222 +129,4 @@ void CollisionPipeline::checkDataValues() } } -void CollisionPipeline::doCollisionReset() -{ - msg_info_when(d_doPrintInfoMessage.getValue()) - << "CollisionPipeline::doCollisionReset" ; - - // clear all contacts - if (contactManager != nullptr) - { - const type::vector& contacts = contactManager->getContacts(); - for (const auto& contact : contacts) - { - if (contact != nullptr) - { - contact->removeResponse(); - } - } - } - - // clear all collision groups - if (groupManager != nullptr) - { - core::objectmodel::BaseContext* scene = getContext(); - groupManager->clearGroups(scene); - } -} - -void CollisionPipeline::doCollisionDetection(const type::vector& collisionModels) -{ - SCOPED_TIMER_VARNAME(docollisiontimer, "doCollisionDetection"); - - msg_info_when(d_doPrintInfoMessage.getValue()) - << "doCollisionDetection, compute Bounding Trees" ; - - // First, we compute a bounding volume for the collision model (for example bounding sphere) - // or we have loaded a collision model that knows its other model - - type::vector vectBoundingVolume; - { - SCOPED_TIMER_VARNAME(bboxtimer, "ComputeBoundingTree"); - -#ifdef SOFA_DUMP_VISITOR_INFO - simulation::Visitor::printNode("ComputeBoundingTree"); -#endif - const bool continuous = intersectionMethod->useContinuous(); - const auto continuousIntersectionType = intersectionMethod->continuousIntersectionType(); - const SReal dt = getContext()->getDt(); - - type::vector::const_iterator it; - const type::vector::const_iterator itEnd = collisionModels.end(); - int nActive = 0; - - const int used_depth = ( - (broadPhaseDetection && broadPhaseDetection->needsDeepBoundingTree()) || - (narrowPhaseDetection && narrowPhaseDetection->needsDeepBoundingTree()) - ) ? d_depth.getValue() : 0; - - for (it = collisionModels.begin(); it != itEnd; ++it) - { - msg_info_when(d_doPrintInfoMessage.getValue()) - << "doCollisionDetection, consider model" ; - - if (!(*it)->isActive()) continue; - - if (continuous) - { - const std::string msg = "Compute Continuous BoundingTree: " + (*it)->getName(); - ScopedAdvancedTimer continuousBoundingTreeTimer(msg.c_str()); - (*it)->computeContinuousBoundingTree(dt, continuousIntersectionType, used_depth); - } - else - { - std::string msg = "Compute BoundingTree: " + (*it)->getName(); - ScopedAdvancedTimer boundingTreeTimer(msg.c_str()); - (*it)->computeBoundingTree(used_depth); - } - - vectBoundingVolume.push_back ((*it)->getFirst()); - ++nActive; - } - -#ifdef SOFA_DUMP_VISITOR_INFO - simulation::Visitor::printCloseNode("ComputeBoundingTree"); -#endif - - msg_info_when(d_doPrintInfoMessage.getValue()) - << "doCollisionDetection, Computed "<getName(); - -#ifdef SOFA_DUMP_VISITOR_INFO - simulation::Visitor::printNode("BroadPhase"); -#endif - { - SCOPED_TIMER_VARNAME(broadphase, "BroadPhase"); - intersectionMethod->beginBroadPhase(); - broadPhaseDetection->beginBroadPhase(); - broadPhaseDetection->addCollisionModels(vectBoundingVolume); // detection is done there - broadPhaseDetection->endBroadPhase(); - intersectionMethod->endBroadPhase(); - } -#ifdef SOFA_DUMP_VISITOR_INFO - simulation::Visitor::printCloseNode("BroadPhase"); -#endif - - // then we start the narrow phase - if (narrowPhaseDetection == nullptr) - { - return; // can't go further - } - - msg_info_when(d_doPrintInfoMessage.getValue()) - << "doCollisionDetection, NarrowPhaseDetection "<getName(); - -#ifdef SOFA_DUMP_VISITOR_INFO - simulation::Visitor::printNode("NarrowPhase"); -#endif - { - SCOPED_TIMER_VARNAME(narrowphase, "NarrowPhase"); - intersectionMethod->beginNarrowPhase(); - narrowPhaseDetection->beginNarrowPhase(); - const type::vector >& vectCMPair = broadPhaseDetection->getCollisionModelPairs(); - - msg_info_when(d_doPrintInfoMessage.getValue()) - << "doCollisionDetection, "<< vectCMPair.size()<<" colliding model pairs" ; - - narrowPhaseDetection->addCollisionPairs(vectCMPair); - narrowPhaseDetection->endNarrowPhase(); - intersectionMethod->endNarrowPhase(); - } -#ifdef SOFA_DUMP_VISITOR_INFO - simulation::Visitor::printCloseNode("NarrowPhase"); -#endif - -} - -void CollisionPipeline::doCollisionResponse() -{ - core::objectmodel::BaseContext* scene = getContext(); - // then we start the creation of contacts - if (narrowPhaseDetection == nullptr || contactManager == nullptr) - { - return; // can't go further - } - - msg_info_when(d_doPrintInfoMessage.getValue()) - << "Create Contacts " << contactManager->getName() ; - - { - SCOPED_TIMER_VARNAME(createContactsTimer, "CreateContacts"); - contactManager->createContacts(narrowPhaseDetection->getDetectionOutputs()); - } - - // finally we start the creation of collisionGroup - - const type::vector& contacts = contactManager->getContacts(); - - // First we remove all contacts with non-simulated objects and directly add them - type::vector notStaticContacts; - - { - SCOPED_TIMER_VARNAME(createStaticObjectsResponseTimer, "CreateStaticObjectsResponse"); - for (const auto& contact : contacts) - { - const auto collisionModels = contact->getCollisionModels(); - if (collisionModels.first != nullptr && !collisionModels.first->isSimulated()) - { - contact->createResponse(collisionModels.second->getContext()); - } - else if (collisionModels.second != nullptr && !collisionModels.second->isSimulated()) - { - contact->createResponse(collisionModels.first->getContext()); - } - else - { - notStaticContacts.push_back(contact); - } - } - } - - if (groupManager == nullptr) - { - SCOPED_TIMER_VARNAME(createResponseTimer, "CreateMovingObjectsResponse"); - - msg_info_when(d_doPrintInfoMessage.getValue()) - << "Linking all contacts to Scene" ; - - for (const auto& contact : notStaticContacts) - { - contact->createResponse(scene); - } - } - else - { - msg_info_when(d_doPrintInfoMessage.getValue()) - << "Create Groups "<getName(); - - groupManager->createGroups(scene, notStaticContacts); - } -} - -std::set< std::string > CollisionPipeline::getResponseList() const -{ - std::set< std::string > listResponse; - core::collision::Contact::Factory::iterator it; - for (it=core::collision::Contact::Factory::getInstance()->begin(); it!=core::collision::Contact::Factory::getInstance()->end(); ++it) - { - listResponse.insert(it->first); - } - return listResponse; -} - } // namespace sofa::component::collision::detection::algorithm diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.h index 8d7a2233213..d497092d498 100644 --- a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.h +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CollisionPipeline.h @@ -22,36 +22,30 @@ #pragma once #include -#include +#include +#include namespace sofa::component::collision::detection::algorithm { -class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API CollisionPipeline : public sofa::simulation::PipelineImpl +class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API CollisionPipeline : public CompositeCollisionPipeline { public: - SOFA_CLASS(CollisionPipeline,sofa::simulation::PipelineImpl); + SOFA_CLASS(CollisionPipeline, CompositeCollisionPipeline); Data d_doPrintInfoMessage; Data d_doDebugDraw; Data d_depth; + protected: CollisionPipeline(); public: void init() override; - /// get the set of response available with the current collision pipeline - std::set< std::string > getResponseList() const override; protected: - // -- Pipeline interface - /// Remove collision response from last step - void doCollisionReset() override; - /// Detect new collisions. Note that this step must not modify the simulation graph - void doCollisionDetection(const sofa::type::vector& collisionModels) override; - /// Add collision response in the simulation graph - void doCollisionResponse() override; - virtual void checkDataValues() ; + + SubCollisionPipeline::SPtr m_subCollisionPipeline; public: static const int defaultDepthValue; diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.cpp new file mode 100644 index 00000000000..0f6691f4054 --- /dev/null +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.cpp @@ -0,0 +1,193 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +using sofa::helper::ScopedAdvancedTimer ; + +#include + + +namespace sofa::component::collision::detection::algorithm +{ + +using namespace sofa; +using namespace sofa::core; +using namespace sofa::core::collision; + +void registerCompositeCollisionPipeline(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(core::ObjectRegistrationData("Multiple collision pipelines in one.") + .add< CompositeCollisionPipeline >()); +} + +CompositeCollisionPipeline::CompositeCollisionPipeline() + : d_parallelDetection(initData(&d_parallelDetection, false, "parallelDetection", "Parallelize collision detection.")) + , l_subCollisionPipelines(initLink("subCollisionPipelines", "List of sub collision pipelines to handle.")) +{ +} + +void CompositeCollisionPipeline::init() +{ + Inherit1::init(); + + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); + + if(l_subCollisionPipelines.size() == 0) + { + msg_warning() << "No SubCollisionPipeline defined in CompositeCollisionPipeline. Nothing will be done." ; + + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + return; + } + + if(d_parallelDetection.getValue()) + { + this->initTaskScheduler(); + } + + // UX: warn if there is any CollisionModel not handled by any SubCollisionPipeline + simulation::Node* root = dynamic_cast(getContext()); + std::vector sceneCollisionModels; + root->getTreeObjects(&sceneCollisionModels); + + std::set pipelineCollisionModels; + for(auto* subPipeline : l_subCollisionPipelines) + { + if(!subPipeline) + { + msg_error() << "One of the subCollisionPipeline is incorrect (nullptr or invalid) "; + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + return; + } + + for (auto* cm : subPipeline->getCollisionModels()) + { + pipelineCollisionModels.insert(cm); + } + } + + for (const auto& cm : sceneCollisionModels) + { + if (pipelineCollisionModels.find(cm) == pipelineCollisionModels.end()) + { + msg_warning() << "CollisionModel " << cm->getPathName() << " is not handled by any SubCollisionPipeline."; + } + } + +} + +void CompositeCollisionPipeline::reset() +{ + +} + +void CompositeCollisionPipeline::doCollisionReset() +{ + msg_info() << "CompositeCollisionPipeline::doCollisionReset" ; + + for(const auto& subPipeline : l_subCollisionPipelines) + { + subPipeline->computeCollisionReset(); + } +} + +void CompositeCollisionPipeline::doCollisionDetection(const type::vector& collisionModels) +{ + SOFA_UNUSED(collisionModels); + + SCOPED_TIMER_VARNAME(docollisiontimer, "doCollisionDetection"); + + if(m_taskScheduler) + { + auto computeCollisionDetection = [&](const auto& range) + { + for (auto it = range.start; it != range.end; ++it) + { + (*it)->computeCollisionDetection(); + } + }; + + sofa::simulation::forEachRange(sofa::simulation::ForEachExecutionPolicy::PARALLEL, *m_taskScheduler, l_subCollisionPipelines.begin(), l_subCollisionPipelines.end(), computeCollisionDetection); + } + else + { + for (const auto& subPipeline : l_subCollisionPipelines) + { + subPipeline->computeCollisionDetection(); + } + } +} + +void CompositeCollisionPipeline::doCollisionResponse() +{ + for (const auto& subPipeline : l_subCollisionPipelines) + { + subPipeline->computeCollisionResponse(); + } +} + +std::set< std::string > CompositeCollisionPipeline::getResponseList() const +{ + return BaseSubCollisionPipeline::getResponseList(); +} + +void CompositeCollisionPipeline::computeCollisionReset() +{ + if(!this->isComponentStateValid()) + return; + + doCollisionReset(); +} + +void CompositeCollisionPipeline::computeCollisionDetection() +{ + if(!this->isComponentStateValid()) + return; + + //useless + static std::vector collisionModels{}; + + doCollisionDetection(collisionModels); +} + +void CompositeCollisionPipeline::computeCollisionResponse() +{ + if(!this->isComponentStateValid()) + return; + + doCollisionResponse(); +} + +} // namespace sofa::component::collision::detection::algorithm diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.h new file mode 100644 index 00000000000..3e28a8c86b0 --- /dev/null +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/CompositeCollisionPipeline.h @@ -0,0 +1,73 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include + +#include + +namespace sofa::component::collision::detection::algorithm +{ + +class BaseSubCollisionPipeline; + +class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API CompositeCollisionPipeline : public sofa::core::collision::Pipeline, public sofa::simulation::TaskSchedulerUser +{ +public: + SOFA_CLASS2(CompositeCollisionPipeline, sofa::core::collision::Pipeline, sofa::simulation::TaskSchedulerUser); + + sofa::Data d_depth; +protected: + CompositeCollisionPipeline(); +public: + void init() override; + + /// get the set of response available with the current collision pipeline + std::set< std::string > getResponseList() const override; +protected: + // -- Pipeline interface + /// Remove collision response from last step + void doCollisionReset() override; + /// Detect new collisions. Note that this step must not modify the simulation graph + void doCollisionDetection(const sofa::type::vector& collisionModels) override; + /// Add collision response in the simulation graph + void doCollisionResponse() override; + + void reset() override; + + /// Remove collision response from last step + virtual void computeCollisionReset() override final; + /// Detect new collisions. Note that this step must not modify the simulation graph + virtual void computeCollisionDetection() override final; + /// Add collision response in the simulation graph + virtual void computeCollisionResponse() override final; + +public: + sofa::Data d_parallelDetection; + sofa::MultiLink < CompositeCollisionPipeline, BaseSubCollisionPipeline, sofa::BaseLink::FLAG_DUPLICATE > l_subCollisionPipelines; + + + friend class CollisionPipeline; // to be able to call do*() +}; + +} // namespace sofa::component::collision::detection::algorithm diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.cpp new file mode 100644 index 00000000000..a8449c5a1cd --- /dev/null +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.cpp @@ -0,0 +1,271 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include + +#include + +#include + +#include + +#include +using sofa::helper::ScopedAdvancedTimer ; + +#include + + +namespace sofa::component::collision::detection::algorithm +{ + +using namespace sofa; +using namespace sofa::core; +using namespace sofa::core::collision; + +void registerSubCollisionPipeline(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(core::ObjectRegistrationData("Collision pipeline to be used with CompositeCollisionPipeline.") + .add< SubCollisionPipeline >()); +} + +SubCollisionPipeline::SubCollisionPipeline() + : Inherited() + , d_depth(initData(&d_depth, s_defaultDepthValue, "depth", +("Max depth of bounding trees. (default=" + std::to_string(s_defaultDepthValue) + ", min=?, max=?)").c_str())) + , l_collisionModels(initLink("collisionModels", "List of collision models to consider in this pipeline")) + , l_intersectionMethod(initLink("intersectionMethod", "Intersection method to use in this pipeline")) + , l_contactManager(initLink("contactManager", "Contact manager to use in this pipeline")) + , l_broadPhaseDetection(initLink("broadPhaseDetection", "Broad phase detection to use in this pipeline")) + , l_narrowPhaseDetection(initLink("narrowPhaseDetection", "Narrow phase detection to use in this pipeline")) +{ +} + +void SubCollisionPipeline::doInit() +{ + bool validity = true; + + //Check given parameters + if (l_collisionModels.size() == 0) + { + msg_warning() << "At least one CollisionModel is required to compute collision detection."; + validity = false; + } + + if (!l_intersectionMethod) + { + msg_warning() << "An Intersection detection component is required to compute collision detection."; + validity = false; + } + + if (!l_contactManager) + { + msg_warning() << "A contact manager component is required to compute collision detection."; + validity = false; + } + + if (!l_broadPhaseDetection) + { + msg_warning() << "A BroadPhase component is required to compute collision detection."; + validity = false; + } + if (!l_narrowPhaseDetection) + { + msg_warning() << "A NarrowPhase component is required to compute collision detection."; + validity = false; + } + + if (!validity) + { + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + } + else + { + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); + } + +} + +void SubCollisionPipeline::computeCollisionReset() +{ + if (!this->isComponentStateValid()) + return; + + msg_info() << "SubCollisionPipeline::doCollisionReset"; + + l_broadPhaseDetection->setIntersectionMethod(l_intersectionMethod.get()); + l_narrowPhaseDetection->setIntersectionMethod(l_intersectionMethod.get()); + l_contactManager->setIntersectionMethod(l_intersectionMethod.get()); + + // clear all contacts + const type::vector& contacts = l_contactManager->getContacts(); + for (const auto& contact : contacts) + { + if (contact != nullptr) + { + contact->removeResponse(); + } + } +} + +void SubCollisionPipeline::computeCollisionDetection() +{ + SCOPED_TIMER_VARNAME(docollisiontimer, "doCollisionDetection"); + + if (!this->isComponentStateValid()) + return; + + msg_info() << "doCollisionDetection, compute Bounding Trees" ; + + // First, we compute a bounding volume for the collision model (for example bounding sphere) + // or we have loaded a collision model that knows its other model + + type::vector vectBoundingVolume; + { + SCOPED_TIMER_VARNAME(bboxtimer, "ComputeBoundingTree"); + + const bool continuous = l_intersectionMethod->useContinuous(); + const auto continuousIntersectionType = l_intersectionMethod->continuousIntersectionType(); + const SReal dt = getContext()->getDt(); + + int nActive = 0; + + const int used_depth = ( + (l_broadPhaseDetection->needsDeepBoundingTree()) || + (l_narrowPhaseDetection->needsDeepBoundingTree()) + ) ? d_depth.getValue() : 0; + + for (auto it = l_collisionModels.begin(); it != l_collisionModels.end(); ++it) + { + msg_info() << "doCollisionDetection, consider model" ; + + if (!(*it)->isActive()) continue; + + if (continuous) + { + const std::string msg = "Compute Continuous BoundingTree: " + (*it)->getName(); + ScopedAdvancedTimer continuousBoundingTreeTimer(msg.c_str()); + (*it)->computeContinuousBoundingTree(dt, continuousIntersectionType, used_depth); + } + else + { + std::string msg = "Compute BoundingTree: " + (*it)->getName(); + ScopedAdvancedTimer boundingTreeTimer(msg.c_str()); + (*it)->computeBoundingTree(used_depth); + } + + vectBoundingVolume.push_back ((*it)->getFirst()); + ++nActive; + } + + + msg_info() << "doCollisionDetection, Computed "<getName(); + + { + SCOPED_TIMER_VARNAME(broadphase, "BroadPhase"); + l_intersectionMethod->beginBroadPhase(); + l_broadPhaseDetection->beginBroadPhase(); + l_broadPhaseDetection->addCollisionModels(vectBoundingVolume); // detection is done there + l_broadPhaseDetection->endBroadPhase(); + l_intersectionMethod->endBroadPhase(); + } + + msg_info() << "doCollisionDetection, NarrowPhaseDetection "<< l_narrowPhaseDetection->getName(); + + { + SCOPED_TIMER_VARNAME(narrowphase, "NarrowPhase"); + l_intersectionMethod->beginNarrowPhase(); + l_narrowPhaseDetection->beginNarrowPhase(); + const type::vector >& vectCMPair = l_broadPhaseDetection->getCollisionModelPairs(); + + msg_info() << "doCollisionDetection, "<< vectCMPair.size()<<" colliding model pairs" ; + + l_narrowPhaseDetection->addCollisionPairs(vectCMPair); + l_narrowPhaseDetection->endNarrowPhase(); + l_intersectionMethod->endNarrowPhase(); + } + +} + +void SubCollisionPipeline::computeCollisionResponse() +{ + if (!this->isComponentStateValid()) + return; + + core::objectmodel::BaseContext* scene = getContext(); + + msg_info() << "Create Contacts " << l_contactManager->getName() ; + + { + SCOPED_TIMER_VARNAME(createContactsTimer, "CreateContacts"); + l_contactManager->createContacts(l_narrowPhaseDetection->getDetectionOutputs()); + } + + // finally we start the creation of collisionGroup + const type::vector& contacts = l_contactManager->getContacts(); + + // First we remove all contacts with non-simulated objects and directly add them + type::vector notStaticContacts; + + { + SCOPED_TIMER_VARNAME(createStaticObjectsResponseTimer, "CreateStaticObjectsResponse"); + for (const auto& contact : contacts) + { + const auto collisionModels = contact->getCollisionModels(); + if (collisionModels.first != nullptr && !collisionModels.first->isSimulated()) + { + contact->createResponse(collisionModels.second->getContext()); + } + else if (collisionModels.second != nullptr && !collisionModels.second->isSimulated()) + { + contact->createResponse(collisionModels.first->getContext()); + } + else + { + notStaticContacts.push_back(contact); + } + } + } + + SCOPED_TIMER_VARNAME(createResponseTimer, "CreateMovingObjectsResponse"); + + msg_info() << "Linking all contacts to Scene" ; + + for (const auto& contact : notStaticContacts) + { + contact->createResponse(scene); + } +} + + +std::vector SubCollisionPipeline::getCollisionModels() +{ + std::vector collisionModels; + collisionModels.reserve(l_collisionModels.getSize()); + for(auto* collisionModel : l_collisionModels) + { + collisionModels.push_back(collisionModel); + } + return collisionModels; +} + +} // namespace sofa::component::collision::detection::algorithm diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.h b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.h new file mode 100644 index 00000000000..ff535930df1 --- /dev/null +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/SubCollisionPipeline.h @@ -0,0 +1,67 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace sofa::component::collision::detection::algorithm +{ + +class SOFA_COMPONENT_COLLISION_DETECTION_ALGORITHM_API SubCollisionPipeline : public BaseSubCollisionPipeline +{ +public: + using Inherited = BaseSubCollisionPipeline; + SOFA_CLASS(SubCollisionPipeline, Inherited); +protected: + SubCollisionPipeline(); +public: + virtual ~SubCollisionPipeline() override = default; + void doInit() override; + void doHandleEvent(sofa::core::objectmodel::Event*) override {} + + void computeCollisionReset() override; + void computeCollisionDetection() override; + void computeCollisionResponse() override; + + std::vector getCollisionModels() override; + + sofa::Data d_depth; + sofa::MultiLink < SubCollisionPipeline, sofa::core::CollisionModel, sofa::BaseLink::FLAG_DUPLICATE > l_collisionModels; + sofa::SingleLink< SubCollisionPipeline, sofa::core::collision::Intersection, sofa::BaseLink::FLAG_STOREPATH | sofa::BaseLink::FLAG_STRONGLINK > l_intersectionMethod; + sofa::SingleLink< SubCollisionPipeline, sofa::core::collision::ContactManager, sofa::BaseLink::FLAG_STOREPATH | sofa::BaseLink::FLAG_STRONGLINK > l_contactManager; + sofa::SingleLink< SubCollisionPipeline, sofa::core::collision::BroadPhaseDetection, sofa::BaseLink::FLAG_STOREPATH | sofa::BaseLink::FLAG_STRONGLINK > l_broadPhaseDetection; + sofa::SingleLink< SubCollisionPipeline, sofa::core::collision::NarrowPhaseDetection, sofa::BaseLink::FLAG_STOREPATH | sofa::BaseLink::FLAG_STRONGLINK > l_narrowPhaseDetection; + + static inline constexpr unsigned int s_defaultDepthValue = 6; +}; + +} // namespace sofa::component::collision::detection::algorithm diff --git a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/init.cpp b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/init.cpp index d6e879397e0..b8ae17c38bf 100644 --- a/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/init.cpp +++ b/Sofa/Component/Collision/Detection/Algorithm/src/sofa/component/collision/detection/algorithm/init.cpp @@ -29,6 +29,8 @@ namespace sofa::component::collision::detection::algorithm extern void registerBruteForceBroadPhase(sofa::core::ObjectFactory* factory); extern void registerBruteForceDetection(sofa::core::ObjectFactory* factory); extern void registerBVHNarrowPhase(sofa::core::ObjectFactory* factory); +extern void registerCompositeCollisionPipeline(sofa::core::ObjectFactory* factory); +extern void registerSubCollisionPipeline(sofa::core::ObjectFactory* factory); extern void registerCollisionPipeline(sofa::core::ObjectFactory* factory); extern void registerDirectSAP(sofa::core::ObjectFactory* factory); extern void registerDirectSAPNarrowPhase(sofa::core::ObjectFactory* factory); @@ -64,6 +66,8 @@ void registerObjects(sofa::core::ObjectFactory* factory) registerBruteForceBroadPhase(factory); registerBruteForceDetection(factory); registerBVHNarrowPhase(factory); + registerCompositeCollisionPipeline(factory); + registerSubCollisionPipeline(factory); registerCollisionPipeline(factory); registerDirectSAP(factory); registerDirectSAPNarrowPhase(factory); diff --git a/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp b/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp index ae151f8efd5..9bb60fc3a8d 100644 --- a/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp +++ b/Sofa/Component/Collision/Detection/Algorithm/tests/CollisionPipeline_test.cpp @@ -72,12 +72,14 @@ class TestCollisionPipeline : public BaseSimulationTest { void checkCollisionPipelineWithMissingBroadPhase(); void checkCollisionPipelineWithMissingNarrowPhase(); void checkCollisionPipelineWithMissingContactManager(); + void checkCollisionPipelineWithMissingCollisionModel(); int checkCollisionPipelineWithMonkeyValueForDepth(int value); void doSetUp() override { this->loadPlugins({ Sofa.Component.StateContainer, + Sofa.Component.Collision.Geometry, Sofa.Component.Collision.Detection.Algorithm, Sofa.Component.Collision.Detection.Intersection, Sofa.Component.Collision.Response.Contact @@ -104,6 +106,10 @@ void TestCollisionPipeline::checkCollisionPipelineWithNoAttributes() " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" " \n" ; root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str()); @@ -127,6 +133,10 @@ void TestCollisionPipeline::checkCollisionPipelineWithMissingIntersection() " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" " \n" ; root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str()); @@ -149,6 +159,10 @@ void TestCollisionPipeline::checkCollisionPipelineWithMissingBroadPhase() " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" " \n" ; root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str()); @@ -170,8 +184,12 @@ void TestCollisionPipeline::checkCollisionPipelineWithMissingNarrowPhase() " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" " \n" ; - + root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str()); ASSERT_NE(root.get(), nullptr) ; root->init(sofa::core::execparams::defaultInstance()) ; @@ -191,6 +209,34 @@ void TestCollisionPipeline::checkCollisionPipelineWithMissingContactManager() " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" + " \n" ; + + root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str()); + ASSERT_NE(root.get(), nullptr) ; + root->init(sofa::core::execparams::defaultInstance()) ; + + BaseObject* clp = root->getObject("pipeline") ; + ASSERT_NE(clp, nullptr) ; + +} + +void TestCollisionPipeline::checkCollisionPipelineWithMissingCollisionModel() +{ + EXPECT_MSG_EMIT(Warning) ; + EXPECT_MSG_NOEMIT(Error) ; + + std::stringstream scene ; + scene << " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" " \n" ; root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str()); @@ -212,6 +258,10 @@ int TestCollisionPipeline::checkCollisionPipelineWithMonkeyValueForDepth(int dva " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" " \n" ; root = SceneLoaderXML::loadFromMemory ("testscene", scene.str().c_str()); @@ -252,6 +302,12 @@ TEST_F(TestCollisionPipeline, checkCollisionPipelineWithMissingContactManager) this->checkCollisionPipelineWithMissingContactManager(); } +TEST_F(TestCollisionPipeline, checkCollisionPipelineWithMissingCollisionModel) +{ + this->checkCollisionPipelineWithMissingCollisionModel(); +} + + TEST_F(TestCollisionPipeline, checkCollisionPipelineWithMonkeyValueForDepth_OpenIssue) { const std::vector> testvalues = { diff --git a/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn b/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn new file mode 100644 index 00000000000..50fdf09fd01 --- /dev/null +++ b/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn.view b/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn.view new file mode 100644 index 00000000000..0f039dffcad --- /dev/null +++ b/examples/Component/Collision/Detection/CompositeCollisionPipeline.scn.view @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn b/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn new file mode 100644 index 00000000000..9fd746092c6 --- /dev/null +++ b/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn.view b/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn.view new file mode 100644 index 00000000000..0f039dffcad --- /dev/null +++ b/examples/Component/Collision/Detection/CompositeCollisionPipeline_none.scn.view @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/RegressionStateScenes.regression-tests b/examples/RegressionStateScenes.regression-tests index 6270d2211ad..fc9ec569ad2 100644 --- a/examples/RegressionStateScenes.regression-tests +++ b/examples/RegressionStateScenes.regression-tests @@ -37,6 +37,8 @@ Demos/SofaScene.scn 120 1e-5 1 1 ### Component scenes ### Component/Collision/Response/RuleBasedContactManager.scn 100 1e-4 0 1 Component/Collision/Response/FrictionContact.scn 100 1e-4 0 1 +Component/Collision/Detection/CompositeCollisionPipeline.scn 200 1e-4 0 1 +Component/Collision/Detection/CompositeCollisionPipeline_none.scn 200 1e-4 0 1 Component/Constraint/Lagrangian/BilateralLagrangianConstraint_NNCG.scn 100 1e-4 0 1 Component/Constraint/Lagrangian/BilateralLagrangianConstraint_PGS.scn 100 1e-4 0 1 Component/Constraint/Lagrangian/BilateralLagrangianConstraint_UGS.scn 100 1e-4 0 1