Jump to content
  • Advertisement
isu diss

How do I stop sinking and sliding objects?

Recommended Posts

Some objects don't penetrate the ground, some does. why? How can I fix that?


void Manifold::ApplyImpulse( float dt )
{

  for(int i = 0; i < contact_count; ++i)
  {
	  XMVECTOR p = XMVectorSet(contacts[i].x,contacts[i].y,contacts[i].z, 1.0f);


	XMVECTOR padot = A->GetVelocityAtPoint(p);
	XMVECTOR pbdot = B->GetVelocityAtPoint(p);

	XMVECTOR n = normal;
	XMVECTOR ra = (p - A->GetPosition());
	XMVECTOR rb = (p - B->GetPosition());

 	float term1 =  A->GetMass()>0.0f ? (1.0f / A->GetMass()) : 0.0f;
	float term2 =  B->GetMass()>0.0f ? (1.0f / B->GetMass()) : 0.0f;
	float invdt = dt>0.0f ? (1/dt) : 0.0f;

	// Add constraint error to the velocity constraint. 
	float C = min(0.0f, penetration + 0.015f);
	float velocityBias = 0.0f; 

	velocityBias += -invdt * C *.1f; 


	// Compute normal mass.
	XMVECTOR rnA = XMVector3Cross(ra, n);
	XMVECTOR rnB = XMVector3Cross(rb, n);

	float K = term1 + term2 + XMVector3Dot(rnA, XMVector4Transform(rnA, A->GetIInverse())).m128_f32[0] + XMVector3Dot(rnB, XMVector4Transform(rnB, B->GetIInverse())).m128_f32[0];
	float invK = K > 0.0f ? 1.0f / K : 0.0f;

	XMVECTOR dv = padot  - pbdot;
	float Cdot = XMVector3Dot(dv, n).m128_f32[0];
	//if (Cdot < -1.0f) 
	{ 
		velocityBias += -e * Cdot; 
	} 
	float impulse = -invK * (Cdot - velocityBias);
	XMVECTOR P = 1.17f*impulse * n;

	A->AddImpulse(P);
	B->AddImpulse(-P);
	A->AddImpulsiveTorque(XMVector3Cross(ra, P));
	B->AddImpulsiveTorque(-XMVector3Cross(rb, P));

	/*
  		tangent[0] = XMVector3Orthogonal(n);
		tangent[1] = XMVector3Cross(tangent[0], n);;

		// Add friction constraints.	
		{
			padot = A->GetVelocityAtPoint(p);
			pbdot = B->GetVelocityAtPoint(p);

			ra = (p - A->GetPosition());
			rb = (p - B->GetPosition());

			XMVECTOR rt1A = XMVector3Cross(ra, tangent[0]);
			XMVECTOR rt1B = XMVector3Cross(rb, tangent[0]);

			XMVECTOR rt2A = XMVector3Cross(ra, tangent[1]);
			XMVECTOR rt2B = XMVector3Cross(rb, tangent[1]);

			float K1 =	term1 + term2 + XMVector3Dot(rt1A, XMVector4Transform(rt1A, A->GetIInverse())).m128_f32[0] + XMVector3Dot(rt1B, XMVector4Transform(rt1B, B->GetIInverse())).m128_f32[0];
			float K2 = 	term1 + term2 + XMVector3Dot(rt2A, XMVector4Transform(rt2A, A->GetIInverse())).m128_f32[0] + XMVector3Dot(rt2B, XMVector4Transform(rt2B, B->GetIInverse())).m128_f32[0];

			tangentMasses[0] = K1 > 0.0f ? 1.0f / K1 : 0.0f;
			tangentMasses[1] = K2 > 0.0f ? 1.0f / K2 : 0.0f;
		}

		// Solve tangent constraints.
		for (int j = 0; j < 2; ++j)
		{
			float hi = sf * impulse;
			float lo = -hi;

			dv = padot  - pbdot;
			Cdot = XMVector3Dot(tangent[j], dv).m128_f32[0];

			float timpulse = -tangentMasses[j] * Cdot;
			
			P = timpulse * tangent[j];

			A->AddImpulse(P);
			B->AddImpulse(-P);
			A->AddImpulsiveTorque(XMVector3Cross(ra, P));
			B->AddImpulsiveTorque(-XMVector3Cross(rb, P));
		}*/

  }
}

