Moving a character in the gameworld with newton physics

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
mesklinite
Posts: 11
Joined: Wed Jan 25, 2006 12:45 am

Moving a character in the gameworld with newton physics

Post by mesklinite »

Hi guys,

I've been looking at the irrlicht with the Newton physics implement. The one problem I have is the fact that I can move the character from its position. I have changed the level from one we have made internally. Is there something that Newton is doing in terms of placing the character back to a location that Newton determines?

I'd appreciate any input you guys have.

The tutorial I followed: http://irrforge.org/index.php/Simple_Ne ... ht_Example
I have changed the camera location and where it's looking at.

This is the code we're using:

Code: Select all

#include <Irrlicht.h>
#include "newton.h"
#include <memory.h>

static NewtonWorld* nWorld;

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#pragma comment(lib, "Irrlicht.lib")
#pragma comment(lib, "Newton.lib")

IrrlichtDevice *device = NULL;
IVideoDriver* driver = NULL;
ISceneManager* smgr = NULL;
float NewtonToIrr = 1;;//32.0f;
float IrrToNewton = 1/NewtonToIrr;
IGUIStaticText* pText = NULL;
bool debugOn = true;
float g_disp = 0.0f;

class MyEventReceiver : public  IEventReceiver
{
public:

///////////////////////////

	virtual bool OnEvent(SEvent event)
	{
     
 		if (event.EventType == irr::EET_KEY_INPUT_EVENT&&
			event.KeyInput.PressedDown)
		{
			
			switch(event.KeyInput.Key)
			{
				case KEY_ESCAPE:
				device->closeDevice();
				break;

				case KEY_KEY_D:
				debugOn = !debugOn;
				break;

			}

		}// pressdown

		return 0;

	}
};


MyEventReceiver receiver;

// allocation of memory from Newton
void* _cdecl
NewtonAlloc (int sizeInBytes)
{
	return new char[sizeInBytes];
}

// destruction of memory from Newton
void _cdecl
NewtonFree (void *ptr, int sizeInBytes)
{
	char *tmp;
	tmp = (char*) ptr;
	delete[] tmp;
}

/*
Function:	AddGlobalForce (vector3df Force, vector3df Point, matrix4 BodyMatrix,const NewtonBody* body)

Returns:	Nothing
Parameters:	vector3df Force -- the force you want to apply
			vector3df Point -- global space location to apply the force
			matrix4 BodyMatrix -- Newton Matrix describing object
			NewtonBody* body   -- the body in question

Purpose:	Add a force to an object displaced from the center of mass

Note:		Because of the displacement, you will get a spin or torque, and
			you have to tell Newton what that spin is. Thats what this function
			does.

*/


void AddGlobalForce (vector3df Force, vector3df Point, matrix4 BodyMatrix,const NewtonBody* body)
{
	vector3df R = Point - BodyMatrix.getTranslation();
    vector3df Torque = R.crossProduct(Force);
    NewtonBodyAddForce (body,&Force.X);
    NewtonBodyAddTorque (body,&Torque.X);
}

/*
Function:	AddLocalForce (vector3df Force, vector3df LocalPoint, matrix4 BodyMatrix,const NewtonBody* body)

Returns:	Nothing
Parameters:	vector3df Force -- the force you want to apply, in local space
			vector3df Point -- local space location to apply the force
			matrix4 BodyMatrix -- Newton Matrix describing object
			NewtonBody* body   -- the body in question

Purpose:	Takes a local force and displacement and translates it into a global
			force request

Note:		Because of the displacement, you will get a spin or torque, and
			you have to tell Newton what that spin is. Thats what this function
			does.Called only from within ApplyTorqueandForceHandler

*/
void AddLocalForce (vector3df LocalForce, vector3df LocalPoint, matrix4 BodyMatrix,const NewtonBody* body)
{
     vector3df GlobalForce,GlobalPoint;
     BodyMatrix.transformVect(LocalForce,GlobalForce);
    BodyMatrix.transformVect(LocalPoint,GlobalPoint);
	if (LocalForce.X == 0.0f && LocalForce.Y == 0.0f && LocalForce.Z == 0.0f)
	{

	}
	else
	{
		//AddGlobalForce (GlobalForce, GlobalPoint,BodyMatrix,body);
		
	}
}

