Shake When Push Box To Wall

Post Reply
rzwm
Posts: 3
Joined: Tue Oct 25, 2016 8:17 am

Shake When Push Box To Wall

Post by rzwm »

I have write a demo: using mouse to move a dynamic body(Box) to collide with static body(Wall).But I find, when I push the box to the wall, the box shakes.It's not my expectation. How can I avoid the shaking?
The demo's source code has been uploaded.(All files's format is code page 65001)
Please help me! Thank you!
Attachments
Move2D.cpp
(1.16 KiB) Downloaded 200 times
Move2D.h
(6.82 KiB) Downloaded 178 times
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Shake When Push Box To Wall

Post by drleviathan »

Your code is unreadable for me (I'm using Linux). Perhaps try using text format?
rzwm
Posts: 3
Joined: Tue Oct 25, 2016 8:17 am

Re: Shake When Push Box To Wall

Post by rzwm »

drleviathan wrote:Your code is unreadable for me (I'm using Linux). Perhaps try using text format?
Sorry, I forgot that the code are encrypted, below is the source code in text.
It is just simplely modified from CommonRigidBodyBase.
First I modify pickBody() for always pick in local point (0, 0, 0);
Then I modify movePickedBody() for always move in ground(this is why called Move2D).
And then I create 4 walls and 1 box.

// Move2D.h

Code: Select all

#include "Move2D.h"

class CommonExampleInterface* Move2DCreateFunc(struct CommonExampleOptions& options)
{
	return new Move2D(options.m_guiHelper);
}
// Move2D.cpp

Code: Select all

#ifndef MOVE_2D_H
#define MOVE_2D_H
#include "btBulletDynamicsCommon.h"
#define ARRAY_SIZE_Y 5
#define ARRAY_SIZE_X 5
#define ARRAY_SIZE_Z 5

#include "LinearMath/btVector3.h"
#include "LinearMath/btAlignedObjectArray.h"

#include "../CommonInterfaces/CommonRigidBodyBase.h"

class CommonExampleInterface*   Move2DCreateFunc(struct CommonExampleOptions& options);
struct Move2D : public CommonRigidBodyBase
{
	Move2D(struct GUIHelperInterface* helper)
		: CommonRigidBodyBase(helper)
        {}

	virtual void    initPhysics()
	{
		m_guiHelper->setUpAxis(1);

		createEmptyDynamicsWorld();

		m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
		if (m_dynamicsWorld->getDebugDrawer())
		{
			m_dynamicsWorld->getDebugDrawer()->setDebugMode(btIDebugDraw::DBG_DrawWireframe + btIDebugDraw::DBG_DrawContactPoints);
		}

		CreateGround();
		CreateStaticBodies();
		CreateDynamicBodies();

		m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
	}

	virtual void	resetCamera()
	{
		float dist = 41;
		float pitch = 52;
		float yaw = 35;
		float targetPos[3] = { 0, 0.46, 0 };
		m_guiHelper->resetCamera(dist, pitch, yaw, targetPos[0], targetPos[1], targetPos[2]);
	}

	virtual bool	pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld)
	{
		if (m_dynamicsWorld == 0)
			return false;

		btCollisionWorld::ClosestRayResultCallback rayCallback(rayFromWorld, rayToWorld);

		m_dynamicsWorld->rayTest(rayFromWorld, rayToWorld, rayCallback);
		if (rayCallback.hasHit())
		{
			btVector3 pickPos = rayCallback.m_hitPointWorld;
			btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject);
			if (body)
			{
				if (!(body->isStaticObject() || body->isKinematicObject()))
				{
					m_pickedBody = body;
					m_savedState = m_pickedBody->getActivationState();
					m_pickedBody->setActivationState(DISABLE_DEACTIVATION);
					btVector3 localPivot = btVector3(btScalar(0), btScalar(0), btScalar(0));
					btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body, localPivot);
					m_dynamicsWorld->addConstraint(p2p, true);
					m_pickedConstraint = p2p;
					btScalar mousePickClamping = 30.f;
					p2p->m_setting.m_impulseClamp = mousePickClamping;
					p2p->m_setting.m_tau = 0.001f;
				}
			}

			m_oldPickingPos = rayToWorld;
			m_hitPos = pickPos;
			m_oldPickingDist = (pickPos - rayFromWorld).length();
		}
		return false;
	}

	virtual bool	movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld)
	{
		if (m_pickedBody && m_pickedConstraint)
		{
			btPoint2PointConstraint* pickCon = static_cast<btPoint2PointConstraint*>(m_pickedConstraint);
			if (pickCon)
			{
				btVector3 newPivotB;

				// Calculate the intersection point of ray and y = 1 plane according to the parametric equations of lines
				btVector3 vDir = rayToWorld - rayFromWorld;
				float fy = 1.f;
				float t = (fy - rayFromWorld.y()) / vDir.y();
				float fx = rayFromWorld.x() + vDir.x() * t;
				float fz = rayFromWorld.z() + vDir.z() * t;
				newPivotB = btVector3(fx, fy, fz);
				pickCon->setPivotB(newPivotB);
				return true;
			}
		}
		return false;
	}
	virtual void	CreateGround()
	{
		btBoxShape* pShape = createBoxShape(btVector3(50.f, 50.f, 50.f));
		m_collisionShapes.push_back(pShape);

		btTransform trans;
		trans.setIdentity();
		trans.setOrigin(btVector3(0.f, -50.f, 0.f));

		btRigidBody* pBody = createRigidBody(0.f, trans, pShape, btVector4(0, 0, 1, 1));
	}

	virtual void	CreateStaticBodies()
	{
		btBoxShape* pShape = createBoxShape(btVector3(1.f, 1.f, 10.f));
		m_collisionShapes.push_back(pShape);

		btTransform trans;
		trans.setIdentity();

		// left
		trans.setOrigin(btVector3(11.f, 1.f, 0.f));
		createRigidBody(0.f, trans, pShape, btVector4(1.f, 0.f, 0.f, 1.f));

		// right
		trans.setOrigin(btVector3(-11.f, 1.f, 0.f));
		createRigidBody(0.f, trans, pShape, btVector4(1.f, 0.f, 0.f, 1.f));

		// forward
		pShape = createBoxShape(btVector3(10.f, 1.f, 1.f));
		m_collisionShapes.push_back(pShape);
		trans.setOrigin(btVector3(0.f, 1.f, 11.f));
		createRigidBody(0.f, trans, pShape, btVector4(1.f, 0.f, 0.f, 1.f));

		// back
		trans.setOrigin(btVector3(0.f, 1.f, -11.f));
		createRigidBody(0.f, trans, pShape, btVector4(1.f, 0.f, 0.f, 1.f));
	}

	virtual void	CreateDynamicBodies()
	{
		btBoxShape* pShape = createBoxShape(btVector3(1.f, 1.f, 1.f));
		m_collisionShapes.push_back(pShape);

		btTransform trans;
		trans.setIdentity();
		trans.setOrigin(btVector3(9.f, 1.f, 0.f));

		btRigidBody* pBody = createRigidBody(1.f, trans, pShape, btVector4(0.f, 1.f, 0.f, 1.f));
		pBody->setCcdSweptSphereRadius(.5f);
		pBody->setCcdMotionThreshold(0.01f);
	}
};

