From ed13cc6c265a461f7d2896940cb408849b8045db Mon Sep 17 00:00:00 2001 From: Benjamin Ellenberger Date: Mon, 11 Jul 2016 23:07:48 +0200 Subject: [PATCH] Add a slider to displace pendula via GUI. ------------------------------------------------ The slider applies the selected displacement force according to the chosen scalar and falls back to zero when moved below an absolute value of 0.2. --- examples/ExampleBrowser/ExampleEntries.cpp | 6 +- examples/ExtendedTutorials/MultiPendulum.cpp | 62 ++++++++---- examples/ExtendedTutorials/NewtonsCradle.cpp | 65 +++++++++--- .../ExtendedTutorials/NewtonsRopeCradle.cpp | 98 +++++++++++++------ 4 files changed, 166 insertions(+), 65 deletions(-) diff --git a/examples/ExampleBrowser/ExampleEntries.cpp b/examples/ExampleBrowser/ExampleEntries.cpp index c749e04ba..dbfa792d1 100644 --- a/examples/ExampleBrowser/ExampleEntries.cpp +++ b/examples/ExampleBrowser/ExampleEntries.cpp @@ -282,9 +282,9 @@ static ExampleEntry gDefaultExamples[]= ExampleEntry(1,"Simple Chain", "Create a simple chain using a pair of point2point/distance constraints. You may click and drag any box to see the chain respond.", ET_ChainCreateFunc), ExampleEntry(1,"Simple Bridge", "Create a simple bridge using a pair of point2point/distance constraints. You may click and drag any plank to see the bridge respond.", ET_BridgeCreateFunc), ExampleEntry(1,"Inclined Plane", "Create an inclined plane to show restitution and different types of friction. Use the sliders to vary restitution and friction and press space to reset the scene.", ET_InclinedPlaneCreateFunc), - ExampleEntry(1,"Newton's Cradle", "Create a Newton's Cradle using a pair of point2point/slider constraints. Press 1/2 to lengthen/shorten the pendula, press 3 to displace pendula. Use the sliders to select the number of pendula in total (reset simulation), the number of displaced pendula and other options.", ET_NewtonsCradleCreateFunc), - ExampleEntry(1,"Newton's Rope Cradle", "Create a Newton's Cradle using ropes. Press 3 to displace pendula. Use the sliders to select the number of pendula in total (reset simulation) and the number of displaced pendula.",ET_NewtonsRopeCradleCreateFunc), - ExampleEntry(1,"Multi-Pendulum", "Create a Multi-Pendulum using point2point/slider constraints. Press 1/2 to lengthen/shorten the pendula, press 3 to displace pendula. Use the sliders to select the number of pendula in total (reset simulation), the number of displaced pendula and other options.",ET_MultiPendulumCreateFunc), + ExampleEntry(1,"Newton's Cradle", "Create a Newton's Cradle using a pair of point2point/slider constraints. Press 1/2 to lengthen/shorten the pendula, press 3 to displace pendula. Use the sliders to select the number (reset simulation), length and restitution of pendula, the number of displaced pendula and apply the displacement force.", ET_NewtonsCradleCreateFunc), + ExampleEntry(1,"Newton's Rope Cradle", "Create a Newton's Cradle using ropes. Press 3 to displace pendula. Use the sliders to select the number (reset simulation), length and restitution of pendula and the number of displaced pendula and apply the displacement force.",ET_NewtonsRopeCradleCreateFunc), + ExampleEntry(1,"Multi-Pendulum", "Create a Multi-Pendulum using point2point/slider constraints. Press 1/2 to lengthen/shorten the pendula, press 3 to displace pendula. Use the sliders to select the number (reset simulation), length and restitution of pendula, the number of displaced pendula and apply the displacement force.",ET_MultiPendulumCreateFunc), //todo: create a category/tutorial about advanced topics, such as optimizations, using different collision detection algorithm, different constraint solvers etc. diff --git a/examples/ExtendedTutorials/MultiPendulum.cpp b/examples/ExtendedTutorials/MultiPendulum.cpp index 0d29ce12d..5e1fa59e1 100644 --- a/examples/ExtendedTutorials/MultiPendulum.cpp +++ b/examples/ExtendedTutorials/MultiPendulum.cpp @@ -38,6 +38,8 @@ static btScalar gInitialPendulumLength = 8; // Default pendulum length (distance static btScalar gDisplacementForce = 30; // The default force with which we move the pendulum +static btScalar gForceScalar = 0; // default force scalar to apply a displacement + struct MultiPendulumExample: public CommonRigidBodyBase { MultiPendulumExample(struct GUIHelperInterface* helper) : CommonRigidBodyBase(helper) { @@ -47,21 +49,13 @@ struct MultiPendulumExample: public CommonRigidBodyBase { } virtual void initPhysics(); // build a multi pendulum - virtual void renderScene(); // render the scene to screen - - virtual void createMultiPendulum(btSphereShape* colShape, - btScalar pendulaQty, btScalar xPosition, btScalar yPosition,btScalar zPosition, - btScalar length, btScalar mass); // create a multi pendulum at the indicated x and y position, the specified number of pendula formed into a chain, each with indicated length and mass - + virtual void createMultiPendulum(btSphereShape* colShape, btScalar pendulaQty, btScalar xPosition, btScalar yPosition,btScalar zPosition, btScalar length, btScalar mass); // create a multi pendulum at the indicated x and y position, the specified number of pendula formed into a chain, each with indicated length and mass virtual void changePendulaLength(btScalar length); // change the pendulum length - virtual void changePendulaRestitution(btScalar restitution); // change the pendula restitution - virtual void stepSimulation(float deltaTime); // step the simulation - virtual bool keyboardCallback(int key, int state); // handle keyboard callbacks - + virtual void applyPendulumForce(btScalar pendulumForce); void resetCamera() { float dist = 41; float pitch = 52; @@ -72,7 +66,6 @@ struct MultiPendulumExample: public CommonRigidBodyBase { } std::vector constraints; // keep a handle to the slider constraints - std::vector pendula; // keep a handle to the pendula }; @@ -84,6 +77,8 @@ void onMultiPendulaRestitutionChanged(float pendulaRestitution); // change the p void floorMSliderValue(float notUsed); // floor the slider values which should be integers +void applyMForceWithForceScalar(float forceScalar); + void MultiPendulumExample::initPhysics() { // Setup your physics scene { // create a slider to change the number of pendula @@ -135,6 +130,15 @@ void MultiPendulumExample::initPhysics() { // Setup your physics scene slider); } + { // create a slider to apply the force by slider + SliderParams slider("Apply displacement force", &gForceScalar); + slider.m_minVal = -1; + slider.m_maxVal = 1; + slider.m_clampToNotches = false; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( + slider); + } + m_guiHelper->setUpAxis(1); createEmptyDynamicsWorld(); @@ -168,10 +172,12 @@ void MultiPendulumExample::initPhysics() { // Setup your physics scene } void MultiPendulumExample::stepSimulation(float deltaTime) { + + applyMForceWithForceScalar(gForceScalar); // apply force defined by apply force slider + if (m_dynamicsWorld) { m_dynamicsWorld->stepSimulation(deltaTime); } - } void MultiPendulumExample::createMultiPendulum(btSphereShape* colShape, @@ -352,7 +358,7 @@ bool MultiPendulumExample::keyboardCallback(int key, int state) { //key 1, key 2, key 3 switch (key) { - case 49 /*ASCII for 1*/: { + case '1' /*ASCII for 1*/: { //assumption: Sphere are aligned in Z axis btScalar newLimit = btScalar(gCurrentPendulumLength + 0.1); @@ -363,7 +369,7 @@ bool MultiPendulumExample::keyboardCallback(int key, int state) { b3Printf("Increase pendulum length to %f", gCurrentPendulumLength); return true; } - case 50 /*ASCII for 2*/: { + case '2' /*ASCII for 2*/: { //assumption: Sphere are aligned in Z axis btScalar newLimit = btScalar(gCurrentPendulumLength - 0.1); @@ -377,11 +383,8 @@ bool MultiPendulumExample::keyboardCallback(int key, int state) { b3Printf("Decrease pendulum length to %f", gCurrentPendulumLength); return true; } - case 51 /*ASCII for 3*/: { - for (int i = floor(gPendulaQty)-1; i >= gPendulaQty-gDisplacedPendula; i--) { - if (gDisplacedPendula >= 0 && gDisplacedPendula < gPendulaQty) - pendula[i]->applyCentralForce(btVector3(gDisplacementForce, 0, 0)); - } + case '3' /*ASCII for 3*/: { + applyPendulumForce(gDisplacementForce); return true; } } @@ -389,6 +392,16 @@ bool MultiPendulumExample::keyboardCallback(int key, int state) { return false; } +void MultiPendulumExample::applyPendulumForce(btScalar pendulumForce){ + if(pendulumForce != 0){ + b3Printf("Apply %f to pendulum",pendulumForce); + for (int i = 0; i < gDisplacedPendula; i++) { + if (gDisplacedPendula >= 0 && gDisplacedPendula <= gPendulaQty) + pendula[i]->applyCentralForce(btVector3(pendulumForce, 0, 0)); + } + } +} + // GUI parameter modifiers void onMultiPendulaLengthChanged(float pendulaLength) { // Change the pendula length @@ -411,6 +424,17 @@ void floorMSliderValue(float notUsed) { // floor the slider values which should gDisplacedPendula = floor(gDisplacedPendula); } +void applyMForceWithForceScalar(float forceScalar) { + if(mex){ + btScalar appliedForce = forceScalar * gDisplacementForce; + + if(fabs(gForceScalar) < 0.2f) + gForceScalar = 0; + + mex->applyPendulumForce(appliedForce); + } +} + CommonExampleInterface* ET_MultiPendulumCreateFunc( CommonExampleOptions& options) { mex = new MultiPendulumExample(options.m_guiHelper); diff --git a/examples/ExtendedTutorials/NewtonsCradle.cpp b/examples/ExtendedTutorials/NewtonsCradle.cpp index a8b8d5773..baa7536fc 100644 --- a/examples/ExtendedTutorials/NewtonsCradle.cpp +++ b/examples/ExtendedTutorials/NewtonsCradle.cpp @@ -38,7 +38,9 @@ static btScalar gCurrentPendulumLength = 8; // current pendula length static btScalar gInitialPendulumLength = 8; // default pendula length -static btScalar gForcingForce = 30; // default force to displace the pendula +static btScalar gDisplacementForce = 30; // default force to displace the pendula + +static btScalar gForceScalar = 0; // default force scalar to apply a displacement struct NewtonsCradleExample: public CommonRigidBodyBase { NewtonsCradleExample(struct GUIHelperInterface* helper) : @@ -53,6 +55,7 @@ struct NewtonsCradleExample: public CommonRigidBodyBase { virtual void changePendulaRestitution(btScalar restitution); virtual void stepSimulation(float deltaTime); virtual bool keyboardCallback(int key, int state); + virtual void applyPendulumForce(btScalar pendulumForce); void resetCamera() { float dist = 41; float pitch = 52; @@ -62,17 +65,19 @@ struct NewtonsCradleExample: public CommonRigidBodyBase { targetPos[2]); } - std::vector constraints; - std::vector pendula; + std::vector constraints; // keep a handle to the slider constraints + std::vector pendula; // keep a handle to the pendula }; static NewtonsCradleExample* nex = NULL; -void onPendulaLengthChanged(float pendulaLength); +void onPendulaLengthChanged(float pendulaLength); // Change the pendula length -void onPendulaRestitutionChanged(float pendulaRestitution); +void onPendulaRestitutionChanged(float pendulaRestitution); // change the pendula restitution -void floorSliderValue(float notUsed); +void floorSliderValue(float notUsed); // floor the slider values which should be integers + +void applyForceWithForceScalar(float forceScalar); void NewtonsCradleExample::initPhysics() { @@ -117,7 +122,7 @@ void NewtonsCradleExample::initPhysics() { } { // create a slider to change the force to displace the lowest pendulum - SliderParams slider("Displacement force", &gForcingForce); + SliderParams slider("Displacement force", &gDisplacementForce); slider.m_minVal = 0.1; slider.m_maxVal = 200; slider.m_clampToNotches = false; @@ -125,6 +130,15 @@ void NewtonsCradleExample::initPhysics() { slider); } + { // create a slider to apply the force by slider + SliderParams slider("Apply displacement force", &gForceScalar); + slider.m_minVal = -1; + slider.m_maxVal = 1; + slider.m_clampToNotches = false; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( + slider); + } + m_guiHelper->setUpAxis(1); createEmptyDynamicsWorld(); @@ -162,10 +176,12 @@ void NewtonsCradleExample::initPhysics() { } void NewtonsCradleExample::stepSimulation(float deltaTime) { + + applyForceWithForceScalar(gForceScalar); // apply force defined by apply force slider + if (m_dynamicsWorld) { m_dynamicsWorld->stepSimulation(deltaTime); } - } void NewtonsCradleExample::createPendulum(btSphereShape* colShape,btVector3 position, btScalar length, btScalar mass) { @@ -281,7 +297,7 @@ bool NewtonsCradleExample::keyboardCallback(int key, int state) { //key 1, key 2, key 3 switch (key) { - case 49 /*ASCII for 1*/: { + case '1' /*ASCII for 1*/: { //assumption: Sphere are aligned in Z axis btScalar newLimit = btScalar(gCurrentPendulumLength + 0.1); @@ -292,7 +308,7 @@ bool NewtonsCradleExample::keyboardCallback(int key, int state) { b3Printf("Increase pendulum length to %f", gCurrentPendulumLength); return true; } - case 50 /*ASCII for 2*/: { + case '2' /*ASCII for 2*/: { //assumption: Sphere are aligned in Z axis btScalar newLimit = btScalar(gCurrentPendulumLength - 0.1); @@ -306,11 +322,8 @@ bool NewtonsCradleExample::keyboardCallback(int key, int state) { b3Printf("Decrease pendulum length to %f", gCurrentPendulumLength); return true; } - case 51 /*ASCII for 3*/: { - for (int i = 0; i < gDisplacedPendula; i++) { - if (gDisplacedPendula >= 0 && gDisplacedPendula <= gPendulaQty) - pendula[i]->applyCentralForce(btVector3(gForcingForce, 0, 0)); - } + case '3' /*ASCII for 3*/: { + applyPendulumForce(gDisplacementForce); return true; } } @@ -318,6 +331,16 @@ bool NewtonsCradleExample::keyboardCallback(int key, int state) { return false; } +void NewtonsCradleExample::applyPendulumForce(btScalar pendulumForce){ + if(pendulumForce != 0){ + b3Printf("Apply %f to pendulum",pendulumForce); + for (int i = 0; i < gDisplacedPendula; i++) { + if (gDisplacedPendula >= 0 && gDisplacedPendula <= gPendulaQty) + pendula[i]->applyCentralForce(btVector3(pendulumForce, 0, 0)); + } + } +} + // GUI parameter modifiers void onPendulaLengthChanged(float pendulaLength) { @@ -336,6 +359,18 @@ void onPendulaRestitutionChanged(float pendulaRestitution) { void floorSliderValue(float notUsed) { gPendulaQty = floor(gPendulaQty); gDisplacedPendula = floor(gDisplacedPendula); + +} + +void applyForceWithForceScalar(float forceScalar) { + if(nex){ + btScalar appliedForce = forceScalar * gDisplacementForce; + + if(fabs(gForceScalar) < 0.2f) + gForceScalar = 0; + + nex->applyPendulumForce(appliedForce); + } } CommonExampleInterface* ET_NewtonsCradleCreateFunc( diff --git a/examples/ExtendedTutorials/NewtonsRopeCradle.cpp b/examples/ExtendedTutorials/NewtonsRopeCradle.cpp index d0a4b86a9..7d8a289de 100644 --- a/examples/ExtendedTutorials/NewtonsRopeCradle.cpp +++ b/examples/ExtendedTutorials/NewtonsRopeCradle.cpp @@ -44,7 +44,9 @@ static btScalar gInitialPendulumHeight = 8; // default pendula height static btScalar gRopeResolution = 1; // default rope resolution (number of links as in a chain) -static btScalar gForcingForce = 30; // default force to displace the pendula +static btScalar gDisplacementForce = 30; // default force to displace the pendula + +static btScalar gForceScalar = 0; // default force scalar to apply a displacement struct NewtonsRopeCradleExample : public CommonRigidBodyBase { NewtonsRopeCradleExample(struct GUIHelperInterface* helper) : @@ -52,7 +54,9 @@ struct NewtonsRopeCradleExample : public CommonRigidBodyBase { } virtual ~NewtonsRopeCradleExample(){} virtual void initPhysics(); + virtual void stepSimulation(float deltaTime); virtual void renderScene(); + virtual void applyPendulumForce(btScalar pendulumForce); void createEmptyDynamicsWorld() { m_collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration(); @@ -105,6 +109,8 @@ void onRopePendulaRestitutionChanged(float pendulaRestitution); void floorRSliderValue(float notUsed); +void applyRForceWithForceScalar(float forceScalar); + void NewtonsRopeCradleExample::initPhysics() { @@ -167,47 +173,56 @@ void NewtonsRopeCradleExample::initPhysics() } { // create a slider to change the force to displace the lowest pendulum - SliderParams slider("Displacement force", &gForcingForce); + SliderParams slider("Displacement force", &gDisplacementForce); slider.m_minVal = 0.1; slider.m_maxVal = 200; slider.m_clampToNotches = false; m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider); } + + { // create a slider to apply the force by slider + SliderParams slider("Apply displacement force", &gForceScalar); + slider.m_minVal = -1; + slider.m_maxVal = 1; + slider.m_clampToNotches = false; + m_guiHelper->getParameterInterface()->registerSliderFloatParameter( + slider); + } m_guiHelper->setUpAxis(1); createEmptyDynamicsWorld(); // create a debug drawer - m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld); - if (m_dynamicsWorld->getDebugDrawer()) - m_dynamicsWorld->getDebugDrawer()->setDebugMode( - btIDebugDraw::DBG_DrawWireframe - + btIDebugDraw::DBG_DrawContactPoints - + btIDebugDraw::DBG_DrawConstraints - + btIDebugDraw::DBG_DrawConstraintLimits); + m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld); + if (m_dynamicsWorld->getDebugDrawer()) + m_dynamicsWorld->getDebugDrawer()->setDebugMode( + btIDebugDraw::DBG_DrawWireframe + + btIDebugDraw::DBG_DrawContactPoints + + btIDebugDraw::DBG_DrawConstraints + + btIDebugDraw::DBG_DrawConstraintLimits); - { // create the pendula starting at the indicated position below and where each pendulum has the following mass - btScalar pendulumMass(1.0f); + { // create the pendula starting at the indicated position below and where each pendulum has the following mass + btScalar pendulumMass(1.0f); - btVector3 position(0.0f,15.0f,0.0f); // initial left-most pendulum position - btQuaternion orientation(0,0,0,1); // orientation of the pendula + btVector3 position(0.0f,15.0f,0.0f); // initial left-most pendulum position + btQuaternion orientation(0,0,0,1); // orientation of the pendula - // Re-using the same collision is better for memory usage and performance - btSphereShape* pendulumShape = new btSphereShape(gSphereRadius); - m_collisionShapes.push_back(pendulumShape); + // Re-using the same collision is better for memory usage and performance + btSphereShape* pendulumShape = new btSphereShape(gSphereRadius); + m_collisionShapes.push_back(pendulumShape); - for (int i = 0; i < floor(gPendulaQty); i++) { + for (int i = 0; i < floor(gPendulaQty); i++) { - // create pendulum - createRopePendulum(pendulumShape, position, orientation,gInitialPendulumWidth, - gInitialPendulumHeight, pendulumMass); + // create pendulum + createRopePendulum(pendulumShape, position, orientation,gInitialPendulumWidth, + gInitialPendulumHeight, pendulumMass); - // displace the pendula 1.05 sphere size, so that they all nearly touch (small spacings in between) - position.setX(position.x()-2.1f * gSphereRadius); - } + // displace the pendula 1.05 sphere size, so that they all nearly touch (small spacings in between) + position.setX(position.x()-2.1f * gSphereRadius); } + } m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld); } @@ -229,6 +244,15 @@ void NewtonsRopeCradleExample::connectWithRope(btRigidBody* body1, btRigidBody* getSoftDynamicsWorld()->addSoftBody(softBodyRope0); } +void NewtonsRopeCradleExample::stepSimulation(float deltaTime) { + + applyRForceWithForceScalar(gForceScalar); // apply force defined by apply force slider + + if (m_dynamicsWorld) { + m_dynamicsWorld->stepSimulation(deltaTime); + } +} + void NewtonsRopeCradleExample::createRopePendulum(btSphereShape* colShape, btVector3 position, btQuaternion pendulumOrientation, btScalar width, btScalar height, btScalar mass) { @@ -312,11 +336,8 @@ bool NewtonsRopeCradleExample::keyboardCallback(int key, int state) { // key 3 switch (key) { - case 51 /*ASCII for 3*/: { - for (int i = 0; i < gDisplacedPendula; i++) { - if (gDisplacedPendula >= 0 && gDisplacedPendula <= gPendulaQty) - pendula[i]->applyCentralForce(btVector3(gForcingForce, 0, 0)); - } + case '3' /*ASCII for 3*/: { + applyPendulumForce(gDisplacementForce); return true; } } @@ -324,6 +345,16 @@ bool NewtonsRopeCradleExample::keyboardCallback(int key, int state) { return false; } +void NewtonsRopeCradleExample::applyPendulumForce(btScalar pendulumForce){ + if(pendulumForce != 0){ + b3Printf("Apply %f to pendulum",pendulumForce); + for (int i = 0; i < gDisplacedPendula; i++) { + if (gDisplacedPendula >= 0 && gDisplacedPendula <= gPendulaQty) + pendula[i]->applyCentralForce(btVector3(pendulumForce, 0, 0)); + } + } +} + // GUI parameter modifiers void onRopePendulaRestitutionChanged(float pendulaRestitution) { @@ -338,6 +369,17 @@ void floorRSliderValue(float notUsed) { gRopeResolution = floor(gRopeResolution); } +void applyRForceWithForceScalar(float forceScalar) { + if(nex){ + btScalar appliedForce = forceScalar * gDisplacementForce; + + if(fabs(gForceScalar) < 0.2f) + gForceScalar = 0; + + nex->applyPendulumForce(appliedForce); + } +} + CommonExampleInterface* ET_NewtonsRopeCradleCreateFunc( CommonExampleOptions& options) { nex = new NewtonsRopeCradleExample(options.m_guiHelper);