I had to multiply impulse by 1.17f to get bounciness. why?

I have attached two videos. with and without the tangent code (^^^^^ the code I have commented out)

with the tangent code all objects start to slide. why?

1st video >> with full apply impulse code

2nd video >> w/o tangent code

Share this post


Link to post
Share on other sites
Advertisement

Are you solving one contact point? By looking at your stuff I don't think so...

If that's the case, there are some bugs in your code, which is common for a newbie. Some fixes:

1. Your code is using the relative velocity at each iteration to compute the velocity bias. This is wrong. You should only use the initial relative velocity to compute the velocity bias.

2. Your code is multiplying the impulse vector by some scalar. This is called relaxation. This is not necessary. You're already adding the restitution to the velocity constraint if it falls bellow a threshold (-1). So no need to scale it up.

3. Your code is not warm starting the solver (applying the cached impulses)

4. You code is not accumulating the impulses. Neither it is clamping the new accumulated impulses.

Then there can be a sign problem. If the contact normal always point from body A to body B (which is a good idea) then the velocity constraint is as such:

float32 Cdot = b3Dot(vB - vA, m_normal);

float32 impulse = -m_invK * (Cdot + m_velocityBias);

b3Vec3 PA = -impulse * m_normal;

b3Vec3 PB = -PA;

// Apply impulses to bodies

Your code should look something along these lines (pseudo):

void Contact::InitializeVelocityConstraints()
{
    // Evaluate C
    // Compute velocity bias
    // Compute effective mass
}

void Contact::WarmStart()
{
    // Apply accumulated impulses
}

void Contact::SolveVelocityConstraints()
{
    // Compute Cdot
    // Compute impulse
    // Accumulate and clamp impulses
    // Apply impulses
}

Then a simple simulation loop could be something like this:

GenerateContacts();

IntegrateVelocities();

for each contact c
    c->InitializeVelocityConstraints();
    c->WarmStart();

for each iteration
    for each contact c
        c->SolveVelocityConstraints();

IntegratePositions();

If you do the math you will realize that initializing and solving contact velocity constraints this way is equivalent to formulating a linear system (actually an LCP) and iteratively solving it using Projected Gauss Seidel.

As I said in an earlier post, you should port exactly the solver code that is in whatever reliable engine using sequential impulses. I recommend Bounce Lite's because that is the solver you're trying to implement. Don't play around with alternatives. Unless you're solving a sphere on a plane, which is what I recoomended earlier. In this case you need only one impulse to bring the relative velocity at the contact point to a target value and don't need impulse caching at all.

Share this post


Link to post
Share on other sites

I'm solving multiple contacts(4) at once. Your post is really helpful. Thank you sir. I'm still following randy's impulse engine. 'cos it's easy.

Share this post


Link to post
Share on other sites

Don't expect us to debug the code for you. 

The best we can do is sharing information and some code. 

Debug draw everything you can!

This can be done by defining a simple global draw interface variable that you can call anywhere in your library.

Draw the boxes
Draw the SAT features 
Draw the Sutherland Hodgman Clipping polygon
Draw the contact points, normals, and tangents

Make a testbed. Each test draws something different. 

The videos above are not showing up for me too. Put them on YT and share as a private link!

Share this post


Link to post
Share on other sites

Arbiter.h

Fine AFAIK

Arbiter.cpp

Collision detection and contact creation code difficult to read due to DXMATH and likely bugged.

Suggestion is to do spheres on a plane.

Line 379:

// accumulate Impulses
XMVECTOR P = c->Pn * n + c->Pt * tangent[1];

Should be 

// apply impulses
XMVECTOR P = c->Pn * n + c->Pt1 * tangent[0] + C->Pt2 * tangent[1];

There should be two impulses per contact point. One for each tangential direction (simply).

World.h

Fine AFAIK

World.cpp

Seems good

The videos are still not showing up. Your posts are becoming a great mess. Use YouTube!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!