#endif // !MOVE_2D_H

User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Shake When Push Box To Wall

Post by drleviathan »

Ok so the ray picking creates a btPoint2PointConstraint on the dynamic rigid body. My guess is that the target point for the constraint puts the dynamic body inside the static geometry, so either (a) the penetration resolution code is popping it out each frame or (b) the object is colliding hard against static geometry and bouncing back.

Here are some ideas on how to solve this:

(1) Temporarily while the object is under constraint set its restitution (bounciness) to zero, and restore to its old restitution whenever the constraint lets go. It would also help if your static geometry has low restitution by default. Essentially this dampens collision reactions and pumps less energy into the system.

(2) The Point2PointConstraint is stiff by default. Perhaps there is a way to dial its strength down so that it doesn't pull the object so hard. I don't know enough about constraints to say whether this is even possible much less exactly how to do it, but it is worth looking at the API to see if it is possible.

(3) Instead of using a stiff constraint... write a softer spring Action that tries to get the object there by setting its velocity. This can work quite well as long as you're tolerant of a little bit of lag between where the object is and where your ray pick wants it to be.

BTW, I should mention that I could not find in your code where you delete and dismantle m_pickedConstraint and the code that creates it does not appear to check whether m_pickedConstraint is already in use. In short, you might have a potential memory leak where the old pointer can be left dangling.
rzwm
Posts: 3
Joined: Tue Oct 25, 2016 8:17 am

Re: Shake When Push Box To Wall

Post by rzwm »

drleviathan wrote:Ok so the ray picking creates a btPoint2PointConstraint on the dynamic rigid body. My guess is that the target point for the constraint puts the dynamic body inside the static geometry, so either (a) the penetration resolution code is popping it out each frame or (b) the object is colliding hard against static geometry and bouncing back.

Here are some ideas on how to solve this:

(1) Temporarily while the object is under constraint set its restitution (bounciness) to zero, and restore to its old restitution whenever the constraint lets go. It would also help if your static geometry has low restitution by default. Essentially this dampens collision reactions and pumps less energy into the system.

(2) The Point2PointConstraint is stiff by default. Perhaps there is a way to dial its strength down so that it doesn't pull the object so hard. I don't know enough about constraints to say whether this is even possible much less exactly how to do it, but it is worth looking at the API to see if it is possible.

(3) Instead of using a stiff constraint... write a softer spring Action that tries to get the object there by setting its velocity. This can work quite well as long as you're tolerant of a little bit of lag between where the object is and where your ray pick wants it to be.

BTW, I should mention that I could not find in your code where you delete and dismantle m_pickedConstraint and the code that creates it does not appear to check whether m_pickedConstraint is already in use. In short, you might have a potential memory leak where the old pointer can be left dangling.
Thanks for your reply.
for (1), it doesn't work.In fact, the bodies's restitution are already zero.
for (2), I am finding the means of modify the strength of constraints, but I have not find it.
for (3), I think the lag is a bad experience, so I will consider it in the last.

And you have point that the code may has potential memory leak. In face, class Move2D it public inheritance from class CommonRigidBodyBase, and all other things are processed in it. So don't worry about it. Anyway, thank you all the same.
Post Reply