Strange behaviour with collisions and some material question

HexDump

08-02-2008 08:14:42

Hi all,

After being using newton for 1 month, I can say it is a pretty good physics engine. I´m starting to feel confortable.

Anyway, I have find some "problems/bugs/my fault" that I do not uderstand why they happen. First of all, I have a bullet that hits a barrel. Could andybody tell me why newton is notifying be 3 times per physics run that the bullet is hitting the barrel?. When the ball hits it 5 times the barrel exploits, and because this problem, after 2 impacts the barrel dies.

The other question is. Isn´t supposed newton to only notify me about collisions I have set a material pair for?. For example I have a bullet material, and haven´t defined any bullet/bullet collision but newton keeps notifying me about this. What's the problem?.

This is the code I use for material creation, and the callback:



class CEntityMatCallback :
public OgreNewt::ContactCallback
{
public:


int userProcess();

CEntityMatCallback(){};
~CEntityMatCallback(){};


};

This is the only method the collision callback has
int CEntityMatCallback::userProcess()
{
bool bAccept=false;
CLogicComp* pLogic=0;
CGameEntity* pObj1=(CGameEntity*)m_body0->getUserData();
CGameEntity* pObj2=(CGameEntity*)m_body1->getUserData();

if(pObj1)
{
pLogic=pObj1->GetComponent<CLogicComp>();
if(pLogic)
bAccept=pLogic->OnCollision(pObj2);
}

if(pObj2)
{
pLogic=pObj2->GetComponent<CLogicComp>();
if(pLogic)
bAccept |= pLogic->OnCollision(pObj1);
}
return bAccept;
}


bool CPhysicsSystem::RegisterMaterial(const std::string& sMatName, int iID)
{
assert(sMatName!="");

stdext::hash_map<std::string,OgreNewt::MaterialID*>::const_iterator it=m_Materials.find(sMatName);
if(it==m_Materials.end())
{
//There's a problem with the ID, if we don´t use 0 allways it explodes when adding the custom contactcallback
OgreNewt::MaterialID* pMat=new OgreNewt::MaterialID(m_pPhysicWorld.get(),0/*iID*/);

std::pair<std::string,OgreNewt::MaterialID*> mypair=std::make_pair(sMatName,pMat);
m_Materials.insert(mypair);
return true;
}
else
return false;

}

OgreNewt::MaterialID* CPhysicsSystem::GetMaterial(const std::string& sMatName)
{
stdext::hash_map<std::string,OgreNewt::MaterialID*>::const_iterator it=m_Materials.find(sMatName);

assert(it!=m_Materials.end());

if(it!=m_Materials.end())
return it->second;
else
return 0;
}


bool CPhysicsSystem::RegisterMaterialPair(const std::string& sMatPairName, const std::string& sMat1Name, const std::string& sMat2Name)
{
bool bReturn=true;
assert(sMatPairName!="");
assert(sMat1Name!="" && m_Materials.find(sMat1Name)!=m_Materials.end());
assert(sMat2Name!=""&& m_Materials.find(sMat2Name)!=m_Materials.end());

stdext::hash_map<std::string,OgreNewt::MaterialID*>::const_iterator itMat1=m_Materials.find(sMat1Name);
stdext::hash_map<std::string,OgreNewt::MaterialID*>::const_iterator itMat2=m_Materials.find(sMat2Name);

if(itMat1==m_Materials.end())
{
Ogre::LogManager::getSingletonPtr()->logMessage("[CPhysicsSystem] Material "+sMat1Name+ " is not registered");
bReturn=false;
}

if(bReturn && itMat2==m_Materials.end())
{
Ogre::LogManager::getSingletonPtr()->logMessage("[CPhysicsSystem] Material "+sMat2Name+ " is not registered");
bReturn=false;
}

if(bReturn)
{
OgreNewt::MaterialID* mat1=itMat1->second;
OgreNewt::MaterialID* mat2=itMat2->second;
OgreNewt::MaterialPair* p=new OgreNewt::MaterialPair(m_pPhysicWorld.get(),itMat1->second,itMat2->second);
std::pair<std::string, OgreNewt::MaterialPair*> mypair=std::make_pair(sMatPairName,p);
p->setContactCallback(&m_EntityCallback);
m_MaterialPairs.insert(mypair);
}

return bReturn;
}


As you may notice this is very simple. I just have a RegisterMaterial and RegisterMaterialPair, that the user calls to add materials and materialpairs to newton (I´m using ogrenewt). All pairs are targeted to the same callback, that has the duty to notify both sides.

As I said before When 2 bodies collide, this callback is being called more than once and I´m receiving collsiions from pairs I did not configure, could it be because I create all materials with id 0? (Newton hanged when using a non 0 id for the material).

Sorry for the long code,and thanks a lot for the help.

HexDump.

walaber

08-02-2008 16:45:01

you should not be using the constructor that allows for you to set the ID variable yourself, it is generated automatically.

change your code to just call:


greNewt::MaterialID* pMat=new OgreNewt::MaterialID(m_pPhysicWorld.get());


that should fix your problem!

as for the multiple collisions, "userProcess" gets called once for each contact that happens during an update. depending on how faces are aligned, you may get several from a single "collision" between objects.

the most common way to handle this for simple collision detection is to do something like this (pseudocode):


class MyCallback : public OgreNewt::ContactCallback
{
public:

float hardestHit;

int userBegin();
int userProcess();
void userEnd();
};


int MyCallback::userBegin()
{
// new (potential) collision. reset vars.
hardestHit = 0.0f;
}


int MyBallback::userProcess()
{
// get the "normal speed" for this contact.
float normSpeed = getContactNormalSpeed();

if (normSpeed > hardestHit) { hardestHit = normSpeed; }
}

void MyCallback::userEnd()
{
if (hardestHit > 0.0f)
{
// we have a collision!
collisionSystem->notifyCollision( blah, blah, blah );
}
}



none of this code has been checked, but you get the idea, right? the basic idea is to store the largest contact from userProcess, and then report it in userEnd, because that is only called once.

HexDump

08-02-2008 16:50:10

Man, I love you (errrr, well, do not misundestood me, you know what I mean :twisted: ).

Thanks a lot for the help. I´m gonna try it when getting home :D.

HexDump

HexDump

09-02-2008 11:22:16

Hi again,

Well walaber, your method works as expected but there's something I didn´t noticed first time I read your pseudocode. What about if I want to cancel the contact? I mean, you get hardest contact, and then use it to notify colliders, but what about if I don´t want this collision to happen?. processEnd() doesn´t allow me to return a value for this :/. The main problem here is that I´m using same callback for all the contacts, then aach object logic tells the notifier (the callback) if it wants to accept the collsion or not, for example based on the type of the object.

Thanks in advance,
HexDump.

dudeabot

09-02-2008 13:03:44

return 0 on userBegin or UserProcess

HexDump

09-02-2008 16:24:57

Dudeabot, I think this is not quite right. To to this, the notification to my entities should be done in the userProcess (this is the way I did it before). Now I´m force to move the previouis userProcess code to the userEnd(), because I just want to notify a contact, and here, I can not return anything.

Not sure, But if I do what you say, I could be notifiying a collision that do not match the one I´m calculating the force from.

Don´t you think.

Thanks in advance,
HexDmp.

walaber

10-02-2008 01:51:20

dudeabot is correct, the only way to ignore a collision is to bo it contact-by-contact in the userProcess function.

i would suggest modifying your collision logic system to have two calbacks or filter functions... something like onContact() which returns a bool for allowing and ignoring contacts, and an onHit() which is called from the userEnd(), can can be used for things like sound triggers, and other game logic.