Character rotating by itself.

Y2K

07-04-2006 07:16:13

I have spend all day today trying to figure out what could be wrong, I hope someone could help me. My problem is that when I move my character, even if it's in one direction, at times it would start spinning/rotating.

I create a collision tree for my landscape ...
mSceneMgr->setWorldGeometry("test.scene");

//Create a static triangle mesh from .scene world geometry
int numMesh = mDotSceneMgr->getNumMeshes(NULL);
for(int mesh = 0; mesh < numMesh; mesh++)
{
int numVerts = mDotSceneMgr->getNumVertices(NULL,mesh);
int numIndices = mDotSceneMgr->getNumIndex(NULL,mesh);
float *verts = mDotSceneMgr->getVerticesPtr(NULL,mesh);
int *indices = mDotSceneMgr->getIndexPtr(NULL,mesh);

OgreNewt::Collision* mainWorldCollision = new CTreeCollision(numVerts,
numIndices, verts, indices, mWorld);

OgreNewt::Body* mBody = new OgreNewt::Body(mWorld,mainWorldCollision);
delete mainWorldCollision;
}


This is the way I create my character ...
mass = 10;
inertia = OgreNewt::MomentOfInertia::CalcEllipsoidSolid(mass,AABBSize);

playerCollision = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld,AABBSize);
playerBody = new OgreNewt::Body(mWorld,playerCollision,1);

playerBody->attachToNode(mPlayerNode);
playerBody->setPositionOrientation(mPlayerNode->getPosition(),mPlayerNode->getOrientation());

delete playerCollision;

playerBody->setMassMatrix(mass,inertia);

playerBody->setCustomForceAndTorqueCallback(CPlayerCharacter::characterForceCallback);

uv = new OgreNewt::BasicJoints::UpVector(mWorld,playerBody,Vector3(Vector3::UNIT_Y));

playerBody->setMaterialGroupID(mPlayerMat);
playerBody->setUserData(this);


Based on key input I set a velocity vector(testVelocity in this case) which get's fed into the customCallback ... for instance, if UP is pressed ...
Quaternion orientation;
Vector3 position, trans, vec;
playerBody->getPositionOrientation(position,orientation);
vec = Vector3(0,0,0.5);
Vector3 cur_vel = playerBody->getVelocity();
trans = orientation * vec;
Vector3 vel = trans * -1 * -30;
vel.y = cur_vel.y;
testVelocity = vel;


And finally my customForceCallback ...
CPlayerCharacter* player = (CPlayerCharacter*)me->getUserData();

me->setVelocity(player->getVelocity());
player->setVelocity(Vector3(0,0,0));

//apply a simple gravity force.
Ogre::Real mass;
Ogre::Vector3 inertia;

me->getMassMatrix(mass, inertia);
Ogre::Vector3 force(0,-9.8,0);
force *= mass;

me->addForce( force );


Again, even if I apply just a constant force, the character will start rotating, this happens especially if i'm going up or down a slope.

Any help would be appreciated. If I missed something, I appologise, first time posting :oops:

walaber

07-04-2006 21:37:55

the rotation is caused by friction between the body and the ground. the easiest solution is to remove friction (via materialpair) between the player and the ground.

other solutions would be to apply a torque based on omega to keep the body facing forward, or modifying the UpVector joint to not allow for rotation.

agoratim

03-08-2006 02:12:26

walaber,
I'm wondering if you could provide an example of applying torque to keep the body facing forward. I'm attempting something similar at the moment but with limited luck.

My code is based off the CharacterControl example (CharacterControl.cpp ln. 352) that's bundled with Newton. The general idea is to find the angle between the current heading and the desired heading and to gradually apply torque in the proper direction. The code is as follows:


// find the angle between the desired and current heading
oCurrentHeading = pBody->getOrientation();
float fCosAngle = min(max(oCurrentHeading.Dot(getDesiredHeading()), -1.0f), 1.0f);
Radian oSteerAngle = Math::ACos(fCosAngle);

// calculate the torque vector that will get us facing the right direction
float fTorque = 0.5f * oInertia.y * (oSteerAngle.valueRadians() * fElapsed - pBody->getOmega().y) * fElapsed;

// give it a twist
pBody->setTorque(Vector3(0.0f, fTorque, 0.0f));


The result of this code is that the body never converges on a single heading. It just sort of flips back and forth. I strongly suspect the problem has to do with my complete lack of knowledge of quaternions among other things.

Any suggestions?

agoratim

07-08-2006 00:09:16