void _cdecl NewtonDebugCollision(const NewtonBody* body, int vertexCount, const float* FaceArray, int faceId)
{
	core::vector3df p0 (FaceArray[0], FaceArray[1], FaceArray[2] );
	
	const video::SColor c0(255,55,255,0);

	for (int i = 2; i < vertexCount; i ++) 
	{
		core::vector3df p1( FaceArray[(i-1) * 3 + 0], FaceArray[(i-1) * 3 + 1], FaceArray[(i-1) * 3 + 2] );
		core::vector3df p2( FaceArray[i * 3 + 0], FaceArray[i * 3 + 1], FaceArray[i * 3 + 2] );
	
		core::triangle3df t;
		t.set(p1*NewtonToIrr,
			  p2*NewtonToIrr,
			  p0*NewtonToIrr);
		
	 	driver->draw3DTriangle(t, c0);
	}
}



void _cdecl NewtonDebugBody (const NewtonBody* body)
{

	matrix4 mat;
	SMaterial material;

	material.Texture1 = 0;
	material.Lighting = false;
 	driver->setTransform(video::ETS_WORLD, mat);
 	driver->setMaterial(material);
	NewtonBodyForEachPolygonDo(body,NewtonDebugCollision);

}

static void setTransform(const NewtonBody* body, const float* matrix)
{
    //get graphic object
    ISceneNode* node = (ISceneNode*) NewtonBodyGetUserData(body);

    //copy matrix to an irrlicht matrix
    matrix4 mat;
    memcpy(mat.M, matrix, sizeof(float)*16);

    //set transformation
    node->setPosition(mat.getTranslation() * NewtonToIrr);
	node->setRotation(mat.getRotationDegrees());
}

static void setForceAndTorque(const NewtonBody* body)
{
    float mass;
    float Ixx;
    float Iyy;
    float Izz;
	matrix4 mat;
	mat.makeIdentity();
	NewtonBodyGetMatrix(body,mat.M);

    NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);

    vector3df force(0, -mass* 9.8f, 0.0);
    vector3df torque(0, 00.0f, 0);
	vector3df mforce(0,0,500);
	vector3df displace(g_disp,0,0);
    NewtonBodyAddForce(body, &force.X);
    AddLocalForce(mforce,displace,mat,body);
}


