summaryrefslogtreecommitdiff
path: root/examples/ReducedDeformableDemo/ReducedCollide.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/ReducedDeformableDemo/ReducedCollide.cpp')
-rw-r--r--examples/ReducedDeformableDemo/ReducedCollide.cpp522
1 files changed, 522 insertions, 0 deletions
diff --git a/examples/ReducedDeformableDemo/ReducedCollide.cpp b/examples/ReducedDeformableDemo/ReducedCollide.cpp
new file mode 100644
index 000000000..dd84946ae
--- /dev/null
+++ b/examples/ReducedDeformableDemo/ReducedCollide.cpp
@@ -0,0 +1,522 @@
+/*
+ Bullet Continuous Collision Detection and Physics Library
+ Copyright (c) 2019 Google Inc. http://bulletphysics.org
+ This software is provided 'as-is', without any express or implied warranty.
+ In no event will the authors be held liable for any damages arising from the use of this software.
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it freely,
+ subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include "ReducedCollide.h"
+///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
+#include "btBulletDynamicsCommon.h"
+#include "BulletSoftBody/btDeformableMultiBodyDynamicsWorld.h"
+#include "BulletSoftBody/BulletReducedDeformableBody/btReducedDeformableBody.h"
+#include "BulletSoftBody/BulletReducedDeformableBody/btReducedDeformableBodyHelpers.h"
+#include "BulletSoftBody/BulletReducedDeformableBody/btReducedDeformableBodySolver.h"
+#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h"
+#include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h"
+#include "../CommonInterfaces/CommonParameterInterface.h"
+#include <stdio.h> //printf debugging
+
+#include "../CommonInterfaces/CommonDeformableBodyBase.h"
+#include "../Utils/b3ResourcePath.h"
+
+///The BasicTest shows the contact between volumetric deformable objects and rigid objects.
+// static btScalar E = 50;
+// static btScalar nu = 0.3;
+static btScalar damping_alpha = 0.0;
+static btScalar damping_beta = 0.0;
+static btScalar COLLIDING_VELOCITY = 4;
+static int num_modes = 20;
+
+class ReducedCollide : public CommonDeformableBodyBase
+{
+public:
+ ReducedCollide(struct GUIHelperInterface* helper)
+ : CommonDeformableBodyBase(helper)
+ {
+ }
+ virtual ~ReducedCollide()
+ {
+ }
+ void initPhysics();
+
+ void exitPhysics();
+
+ btMultiBody* createFeatherstoneMultiBody_testMultiDof(class btMultiBodyDynamicsWorld* world, int numLinks, const btVector3& basePosition, const btVector3& baseHalfExtents, const btVector3& linkHalfExtents, bool spherical = false, bool floating = false);
+ void addColliders_testMultiDof(btMultiBody* pMultiBody, btMultiBodyDynamicsWorld* pWorld, const btVector3& baseHalfExtents, const btVector3& linkHalfExtents);
+
+ // TODO: disable pick force, non-interactive for now.
+ bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) {
+ return false;
+ }
+
+ void resetCamera()
+ {
+ // float dist = 20;
+ // float pitch = -10;
+ float dist = 10;
+ float pitch = -5;
+ float yaw = 90;
+ float targetPos[3] = {0, 0, 0};
+
+ // float dist = 5;
+ // float pitch = -35;
+ // float yaw = 50;
+ // float targetPos[3] = {-3, 2.8, -2.5};
+ m_guiHelper->resetCamera(dist, yaw, pitch, targetPos[0], targetPos[1], targetPos[2]);
+ }
+
+ void Ctor_RbUpStack()
+ {
+ float mass = 10;
+
+ btCollisionShape* shape = new btBoxShape(btVector3(0.5, 0.5, 0.5));
+ // btCollisionShape* shape = new btBoxShape(btVector3(1, 1, 1));
+ btVector3 localInertia(0, 0, 0);
+ if (mass != 0.f)
+ shape->calculateLocalInertia(mass, localInertia);
+
+ btTransform startTransform;
+ startTransform.setIdentity();
+ startTransform.setOrigin(btVector3(0,-2,0));
+ // startTransform.setRotation(btQuaternion(btVector3(1, 0, 1), SIMD_PI / 3.0));
+ btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
+
+ btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, shape, localInertia);
+ btRigidBody* body = new btRigidBody(rbInfo);
+
+ m_dynamicsWorld->addRigidBody(body, 1, 1+2);
+
+ body->setActivationState(DISABLE_DEACTIVATION);
+ body->setLinearVelocity(btVector3(0, COLLIDING_VELOCITY, 0));
+ // body->setFriction(1);
+ }
+
+ void rigidBar()
+ {
+ float mass = 10;
+
+ btCollisionShape* shape = new btBoxShape(btVector3(0.5, 0.25, 2));
+ btVector3 localInertia(0, 0, 0);
+ if (mass != 0.f)
+ shape->calculateLocalInertia(mass, localInertia);
+
+ btTransform startTransform;
+ startTransform.setIdentity();
+ startTransform.setOrigin(btVector3(0,10,0));
+ // startTransform.setRotation(btQuaternion(btVector3(1, 0, 1), SIMD_PI / 3.0));
+ btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
+
+ btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, shape, localInertia);
+ btRigidBody* body = new btRigidBody(rbInfo);
+
+ m_dynamicsWorld->addRigidBody(body, 1, 1+2);
+
+ body->setActivationState(DISABLE_DEACTIVATION);
+ body->setLinearVelocity(btVector3(0, 0, 0));
+ // body->setFriction(0);
+ }
+
+ void createGround()
+ {
+ // float mass = 55;
+ float mass = 0;
+
+ btCollisionShape* shape = new btBoxShape(btVector3(10, 2, 10));
+ btVector3 localInertia(0, 0, 0);
+ if (mass != 0.f)
+ shape->calculateLocalInertia(mass, localInertia);
+
+ btTransform startTransform;
+ startTransform.setIdentity();
+ startTransform.setOrigin(btVector3(0,-2,0));
+ // startTransform.setRotation(btQuaternion(btVector3(1, 0, 1), SIMD_PI / 3.0));
+ btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
+
+ btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, shape, localInertia);
+ btRigidBody* body = new btRigidBody(rbInfo);
+
+ m_dynamicsWorld->addRigidBody(body, 1, 1+2);
+
+ body->setActivationState(DISABLE_DEACTIVATION);
+ body->setLinearVelocity(btVector3(0, 0, 0));
+ // body->setFriction(1);
+ }
+
+ void stepSimulation(float deltaTime)
+ {
+ float internalTimeStep = 1. / 60.f;
+ m_dynamicsWorld->stepSimulation(deltaTime, 1, internalTimeStep);
+ }
+
+ virtual void renderScene()
+ {
+ CommonDeformableBodyBase::renderScene();
+ btDeformableMultiBodyDynamicsWorld* deformableWorld = getDeformableDynamicsWorld();
+
+ for (int i = 0; i < deformableWorld->getSoftBodyArray().size(); i++)
+ {
+ btReducedDeformableBody* rsb = static_cast<btReducedDeformableBody*>(deformableWorld->getSoftBodyArray()[i]);
+ {
+ btSoftBodyHelpers::DrawFrame(rsb, deformableWorld->getDebugDrawer());
+ btSoftBodyHelpers::Draw(rsb, deformableWorld->getDebugDrawer(), deformableWorld->getDrawFlags());
+ }
+
+ for (int p = 0; p < rsb->m_contactNodesList.size(); ++p)
+ {
+ int index = rsb->m_contactNodesList[p];
+ deformableWorld->getDebugDrawer()->drawSphere(rsb->m_nodes[index].m_x, 0.2, btVector3(0, 1, 0));
+ }
+ }
+ }
+};
+
+void ReducedCollide::initPhysics()
+{
+ m_guiHelper->setUpAxis(1);
+
+ ///collision configuration contains default setup for memory, collision setup
+ m_collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration();
+
+ ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
+ m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
+
+ m_broadphase = new btDbvtBroadphase();
+ btReducedDeformableBodySolver* reducedSoftBodySolver = new btReducedDeformableBodySolver();
+ btVector3 gravity = btVector3(0, 0, 0);
+ reducedSoftBodySolver->setGravity(gravity);
+
+ btDeformableMultiBodyConstraintSolver* sol = new btDeformableMultiBodyConstraintSolver();
+ sol->setDeformableSolver(reducedSoftBodySolver);
+ m_solver = sol;
+
+ m_dynamicsWorld = new btDeformableMultiBodyDynamicsWorld(m_dispatcher, m_broadphase, sol, m_collisionConfiguration, reducedSoftBodySolver);
+ m_dynamicsWorld->setGravity(gravity);
+ m_dynamicsWorld->getSolverInfo().m_globalCfm = 1e-3;
+ m_dynamicsWorld->getSolverInfo().m_solverMode |= SOLVER_RANDMIZE_ORDER;
+ m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
+
+ // create volumetric reduced deformable body
+ {
+ std::string file_path("../../../data/reduced_cube/");
+ std::string vtk_file("cube_mesh.vtk");
+ btReducedDeformableBody* rsb = btReducedDeformableBodyHelpers::createReducedDeformableObject(
+ getDeformableDynamicsWorld()->getWorldInfo(),
+ file_path,
+ vtk_file,
+ num_modes,
+ false);
+
+ getDeformableDynamicsWorld()->addSoftBody(rsb);
+ rsb->getCollisionShape()->setMargin(0.1);
+ // rsb->scale(btVector3(0.5, 0.5, 0.5));
+
+ rsb->setStiffnessScale(100);
+ rsb->setDamping(damping_alpha, damping_beta);
+
+ rsb->setTotalMass(15);
+
+ btTransform init_transform;
+ init_transform.setIdentity();
+ init_transform.setOrigin(btVector3(0, 4, 0));
+ // init_transform.setRotation(btQuaternion(0, SIMD_PI / 2.0, SIMD_PI / 2.0));
+ rsb->transformTo(init_transform);
+
+ rsb->m_cfg.kKHR = 1; // collision hardness with kinematic objects
+ rsb->m_cfg.kCHR = 1; // collision hardness with rigid body
+ rsb->m_cfg.kDF = 0;
+ rsb->m_cfg.collisions = btSoftBody::fCollision::SDF_RD;
+ rsb->m_cfg.collisions |= btSoftBody::fCollision::SDF_RDN;
+ rsb->m_sleepingThreshold = 0;
+ btSoftBodyHelpers::generateBoundaryFaces(rsb);
+
+ rsb->setRigidVelocity(btVector3(0, -COLLIDING_VELOCITY, 0));
+ // rsb->setRigidAngularVelocity(btVector3(1, 0, 0));
+ b3Printf("total mass: %e", rsb->getTotalMass());
+ }
+ // rigidBar();
+
+ // add a few rigid bodies
+ Ctor_RbUpStack();
+
+ // create ground
+ // createGround();
+
+ // create multibody
+ // {
+ // bool damping = false;
+ // bool gyro = true;
+ // int numLinks = 0;
+ // bool spherical = true; //set it ot false -to use 1DoF hinges instead of 3DoF sphericals
+ // bool multibodyOnly = true;
+ // bool canSleep = false;
+ // bool selfCollide = true;
+ // bool multibodyConstraint = false;
+ // btVector3 linkHalfExtents(0.05, 0.37, 0.1);
+ // btVector3 baseHalfExtents(1, 1, 1);
+ // // btVector3 baseHalfExtents(2.5, 0.5, 2.5);
+ // // btVector3 baseHalfExtents(0.05, 0.37, 0.1);
+
+ // bool g_floatingBase = true;
+ // // btMultiBody* mbC = createFeatherstoneMultiBody_testMultiDof(m_dynamicsWorld, numLinks, btVector3(0, 4, 0), linkHalfExtents, baseHalfExtents, spherical, g_floatingBase);
+ // btMultiBody* mbC = createFeatherstoneMultiBody_testMultiDof(m_dynamicsWorld, numLinks, btVector3(0.f, 4.f, 0.f), baseHalfExtents, linkHalfExtents, spherical, g_floatingBase);
+ // //mbC->forceMultiDof(); //if !spherical, you can comment this line to check the 1DoF algorithm
+
+ // mbC->setCanSleep(canSleep);
+ // mbC->setHasSelfCollision(selfCollide);
+ // mbC->setUseGyroTerm(gyro);
+ // //
+ // if (!damping)
+ // {
+ // mbC->setLinearDamping(0.f);
+ // mbC->setAngularDamping(0.f);
+ // }
+ // else
+ // {
+ // mbC->setLinearDamping(0.1f);
+ // mbC->setAngularDamping(0.9f);
+ // }
+ // //
+ // //////////////////////////////////////////////
+ // // if (numLinks > 0)
+ // // {
+ // // btScalar q0 = 45.f * SIMD_PI / 180.f;
+ // // if (!spherical)
+ // // {
+ // // mbC->setJointPosMultiDof(0, &q0);
+ // // }
+ // // else
+ // // {
+ // // btQuaternion quat0(btVector3(1, 1, 0).normalized(), q0);
+ // // quat0.normalize();
+ // // mbC->setJointPosMultiDof(0, quat0);
+ // // }
+ // // }
+ // ///
+ // addColliders_testMultiDof(mbC, m_dynamicsWorld, baseHalfExtents, linkHalfExtents);
+ // }
+
+ getDeformableDynamicsWorld()->setImplicit(false);
+ getDeformableDynamicsWorld()->setLineSearch(false);
+ getDeformableDynamicsWorld()->setUseProjection(false);
+ getDeformableDynamicsWorld()->getSolverInfo().m_friction = 1;
+ getDeformableDynamicsWorld()->getSolverInfo().m_deformable_erp = 0.2;
+ getDeformableDynamicsWorld()->getSolverInfo().m_deformable_cfm = 0.2;
+ getDeformableDynamicsWorld()->getSolverInfo().m_deformable_maxErrorReduction = btScalar(200);
+ getDeformableDynamicsWorld()->getSolverInfo().m_leastSquaresResidualThreshold = 1e-3;
+ getDeformableDynamicsWorld()->getSolverInfo().m_splitImpulse = false;
+ getDeformableDynamicsWorld()->getSolverInfo().m_numIterations = 100;
+ m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
+
+ // {
+ // SliderParams slider("Young's Modulus", &E);
+ // slider.m_minVal = 0;
+ // slider.m_maxVal = 2000;
+ // if (m_guiHelper->getParameterInterface())
+ // m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
+ // }
+ // {
+ // SliderParams slider("Poisson Ratio", &nu);
+ // slider.m_minVal = 0.05;
+ // slider.m_maxVal = 0.49;
+ // if (m_guiHelper->getParameterInterface())
+ // m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
+ // }
+ // {
+ // SliderParams slider("Mass Damping", &damping_alpha);
+ // slider.m_minVal = 0;
+ // slider.m_maxVal = 1;
+ // if (m_guiHelper->getParameterInterface())
+ // m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
+ // }
+ // {
+ // SliderParams slider("Stiffness Damping", &damping_beta);
+ // slider.m_minVal = 0;
+ // slider.m_maxVal = 0.1;
+ // if (m_guiHelper->getParameterInterface())
+ // m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
+ // }
+}
+
+void ReducedCollide::exitPhysics()
+{
+ //cleanup in the reverse order of creation/initialization
+ removePickingConstraint();
+ //remove the rigidbodies from the dynamics world and delete them
+ int i;
+ for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--)
+ {
+ btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
+ btRigidBody* body = btRigidBody::upcast(obj);
+ if (body && body->getMotionState())
+ {
+ delete body->getMotionState();
+ }
+ m_dynamicsWorld->removeCollisionObject(obj);
+ delete obj;
+ }
+ // delete forces
+ for (int j = 0; j < m_forces.size(); j++)
+ {
+ btDeformableLagrangianForce* force = m_forces[j];
+ delete force;
+ }
+ m_forces.clear();
+
+ //delete collision shapes
+ for (int j = 0; j < m_collisionShapes.size(); j++)
+ {
+ btCollisionShape* shape = m_collisionShapes[j];
+ delete shape;
+ }
+ m_collisionShapes.clear();
+
+ delete m_dynamicsWorld;
+
+ delete m_solver;
+
+ delete m_broadphase;
+
+ delete m_dispatcher;
+
+ delete m_collisionConfiguration;
+}
+
+btMultiBody* ReducedCollide::createFeatherstoneMultiBody_testMultiDof(btMultiBodyDynamicsWorld* pWorld, int numLinks, const btVector3& basePosition, const btVector3& baseHalfExtents, const btVector3& linkHalfExtents, bool spherical, bool floating)
+{
+ //init the base
+ btVector3 baseInertiaDiag(0.f, 0.f, 0.f);
+ float baseMass = 10;
+
+ if (baseMass)
+ {
+ btCollisionShape* pTempBox = new btBoxShape(btVector3(baseHalfExtents[0], baseHalfExtents[1], baseHalfExtents[2]));
+ pTempBox->calculateLocalInertia(baseMass, baseInertiaDiag);
+ delete pTempBox;
+ }
+
+ bool canSleep = false;
+
+ btMultiBody* pMultiBody = new btMultiBody(numLinks, baseMass, baseInertiaDiag, !floating, canSleep);
+
+ btQuaternion baseOriQuat(0.f, 0.f, 0.f, 1.f);
+ // btQuaternion baseOriQuat(btVector3(0, 0, 1), -SIMD_PI / 6.0);
+ pMultiBody->setBasePos(basePosition);
+ pMultiBody->setWorldToBaseRot(baseOriQuat);
+ btVector3 vel(0, 0, 0);
+
+ //init the links
+ btVector3 hingeJointAxis(1, 0, 0);
+ float linkMass = 1.f;
+ btVector3 linkInertiaDiag(0.f, 0.f, 0.f);
+
+ btCollisionShape* pTempBox = new btBoxShape(btVector3(linkHalfExtents[0], linkHalfExtents[1], linkHalfExtents[2]));
+ pTempBox->calculateLocalInertia(linkMass, linkInertiaDiag);
+ delete pTempBox;
+
+ //y-axis assumed up
+ btVector3 parentComToCurrentCom(0, -linkHalfExtents[1] * 2.f, 0); //par body's COM to cur body's COM offset
+ btVector3 currentPivotToCurrentCom(0, -linkHalfExtents[1], 0); //cur body's COM to cur body's PIV offset
+ btVector3 parentComToCurrentPivot = parentComToCurrentCom - currentPivotToCurrentCom; //par body's COM to cur body's PIV offset
+
+ //////
+ btScalar q0 = 0.f * SIMD_PI / 180.f;
+ btQuaternion quat0(btVector3(0, 1, 0).normalized(), q0);
+ quat0.normalize();
+ /////
+
+ for (int i = 0; i < numLinks; ++i)
+ {
+ if (!spherical)
+ pMultiBody->setupRevolute(i, linkMass, linkInertiaDiag, i - 1, btQuaternion(0.f, 0.f, 0.f, 1.f), hingeJointAxis, parentComToCurrentPivot, currentPivotToCurrentCom, true);
+ else
+ //pMultiBody->setupPlanar(i, linkMass, linkInertiaDiag, i - 1, btQuaternion(0.f, 0.f, 0.f, 1.f)/*quat0*/, btVector3(1, 0, 0), parentComToCurrentPivot*2, false);
+ pMultiBody->setupSpherical(i, linkMass, linkInertiaDiag, i - 1, btQuaternion(0.f, 0.f, 0.f, 1.f), parentComToCurrentPivot, currentPivotToCurrentCom, true);
+ }
+
+ pMultiBody->finalizeMultiDof();
+ pMultiBody->setBaseVel(vel);
+
+ ///
+ pWorld->addMultiBody(pMultiBody);
+ ///
+ return pMultiBody;
+}
+
+void ReducedCollide::addColliders_testMultiDof(btMultiBody* pMultiBody, btMultiBodyDynamicsWorld* pWorld, const btVector3& baseHalfExtents, const btVector3& linkHalfExtents)
+{
+ btAlignedObjectArray<btQuaternion> world_to_local;
+ world_to_local.resize(pMultiBody->getNumLinks() + 1);
+
+ btAlignedObjectArray<btVector3> local_origin;
+ local_origin.resize(pMultiBody->getNumLinks() + 1);
+ world_to_local[0] = pMultiBody->getWorldToBaseRot();
+ local_origin[0] = pMultiBody->getBasePos();
+
+ {
+ // float pos[4]={local_origin[0].x(),local_origin[0].y(),local_origin[0].z(),1};
+ btScalar quat[4] = {-world_to_local[0].x(), -world_to_local[0].y(), -world_to_local[0].z(), world_to_local[0].w()};
+
+ if (1)
+ {
+ btCollisionShape* box = new btBoxShape(baseHalfExtents);
+ btMultiBodyLinkCollider* col = new btMultiBodyLinkCollider(pMultiBody, -1);
+ col->setCollisionShape(box);
+
+ btTransform tr;
+ tr.setIdentity();
+ tr.setOrigin(local_origin[0]);
+ tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
+ col->setWorldTransform(tr);
+
+ pWorld->addCollisionObject(col, 2, 1 + 2);
+
+ col->setFriction(1);
+ pMultiBody->setBaseCollider(col);
+ }
+ }
+
+ for (int i = 0; i < pMultiBody->getNumLinks(); ++i)
+ {
+ const int parent = pMultiBody->getParent(i);
+ world_to_local[i + 1] = pMultiBody->getParentToLocalRot(i) * world_to_local[parent + 1];
+ local_origin[i + 1] = local_origin[parent + 1] + (quatRotate(world_to_local[i + 1].inverse(), pMultiBody->getRVector(i)));
+ }
+
+ for (int i = 0; i < pMultiBody->getNumLinks(); ++i)
+ {
+ btVector3 posr = local_origin[i + 1];
+ // float pos[4]={posr.x(),posr.y(),posr.z(),1};
+
+ btScalar quat[4] = {-world_to_local[i + 1].x(), -world_to_local[i + 1].y(), -world_to_local[i + 1].z(), world_to_local[i + 1].w()};
+
+ btCollisionShape* box = new btBoxShape(linkHalfExtents);
+ btMultiBodyLinkCollider* col = new btMultiBodyLinkCollider(pMultiBody, i);
+
+ col->setCollisionShape(box);
+ btTransform tr;
+ tr.setIdentity();
+ tr.setOrigin(posr);
+ tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
+ col->setWorldTransform(tr);
+ col->setFriction(1);
+ pWorld->addCollisionObject(col, 2, 1 + 2);
+
+ pMultiBody->getLink(i).m_collider = col;
+ }
+}
+
+
+
+class CommonExampleInterface* ReducedCollideCreateFunc(struct CommonExampleOptions& options)
+{
+ return new ReducedCollide(options.m_guiHelper);
+}
+
+