For anyone that's interested I seem to have mostly figured this out although not quite in the way that I had hoped. My solution involved first extracting the headings as vectors rather than quaternions. This had the effect of making the math more familiar to me but it also places some restrictions on how the code can be used (I'll get to this in a second). The end result is pretty much the same as what I had before but this time my computation of the angle between the desired and actual heading seem to be correct. Here's the code...

// figure out which way we're currently heading
Quaternion oCurrentHeading = pBody->getOrientation();
oCurrentHeading.normalise();

// figure out what direction we need to turn in to get us on the right track. this will
// be the angle between the vector in which were pointing and where we want to be pointing
Vector3 oVecCurrent = pBody->getOrientation() * Vector3::UNIT_Z;
Vector3 oVecDesired = getDesiredHeading() * Vector3::UNIT_Z;
Vector3 oCross = oVecCurrent.crossProduct(oVecDesired);
Radian oSteerAngle = Math::ASin(min(max(oCross.y, -1.0f), 1.0f));

// calculate the torque vector that will get us facing the right direction
float fTorque = 0.5f * oInertia.y * (oSteerAngle.valueRadians() * fElapsed - pBody->getOmega().y) * fElapsed;

// apply the torque
pBody->setTorque(Vector3(0.0f, fTorque, 0.0f));


So the restriction, and this is a big one, is that the this solution very much assumes that your rotations will be around the Y-axis. You'll notice that in the conversion of a quat to a vector I'm rotating a unit Z vector by the quat's rotation. If the quat represented a rotation around more than just the Y axis the result would not be a strict rotation of the unit vector around the Y-axis and then everything else starts to fall apart.

I believe the solution could be generalized but I don't have a need for that at the moment so I haven't attempted to take it on. If anyone is interested in filling me in on that solution please feel free. Also, if anyone wants to tell me where I originally went wrong I would love to hear that too.

Anyway, I hope someone finds this useful.

-Tim

lonwolf

12-08-2006 12:36:04

the rotation is caused by friction between the body and the ground. the easiest solution is to remove friction (via materialpair) between the player and the ground.

I have the same probs with spinning player body, and despite i've done what you sugested still the body rotates:

OgreNewt::MaterialPair* material_pair1 = new OgreNewt::MaterialPair( mWorld, mat_char, mat_floor );

material_pair1->setDefaultFriction(0.0f, 0.0f);
material_pair1->setDefaultSoftness(1);
material_pair1->setDefaultElasticity(0);
material_pair1->setContinuousCollisionMode(0);

the_hero.playerBody->setMaterialGroupID(mat_char);
bod1->setMaterialGroupID(mat_floor);

// change plane to make slope = test char movement
bod1->getOgreNode()->pitch(Degree(-45));
bod1->setPositionOrientation(bod1->getOgreNode()->getPosition(), bod1->getOgreNode()->getOrientation());


other solutions would be to apply a torque based on omega to keep the body facing forward,

ive done that to, works a bit fine but still after 2 secs of climbing the world starts spinning

or modifying the UpVector joint to not allow for rotation.

this has 2 disadvantages(<>) and 1 advantage(+);
1 (+) keeps the body a bit straight-forward but
1 (<>) starts vibrating after a while
2 (<>) you cant turn right/left using keys/mouse

So, @walaber the question remains... how can you make the character body not spinn when your climbing terrain/slopes??
(im using Elipsoid, i tryed with a box, same effect) :?:

Edit>> if i think a little the UpVector has this weird effect, a combination of forces... the elipsoid/ box tryes to fall backward/forward but the Up vector opposes this. and the result is a spining Mesh/Body... I pretty well know pshysics ( real not simulated) and in the real world the efect will be the same... so basicaly the UpVector isnt 100% sure... im experimenting now without it and see if my theory is right...

Edit >2> Question :?: how can you make a body stay facing UP the Y axis relative to the terrain ( slope) normal, not relative to the World Y axis????????? Anyone nows how? that will pretty much solv this i think

Another solution would be canceling the external forces that make it spinn but i cant find a function or formula that does that and works fine...
Any sugestions please? Thank you in advance

lonwolf

12-08-2006 14:48:25

ok after 5 excruciating hours (think i spelled right :D ) i finally got my body to walk stable on slopes heres the image to undrestand better


i used compound colision to make (in my opinion) the best "slope-riding" fela :lol: if someone needs the code here it is :

