How to implement grabbing of objects?

Post Reply
jorrit
Posts: 13
Joined: Mon Jul 18, 2005 7:16 am
Contact:

How to implement grabbing of objects?

Post by jorrit » Wed Feb 01, 2012 8:30 am

Hi all,

I'm currently using Bullet (in combination with my 3D engine Crystal Space) and I would like to have realistic grabbing of objects. I don't know if any of you are aware of the games Penumbra or Amnesia: The Dark Descent? In that game you have a first person camera and you can grab objects by clicking on them. This is done in a realistic way. For example, to open a door you simply grab the door and then move backwards or forwards. The door will open or close depending on the speed with which you move your mouse. Same for drawers. You can pull out a drawer just the way that you would expect. You can start pulling and stop halfway and then continue or go back. And so on. Same for levers, turning wheels and so on. It all feels very realistic and very nice to use.

So I'm trying to achieve the same. I got a very similar result by creating a pivot joint using btPoint2PointConstraint and dynamicWorld->addConstraint(). This works great.

However there is a small problem in combination with btGeneric6DofConstraint. When the player grabs an object that is connected to such a 6DOF constraint then I guess bullet doesn't know which constraint to fully honor. The problem is that the 6DOF constraint is slightly violated (and so is the pivot joint) because the player is dragging a bit too far. So if you have such a constraint to simulate a door then the player can slightly rotate the door in wrong directions. I guess the problem is that bullet doesn't know which of the two constraints (6dof and pivot) to honor completely so it probably decides to honor both a bit.

I would like the 6DOF constraints to be strict. The player should not be able to pull the door out of its hinges. How can I achieve that? Is there a way I can create a more loosely coupled pivot joint?

In addition, a related problem (I think) is how to make grabbing weight dependend. A heavier object should be harder to grab and if it is very heavy then the player should only be able to drag it on the floor but not lift it in the air. With the pivot joint there is no such restriction. The player can lift anything.

Any advice here?

Thanks!

User avatar
Erwin Coumans
Site Admin
Posts: 4073
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA
Contact:

Re: How to implement grabbing of objects?

Post by Erwin Coumans » Thu Feb 02, 2012 12:36 am

You can set a maximum impulse applied by the btPoint2PointConstraint, it might deal with both cases.

Code: Select all

p2p->m_setting.m_impulseClamp = 30.f;
p2p->m_setting.m_tau = 0.001f;
Can you try it (and tweak the values)?

jorrit
Posts: 13
Joined: Mon Jul 18, 2005 7:16 am
Contact:

Re: How to implement grabbing of objects?

Post by jorrit » Thu Feb 02, 2012 5:27 am

Hmm it seems these settings do improve matters however not fully. No matter what parameters I set it is still possible to slightly get the door out of its hinges and if you pull long enough you will eventually get bigger problems. I'm thinking this might fundamentally not be the right way to handle this. I would like the door hinges to be strict. There should be no way that the door gets wrongly positioned. No matter how hard one is pulling at the door.

So any other things I could try?

Thanks!

Pimms
Posts: 3
Joined: Fri Feb 10, 2012 1:28 pm

Re: How to implement grabbing of objects?

Post by Pimms » Fri Feb 10, 2012 1:47 pm

@jorrit

I'm currently doing the same thing you are, and I have some question regarding how you did the p2p-constraint, as my way of doing it give some... funny results? :) I'm attaching the "lift" object to a static collisionObject in (0,0,0), and setting the static's object pivot-point to be shortly in front of the player. This was the best solution, as the player-body is dynamic, so for instance smashing a crate hard into the ground would send the player skywards.

Anyway, this method makes object at times intersect with walls, floors and other objects giving very jaggy, ugly and unrealistic results. Could you give me some info on how you did this? :)

Pimms

jorrit
Posts: 13
Joined: Mon Jul 18, 2005 7:16 am
Contact:

Re: How to implement grabbing of objects?

Post by jorrit » Fri Feb 10, 2012 2:06 pm

Pimms wrote:@jorrit

I'm currently doing the same thing you are, and I have some question regarding how you did the p2p-constraint, as my way of doing it give some... funny results? :) I'm attaching the "lift" object to a static collisionObject in (0,0,0), and setting the static's object pivot-point to be shortly in front of the player. This was the best solution, as the player-body is dynamic, so for instance smashing a crate hard into the ground would send the player skywards.