int main()
{
device = createDevice(EDT_DIRECT3D9,dimension2d<s32>(640,480), 32,false,false,false,&receiver);

driver = device->getVideoDriver();
smgr = device->getSceneManager();
IGUIEnvironment* env = device->getGUIEnvironment();
   
 	pText = env->addStaticText(L"fred",core::rect<int>(20,20,440,200), false);
	pText->setOverrideColor(video::SColor(255,240,240,235));
	pText->setOverrideFont(
	env->getFont("midfont.bmp"));

   //1. Create Newtonworld
   nWorld = 	 NewtonCreate(NewtonAlloc, NewtonFree);

   // Set up default material properties for newton
   int i = NewtonMaterialGetDefaultGroupID(nWorld);
   NewtonMaterialSetDefaultFriction   (nWorld, i, i, 0.8f, 0.4f);
   NewtonMaterialSetDefaultElasticity (nWorld, i, i, 0.3f);
   NewtonMaterialSetDefaultSoftness   (nWorld, i, i, 0.05f);
   NewtonMaterialSetCollisionCallback (nWorld, i, i, NULL, NULL, NULL, NULL);
  
   //MESH
   //ISceneNode* node = smgr->addTestSceneNode();
 	core::aabbox3d<f32> sbox;
   vector3df ssize;
   float sss = 2.0f;
   IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2");
   IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
   if (node)
   {
      node->setMaterialFlag(EMF_LIGHTING, false);
      node->setFrameLoop(320, 368);
      node->setScale(vector3df(sss,sss,sss));
      node->setMaterialTexture( 0, driver->getTexture("../media/sydney.bmp") );
      node->setPosition(core::vector3df(-736,464,-1555));
      node->setAnimationSpeed(2);

	//size the box in Newton units
 	sbox = mesh->getMesh(0)->getBoundingBox();
	ssize = sbox.getExtent()*IrrToNewton*sss;
    g_disp = ssize.X;
   
   }
   
   //2.a Define Newtoncollision
   NewtonCollision* myShape = NewtonCreateSphere(nWorld, ssize.X/2, ssize.Y/2, ssize.Z/2, NULL);
   
   //b. Create NewtonBody
   NewtonBody* myBody = NewtonCreateBody(nWorld, myShape);
   
   //c. Set Body Properties
  // NewtonBodySetMassMatrix(myBody, 1.0f, 1.0f, 1.0f, 1.0f);
   NewtonBodySetMassMatrix(myBody, 65.0f, 65.0f*ssize.X*ssize.X/4, 65.0f*ssize.Y*ssize.Y/4, 65.0f*ssize.Z*ssize.Z/4);
   NewtonBodySetForceAndTorqueCallback(myBody, setForceAndTorque);
   NewtonBodySetUserData(myBody, (void*) node); //with this you are sending your graphic pointer to Newton.
   NewtonBodySetTransformCallback(myBody, setTransform);
   
/*   
   NewtonBodySetLinearDamping(myBody,1);
	vector3df rd(1,1,1);
	NewtonBodySetAngularDamping(myBody,&rd.X);
 */
	NewtonJoint* upVector;
	vector3df upDirection (0.0f, 1.0f, 0.0f);
	upVector = NewtonConstraintCreateUpVector (nWorld, &upDirection.X, myBody);

   ICameraSceneNode*  camera = smgr->addCameraSceneNodeFPS(0, 200.0f, 250.0f);
   camera->setPosition(vector3df(-736,464,-1818));
   camera->setTarget(vector3df(-736,83,-1818));
               
   //Level
   device->getFileSystem()->addZipFileArchive
      ("../media/level2.pk3");
   scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("level2.bsp");
   scene::ISceneNode* q3node = 0;
    
     if (q3levelmesh)
      q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0));
   q3node->setPosition(core::vector3df(-1370,-130,-1400));
   
     //LevelNewtonCollision
     NewtonCollision* nmapcollision = NewtonCreateTreeCollision(nWorld, NULL);
     NewtonTreeCollisionBeginBuild(nmapcollision);
     int cMeshBuffer, j;
     int v1i, v2i, v3i;
     IMeshBuffer *mb;
     float vArray[9]; // vertex array (3*3 floats)
     int tmpCount = 0;

	core::aabbox3d<f32> box;
	//size the box in Newton units
 	box = q3levelmesh->getMesh(0)->getBoundingBox();
	vector3df size = box.getExtent()*IrrToNewton;

     for (cMeshBuffer=0; cMeshBuffer<q3levelmesh->getMesh(0)->getMeshBufferCount(); cMeshBuffer++)
   {     
      mb = q3levelmesh->getMesh(0)->getMeshBuffer(cMeshBuffer);
      S3DVertex2TCoords* mb_vertices = (S3DVertex2TCoords*)mb->getVertices();
      u16* mb_indices  = mb->getIndices();
      // add each triangle from the mesh
      for (j=0; j<mb->getIndexCount(); j+=3)
      {
         
	//	printf("buff %d count %d\n",cMeshBuffer,j);
		  
		 v1i = mb_indices[j];
         v2i = mb_indices[j+1];
         v3i = mb_indices[j+2];
		 vArray[0] = mb_vertices[v1i].Pos.X* IrrToNewton;
         vArray[1] = mb_vertices[v1i].Pos.Y* IrrToNewton;
         vArray[2] = mb_vertices[v1i].Pos.Z* IrrToNewton;
         vArray[3] = mb_vertices[v2i].Pos.X* IrrToNewton;
         vArray[4] = mb_vertices[v2i].Pos.Y* IrrToNewton;
         vArray[5] = mb_vertices[v2i].Pos.Z* IrrToNewton;
         vArray[6] = mb_vertices[v3i].Pos.X* IrrToNewton;
         vArray[7] = mb_vertices[v3i].Pos.Y* IrrToNewton;
         vArray[8] = mb_vertices[v3i].Pos.Z* IrrToNewton;
 
          NewtonTreeCollisionAddFace(nmapcollision, 3, &vArray[0], 12, 1);
     }
   }
   
      NewtonTreeCollisionEndBuild(nmapcollision, 0);
      NewtonBody* nmapbody = NewtonCreateBody(nWorld, nmapcollision);
     
      // set the newton world size based on the bsp size
      float boxP0[3];
      float boxP1[3];
      float matrix[4][4];
	  matrix4 mmm;
	  mmm.setTranslation(vector3df(-1370,-130,-1400)*IrrToNewton);

	  NewtonBodySetMatrix(nmapbody,&mmm.M[0]);
      NewtonCollisionCalculateAABB (nmapcollision, &matrix[0][0],  &boxP0[0], &boxP1[0]);
      NewtonSetWorldSize (nWorld, (float*)boxP0, (float*)boxP1);
	  int rate;
	  wchar_t tmp[1024];
   while(device->run())
   {
      NewtonUpdate(nWorld, 0.01f);
      //camera->setTarget(node->getPosition());
     
      driver->beginScene(true, true, video::SColor(0,0,0,0));

		if (debugOn)
		{
		 	 NewtonWorldForEachBodyDo (nWorld, NewtonDebugBody);

		}
			rate = driver->getFPS();

			vector3df cPos = camera->getAbsolutePosition();
			swprintf(tmp, 1024, L"camera[%2.1f,%2.1f,%2.1f] fps %d\nD toggle Debug",cPos.X,cPos.Y,cPos.Z,rate);
			pText->setText(tmp);
      smgr->drawAll();
	  env->drawAll();
      driver->endScene();
   }
   device->drop();
   // 4. Destroy World
   NewtonDestroy(nWorld);
   return 0;
} 
dhenton9000
Posts: 395
Joined: Fri Apr 08, 2005 8:46 pm