Vector3 body_pos(2.5,14,9.5);
Vector3 pos_1 = body_pos+Vector3(10,-12,10);
Vector3 pos_2 = body_pos+Vector3(10,-12,-10);
Vector3 pos_3 = body_pos+Vector3(-10,-12,10);
Vector3 pos_4 = body_pos+Vector3(-10,-12,-10);
std::vector<OgreNewt::Collision*> col_array;
OgreNewt::Collision* col_1 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(6,17,6), bn->getOrientation(), body_pos);
col_array.push_back(col_1);
OgreNewt::Collision* col_2 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(5,5,5), bn->getOrientation(), pos_1);
col_array.push_back(col_2);
OgreNewt::Collision* col_3 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(5,5,5), bn->getOrientation(), pos_2);
col_array.push_back(col_3);
OgreNewt::Collision* col_4 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(5,5,5), bn->getOrientation(), pos_3);
col_array.push_back(col_4);
OgreNewt::Collision* col_5 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(5,5,5), bn->getOrientation(), pos_4);
col_array.push_back(col_5);

OgreNewt::Collision* comp_col = new OgreNewt::CollisionPrimitives::CompoundCollision(mWorld, col_array);
OgreNewt::Body* bd = new OgreNewt::Body(mWorld, comp_col);
delete comp_col;

bd->attachToNode(bn);
bd->setPositionOrientation(bn->getPosition(), bn->getOrientation());


where bd=character body and bn = the character SceneNode

i will work a little and shrink down those spheres but the principle is the same

hope it helps in anyway some1. For my project is the last method of 5 in total that works. The rest = no effect :wink:

zzgame

10-10-2006 22:00:40

how to do apply a torque based on omega to keep the body facing forward and how to do modifying the UpVector joint to not allow for rotation ? I search all the topics about the upVector, bu not not find how to do it !
is someone can give me a little code ,thanks!

nikhil

01-11-2006 01:16:43

ok after 5 excruciating hours (think i spelled right :D ) i finally got my body to walk stable on slopes heres the image to undrestand better
i used compound colision to make (in my opinion) the best "slope-riding" fela :lol: if someone needs the code here it is :

Vector3 body_pos(2.5,14,9.5);
Vector3 pos_1 = body_pos+Vector3(10,-12,10);
Vector3 pos_2 = body_pos+Vector3(10,-12,-10);
Vector3 pos_3 = body_pos+Vector3(-10,-12,10);
Vector3 pos_4 = body_pos+Vector3(-10,-12,-10);
std::vector<OgreNewt::Collision*> col_array;
OgreNewt::Collision* col_1 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(6,17,6), bn->getOrientation(), body_pos);
col_array.push_back(col_1);
OgreNewt::Collision* col_2 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(5,5,5), bn->getOrientation(), pos_1);
col_array.push_back(col_2);
OgreNewt::Collision* col_3 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(5,5,5), bn->getOrientation(), pos_2);
col_array.push_back(col_3);
OgreNewt::Collision* col_4 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(5,5,5), bn->getOrientation(), pos_3);
col_array.push_back(col_4);
OgreNewt::Collision* col_5 = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, Vector3(5,5,5), bn->getOrientation(), pos_4);
col_array.push_back(col_5);

OgreNewt::Collision* comp_col = new OgreNewt::CollisionPrimitives::CompoundCollision(mWorld, col_array);
OgreNewt::Body* bd = new OgreNewt::Body(mWorld, comp_col);
delete comp_col;

bd->attachToNode(bn);
bd->setPositionOrientation(bn->getPosition(), bn->getOrientation());


where bd=character body and bn = the character SceneNode

i will work a little and shrink down those spheres but the principle is the same

hope it helps in anyway some1. For my project is the last method of 5 in total that works. The rest = no effect :wink:


How did you get to all the pos* Vector co-ordinates :shock: :shock: ?? and how did you get the primitives to show on the screen .. those white meshes????

plz help

thanks
nik

lonwolf

01-11-2006 13:54:10

ok so first of all i calculated them on a piece of paper considering the middle of the 4 sphere structure that Elpisoid... and regarding the spere radius.. just some simple calculations... anyway thats a nice example of a "free - fall - slide body " that doesnt rotates like crazy.. although its a more complex and clean way to avoid that in some ogrenewt examples.. i prefered making my own.. and another solution will be seting its heigth using OgreNewt::BasicRaycast..

Those white meshes are the visual representation of ogrenewt bodyes.. as you know ogrenewt works with bodyes you define not ogre.. so you can make your newton world far more diferent from the visual.. But to actualy see the newton bodyes a new class has been implemented OgreNewt::Debuger that is very simple to use.. heres my code for implementing it EFICIENTLY without updating it every frame that will result in a fps of 40-60 instead of 400... You simply show the bodyes position and size when you press the M key.. and if you wanna watch a bodys traiectory just press M more times :lol: +

heres a code, put it in KeyPressed