Anyway, this method makes object at times intersect with walls, floors and other objects giving very jaggy, ugly and unrealistic results. Could you give me some info on how you did this? :)

Pimms
Well that's my problem. I haven't really found a solution to this yet. I could minimize the problem by playing with the impulseClamp values (setting them very low) but I couldn't get the problem to completely disappear yet. I'm still hunting for a good solution here.

Greetings,

Pimms
Posts: 3
Joined: Fri Feb 10, 2012 1:28 pm

Re: How to implement grabbing of objects?

Post by Pimms » Fri Feb 10, 2012 4:13 pm

I'm fairly noob at Bullet, but a few points to go by as I've noticed in Penumbra / Amnesia:

- Objects appear to be hung from a rope, thus giving the feeling of weight. Notice how heavier objects especially in P. sort of dangle when being held still.
- This "invisible rope" supports being stretched, thus avoiding awkward jittery motion.

The games are built upon the HPL1/2 engine, which implements ODE. As far as I can tell from the documentation (flame if wrong), there is no native rope-joint in ODE.

It would seem to me that the solution might lay in identifying (i.e., scan the transform each frame) the jittery motion in a constraint of any kind, and upon noticing revert the transform of the body to the last working transform. As mentioned, I have little to no insight in how Bullet works internally, but this makes sense to me.

kloplop321
Posts: 55
Joined: Sun Jan 01, 2012 7:37 pm

Re: How to implement grabbing of objects?

Post by kloplop321 » Fri Feb 10, 2012 4:22 pm

HPL 1 / 2 use Newton Dynamics, not ODE.

You may be able to glean how they did it from their sources.
https://github.com/FrictionalGames/HPL1Engine

Pimms
Posts: 3
Joined: Fri Feb 10, 2012 1:28 pm

Re: How to implement grabbing of objects?

Post by Pimms » Sat Feb 11, 2012 12:08 pm

Ops, messed up on which engine implements what. Anyways, I looked through the most obvious places to eventually put a "lift"-joint, and I couldn't find anything.

Anyways, using Ogre::Quaternion (for multiplication with vectors), I managed to get a very smooth lifting-system. Goes something like this:

Upon interaction (lifting):

Code: Select all

                        //Calculate the direction vector
                        mConTime = 0;
			Ogre::Vector3 v = mPlayer->camYNode->getOrientation() * 
				mPlayer->camXNode->getOrientation() * vp(0,0,1);
                        
			mConBody = (btRigidBody*)mTarget;	
			mConBody->activate();

			//Create an ogre Quaternion (btQuaternion has trouble with vector3 mult)
			btVector3 conRot(	mConBody->getOrientation().getX(),
								mConBody->getOrientation().getY(),
								mConBody->getOrientation().getZ());
			Ogre::Quaternion oq(mConBody->getOrientation().getW(), conRot.x(), conRot.y(), conRot.z());

			//Get the local vector in the targetted shape
			Ogre::Vector3 p = btToOg(mTargetPt - mConBody->getWorldTransform().getOrigin());
			//Multiply it with the inverse of the quaternion
			p = oq.Inverse() * p;
			mCon = new btPoint2PointConstraint(*mConBody, *mBaseBody, ogToBt(p), btVector3(0,0,0));

			//Calculate the distance
			Ogre::Vector3 a = btToOg( mTargetPt );
			Ogre::Vector3 b = mPlayer->mainNode->getPosition();
			mConDist = sqrt( pow(b.x-a.x,2) + pow(b.y-a.y,2) + pow(b.z-a.z,2) );
			 
			mWorld->addConstraint(mCon);
Called every frame:

Code: Select all

        if (mCon)
	{
		if (!mCon->isEnabled())
		{
			dismiss();
			return;
		}

		Ogre::Vector3 v = mPlayer->camYNode->getOrientation() * 
				mPlayer->camXNode->getOrientation() * vp(0,0,1);
		Ogre::Vector3 f = vp(v.x,v.y,v.z)*-mConDist + mPlayer->mainNode->getPosition();

		mConTime += dt;
		if (mConTime > 0.1f)
		{
			mCon->setBreakingImpulseThreshold(1500);
		}

		mCon->setPivotB( ogToBt( f ) );
	}
Hope this is of any help to anyone :)

Post Reply