Post by dhenton9000 »

can you describe your problem in a bit more detail. I posted the code you are looking at.

If your problem is that you expect the character to stand still. It won't, there's a torque being applied and sending it all over the place.

also, the code is VERY dependent on the model. You have to position the Sydney node so it is above the surface and drops down. If it penetrates the surface at start up Newton "pushes" it until there is no interpenetration.
pfo
Posts: 370
Joined: Mon Aug 29, 2005 10:54 pm
Location: http://web.utk.edu/~pfox1

Post by pfo »

If you want to see how to make a really nice character controller w/ Newton, look at the tutorial that comes with the SDK. Note that if the character is moving, the controller sets all friction with everything the character touches to 0, and when it stops it sets it to 2 (lots of friction). This allows a character to walk up stairs or slopes without slowing down, or stop on a stair or slope without sliding down. It also aligns tangential velocity with direction traveling so that moving sideways on a hill won't cause your character to inadvertently turn while walking. If you want a nice character controller to work with, I suggest looking at that and trying to implement it in Irrlicht.
mesklinite
Posts: 11
Joined: Wed Jan 25, 2006 12:45 am

Post by mesklinite »

What is happening at the moment, none of the information that I put in the sydney node affects the location where sydney is. I will look at the newton tutorials as well.
dhenton9000
Posts: 395
Joined: Fri Apr 08, 2005 8:46 pm

Post by dhenton9000 »

mesklinite wrote:What is happening at the moment, none of the information that I put in the sydney node affects the location where sydney is. I will look at the newton tutorials as well.

you are right, the code "resets" sydney overriding your input.

check out the parameter represented by NULL in this snippet

Code: Select all


   //2.a Define Newtoncollision
   NewtonCollision* myShape = NewtonCreateSphere(nWorld, ssize.X/2, ssize.Y/2, ssize.Z/2, NULL);

The newton docs will explain it, its an offset matrix, I don't use it myself.

BTW is that mesklinite as in HAL CLEMENT's Misson of Gravity? No wonder you are using Newton! :D
mesklinite
Posts: 11
Joined: Wed Jan 25, 2006 12:45 am