if(e->getKey()==CEGUI::Key::M) //view OgreNewt bodyes
{
if(main_var.hasShowedLines==false)
{
OgreNewt::Debugger::getSingleton().init( main_var.mSceneMgr );
OgreNewt::Debugger::getSingleton().showLines( mWorld );
main_var.hasShowedLines = true;
}
else
{
OgreNewt::Debugger::getSingleton().hideLines();
OgreNewt::Debugger::getSingleton().deInit();
main_var.hasShowedLines=false;
}
}


observ that main_var.hasShowedLines is a bool variable situated into a structure-type variable ( global defined ) so you can just define a bool hasShowedLines global variable and the code will work.. And dont forget when you "kill" your application to deInit OgreNewt::debugger or else on exit it will show you an error... :wink:


YourGameMainClass::~YourGameMainClass()
{
//etc your code
if(hasShowedLines)
{
OgreNewt::Debugger::getSingleton().hideLines();
OgreNewt::Debugger::getSingleton().deInit();
}

// the rest of your destruction code
}

nikhil

07-11-2006 11:20:43

@Ionwolf

Thnks for your reply.. really appreciate a thorough reply.. i still've to look at it thoroughly :P .. but i should be able to sail through..

peace

nik

lonwolf

07-11-2006 17:28:22

no prob mate glad to help.. note 2 all my nick is LonWolf not IonWolf :lol: :lol: :lol:

nikhil

14-11-2006 11:29:39

to LonWolf

Well.. I'm trying it.. but don't know wht to say.. anyways.. do u
ve an upvector applied to it right now???

What of the materialpair properties between the track and the character??

thanks
nik

lonwolf

14-11-2006 19:20:48

right now its using basicRaycast and upvector, yes.
the materials seem to have failed at the second touch between the character and the plane.. dont ask why.. but thats the beauty of what i created: the chars body never hits the ground.. unless the slope is like 80 degrees then it hits it :)) so no need for now to set material pairs.. although with this solution, making a jump or a nice fall off a cliff is chalenging :D but not imposible. i still havent written the code for it due to the amount of work i have to do for a trip to France. So ill solve that prob later.. :D

nikhil

19-11-2006 05:12:50

right now its using basicRaycast and upvector, yes.
the materials seem to have failed at the second touch between the character and the plane.. dont ask why.. but thats the beauty of what i created: the chars body never hits the ground.. unless the slope is like 80 degrees then it hits it :)) so no need for now to set material pairs.. although with this solution, making a jump or a nice fall off a cliff is chalenging :D but not imposible. i still havent written the code for it due to the amount of work i have to do for a trip to France. So ill solve that prob later.. :D


Hey man

I basically had a skater character. Thanks to your way of implementation. I'm able to produce a skating motion though not in the best of manner. Still it works nice at low speeds.

I replaced the spheres with cylinders and right now using setOmega to turn. I tried it with cylinders in the front and spheres in the back and vice versa. I'm just sharing with you some stuff I tried. May be someone might benefit from all this. Moreover I don't need to use Upvector.

As for the materialPairs, I don't think they are working in my case either.

Good luck with your trip..


thanks and regards

nik

nikhil

19-11-2006 05:13:55

also, what are u using the RayCast for??

lonwolf

19-11-2006 15:56:07

well since i reimplemented the upVector and removed gravity because of the character way of riding stairs and slopes, i need raycasting to simulate a gravity: setting the characters height acording to the terrain. this way i removed any kind of interaction between the char and the terrain. but i interacts well with other object. Note: i still have to make the jumping / falling code becoz i have no more gravity :roll: :wink:
but its doable :D

regards

nikhil

20-11-2006 16:01:55

[quote="lonwolfNote: i still have to make the jumping / falling code becoz i have no more gravity :roll: :wink:
but its doable :D

regards

LOL.. man.. Gud lukk with it.. And ofcourse, its doable.. if we can be God and turn Gravity off.. we can at the least make a monkey jump or an apple fall..

laters

nik

lonwolf

20-11-2006 18:34:29

seems that u didnt got the picture: i actualy have 3 diferent gravities
for arrows, fireballs and stones (apples LOL)., The character is the allmighty "floater" :)) that is he never jumps but he walks normaly and rects very good when hes riding slopes or walking up/down stairs. something that doesnt happen quite well when he interacts.. anyway, theres a nice ogrenewt demo if you have patience and go through them and one of them simulates a movement of a char and if im wrong corect me, but there a "clap"-type variable to detect if hes or not into the air. that i can determine using the the distance fro the source untill the ray hits the ground of the terrain/city/ any other object you can move onto and voila! first he'll have a nice move on the +Y axis untill he reaches maximum height and then a nice fall -Y untill the distance is like very small then he claps the char to the ground. its very easy. but like i said i dont have time to work on the gae right now or any piece of code for friday im at the airport :))