Post by mesklinite »

Yep that's right Mesklinite is form that Sci-Fi book. Learning how to use Newton, I'm gonna look at what you guys mentioned here today I've been MIA for a few days.

Thanks for help, I think I might have a few more questions, but we'll see what this french guy can do haha
mesklinite
Posts: 11
Joined: Wed Jan 25, 2006 12:45 am

Post by mesklinite »

The one thing I had problems last week and again today when I try to implement the offset matrix is the fact that no where in the documentation do they show where box is declared.

Code: Select all

dMatrix matrix (box.GetMatrix());
	matrix.m_posit.m_x = 0.0f;
	matrix.m_posit.m_y = 1.0f;
	matrix.m_posit.m_z = 0.0f;
	NewtonBodySetMatrix (ribidBodyBox, &matrix[0][0]);
Is it possible to move the model without having an offset matrix?
pfo
Posts: 370
Joined: Mon Aug 29, 2005 10:54 pm
Location: http://web.utk.edu/~pfox1

Post by pfo »

Is it possible to move the model without having an offset matrix?
Offset matrix is a kind of confusing term to use here when talking about Newton. In terms of Newton, if someone said to me 'offset matrix', the first thing that comes to mind is the collision offset matrix (passed when you do NewtonCreateBox, NewtonCreateSphere, etc..). The best way to move a body in Newton is through a Force and Torque callback. If you just want to set a body's initial position, use NewtonBodySetMatrix
mesklinite
Posts: 11
Joined: Wed Jan 25, 2006 12:45 am

Post by mesklinite »

I am having a problem and it's something that's I've seen in different approaches that I've had to try to solve this problem.

I always seem to get this error yet in everything that's I've seen, the code

error C2228: left of '.GetMatrix' must have class/struct/union type

Also, what is the purpose of the 4by4 matrix,how does this represent the coordinate system of irrlicht.

Code: Select all


        BoxPrimitive* box;
	NewtonCollision* collision;

	dMatrix matrix (box.GetMatrix());
	matrix.m_posit.m_x = 0.0f;
	matrix.m_posit.m_y = 1.0f;
	matrix.m_posit.m_z = 0.0f;


   //2.a Define Newtoncollision
   //NewtonCollision* myShape = NewtonCreateSphere(nWorld, ssize.X/2, ssize.Y/2, ssize.Z/2, &matrix[0][0]);
   NewtonCollision* myShape = NewtonCreateSphere(nWorld, ssize.X/2, ssize.Y/2, ssize.Z/2, NULL);

   //NewtonCollision* myShape = NewtonCreateSphere(nWorld, (-736), (464) ,(-1555), NULL);
   
   //b. Create NewtonBody
   NewtonBody* myBody = NewtonCreateBody(nWorld, myShape);

   //c. Body properties
   NewtonBodySetMatrix(myBody,&matrix[0][0]);

pfo
Posts: 370
Joined: Mon Aug 29, 2005 10:54 pm
Location: http://web.utk.edu/~pfox1

Post by pfo »

You declared BoxPrimitive as a pointer, you can't use the '.' operator on it to access it, you must use '->'. Also, don't you need to allocate the box? Like 'BoxPrimitive *box = new BoxPrimitive;'?
what is the purpose of the 4by4 matrix,how does this represent the coordinate system of irrlicht.
A 4x4 homogenous matrix represents a position and orientation in 3d space. Matrices have a number of operations that can be applied on them that have use in graphics engines and video games. I won't go into details 'cause there's a lot, but if you don't know about them, do yourself a favor and learn about some of them. Especially if you're working with Newton, I can't tell you how many times I use matrix operations w/ Newton to do things like figure out relative positions and / or orientations, etc...
mesklinite
Posts: 11
Joined: Wed Jan 25, 2006 12:45 am

Post by mesklinite »

Code: Select all

	matrix4 mat2;
	mat2.setTranslation(node->getPosition());
	NewtonBodySetMatrix(myBody, &mat2.M[0]);
This is what we were missing! Thanks for help guys, it was very appreciated.
Post Reply