The problem about dragging in physical world!

qi-an

09-07-2008 10:20:54

Hi ,everybody !
I'm new for Mogre,in my code ,I use MogreNewt as physical engine.Now,I want to move and drag object by keyboard and mouse.My whole codes are based on Demo_04 in OgreNewt ,and the boject have be moved and dragged well ,but now ,I also have two problems about it.
First , I don't know how to stop the callback fuction,so that the boject move automaticly and I can't stop it.
Second,the similar problem is that I dragging object with mouse,when I release the mouse ,the object don't fall the floor but fly.
There isn't setStandarForce() function in MogreNewt ,Is there anyway to solve it?

I need Any help and appreciate !

(I'm so sorry about my poor English !

ProfesorX

09-07-2008 18:38:53


There isn't setStandarForce() function in MogreNewt ,Is there anyway to solve it?


MogreNewt is somewhat different from OgreNewt, is not an "exact" copy of OgreNewt, in OgreNewt you have callbacks, in MogreNewt you have "events" and "delegates", and also some methods in MogreNewt are different from those in OgreNewt, in MogreNewt you have a static method called "Body.ApplyGravityForce()" that would be the equivalent to setStandardForce(), but i suggest you that instead of using that function, apply the gravity in your own function, with all other forces, so you can have better control. In the following example, i apply forces to get a maximum velocity and later, apply a gravity force of -9.8



// Apply your own forcecallback
body.ForceCallback += new ForceCallbackHandler(MyOwnForceCallback);




public void MyOwnForceCallback(Body me)
{

Vector3 gravity = new Vector3(0f, -9.8f, 0f);
float deltaTime = me.World.TimeStep;

Vector3 V0 = me.Velocity;
Vector3 V1 = desiredVelocity;
Vector3 acel = Vector3.ZERO;
acel.x = (V1.x - V0.x) / deltaTime;
acel.z = (V1.z - V0.z) / deltaTime;

acel = acel * me.Mass;
me.AddForce(acel);
me.AddForce(gravity * me.Mass);
}

qi-an

10-07-2008 05:09:38

Thank you ,profesorX!
Your codes are most valuable resource for me!
But,what about velocity ,I don't understand it clearly! Can you explain more?

Thanks,again!

ProfesorX

10-07-2008 18:29:15

it's easy, supose you want to move your object with a maximum velocity (desiredVelocity) of 50, so you need apply a force (aceleration) to your body, but once you reach the maximum velocity, you don't want to keep acelerating, as this will increase the velocity of your body, so you have to subtract the velocity of your body from the maximum velocity, to get the aceleration (force) needed to keep your body at maximum velocity.

in other words:

acel = desiredVelocity - bodyVelocity;

Since the body is not moving, has a velocity of 0, so the aceleration (force) needed is 50;

acel = 50 - 0;


If the body is moving at a velocity of 30, you need a force of 20 to get a velocity of 50;

acel = 50 - 30;

acel.x, acel.z are the direction in wich you want to move, note that if you want to move in an oposite direcction, you need a negative value.

Hope this little explanation help you

qi-an

14-07-2008 05:24:19

Thank you,ProfesorX!
Your explanation are so brilliant! :D
I'am so sorry ,I have to bother you again! :(
Now,in my code ,there are three objects and a plane as floor,in the begining,all object fall to floor ,then I picking and dragging a object with mouse ,it work fine,but when I pinking and dragging another object ,the object that be picked first be dragged together,I think my mistake is in body.ForceCallback event,right?
My code sippet like this:

namespace testOgreNewt
{
public partial class Form1 : Form
{
World mWorld;
const int NEWTON_FRAMERATE = 60;
float m_update = 1.0f / (float)NEWTON_FRAMERATE;
float m_elapsed = 0;
Body dragBody;
float dragDist;
Vector3 dragPoint;
float moveX, moveY;
bool IsDrawing;
Vector3 desiredVelocity = new Vector3(1, 1, 1);
int moveStep;

public void Go()
{
Show();
while (mRoot != null && mRoot.RenderOneFrame())
Application.DoEvents();
}

public void InitOgre()
{
// Create root object
...

// Define Resources
...
// Setup RenderSystem
...

// Create Render Window
...

// Init resources
...
}

public void SceneCreator()
{
mgr = mRoot.CreateSceneManager(SceneType.ST_GENERIC);
MogreNewt.Debugger.Instance.Init(mgr);
cam = mgr.CreateCamera("Camera");
cam.SetPosition(200, 200, 200);
cam.LookAt(new Vector3(0, 0, 0));
cam.AutoAspectRatio = true;
cam.NearClipDistance = 5;
mviewport = mWindow.AddViewport(cam);
mviewport.BackgroundColour = new ColourValue(0.7f, 0.7f, 0.7f);


Plane plane = new Plane(Vector3.UNIT_Y, 0);
MeshManager.Singleton.CreatePlane("ground", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
plane, 1500, 1500, 20, 20, true, 1, 5, 5, Vector3.UNIT_Z);
Entity floor = mgr.CreateEntity("floor","ground");
SceneNode floornode = mgr.RootSceneNode.CreateChildSceneNode("floornode",new Vector3 (0,30,0));
floornode .AttachObject(floor);
floor .SetMaterialName ("Examples/GrassFloor");

mWorld = new World();
mWorld.SetWorldSize(new Vector3(-1000, -1000, -1000), new Vector3(1000, 1000,1000));

Collision col = new MogreNewt.CollisionPrimitives.TreeCollision(mWorld, floor,true);
Body bod = new Body(mWorld, col);
//col.Dispose();

bod.AttachToNode(floornode);
bod.SetPositionOrientation(new Vector3(0, 0, 0), Quaternion.IDENTITY);

float boxmass = 100;
Vector3 boxsize = new Vector3(30, 30, 30);
Vector3 inertia = MomentOfInertia.CalcBoxSolid(boxmass, boxsize);
Entity box1 = mgr.CreateEntity ("box1node","box01.mesh");
SceneNode box1node = mgr.RootSceneNode.CreateChildSceneNode("box1node");
box1node.AttachObject(box1);
box1node .Scale (0.3f,0.3f,0.3f);

Collision col1 = new MogreNewt.CollisionPrimitives.Box(mWorld, boxsize);
Body bod1 = new Body(mWorld, col1);
bod1.SetMassMatrix(boxmass, inertia);
bod1.AttachToNode(box1node);
bod1.IsGravityEnabled = true;
bod1.SetPositionOrientation(new Vector3 (60,100,30), Quaternion.IDENTITY);

//...box2...

//...box3...


//MogreNewt.Debugger.Instance.ShowLines(mWorld);

IsDrawing = false;

moveStep = 0;

InputHandler();

this.CreateFrameListen();
}

protected void CreateFrameListen()
{
mRoot .FrameStarted += new FrameListener.FrameStartedHandler(Newton_FrameStarted);
}

protected void InputHandler()
{
this.KeyDown += new KeyEventHandler(Form1_KeyDown);
this.KeyUp += new KeyEventHandler(Form1_KeyUp);
this.MouseDown += new MouseEventHandler(Form1_MouseDown);
this.MouseMove += new MouseEventHandler(Form1_MouseMove);
this.MouseUp += new MouseEventHandler(Form1_MouseUp);

}

bool mRoot_FrameStarted(FrameEvent evt)
{


return true;
}

void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (dragBody != null)
{
dragBody = null;
}
}

void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (dragBody!=null && e.Button == MouseButtons.Left)
{

dragBody.ForceCallback += new ForceCallbackHandler(gravityCallback);
//dragBody.AutoFreeze = true;

//dragBody = null;
dragPoint = Vector3.ZERO;
dragDist = 0;

IsDrawing = false;
}
}

void gravityCallback(Body me)
{
Vector3 gravity = new Vector3(0f, -980f, 0f);
float deltaTime = me.World.TimeStep;

Vector3 V0 = me.Velocity;
Vector3 V1 = desiredVelocity;
Vector3 acel = Vector3.ZERO;
acel.x = (V1.x - V0.x) / deltaTime;
acel.z = (V1.z - V0.z) / deltaTime;

acel = acel * me.Mass;
me.AddForce(acel);
me.AddForce(gravity * me.Mass);
me.Force = gravity;
}


void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e .Button == MouseButtons .Left && dragBody != null )
{
moveX = (float)e.X / mviewport.ActualWidth;
moveY = (float)e.Y / mviewport.ActualHeight;
IsDrawing = true;

}
}

void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
//perform a raycast
//start at the camera ,and go for 1000 units in the Z direction.
Vector3 start, end;
float clickX, clickY;

clickX = (float) e.X / mviewport.ActualWidth;
clickY = (float) e.Y / mviewport.ActualHeight;

Ray mouseRay = cam.GetCameraToViewportRay(clickX, clickY);

start = mouseRay.Origin;
end = mouseRay.GetPoint(1000);

BasicRaycast Ray = new BasicRaycast(mWorld, start, end);
BasicRaycast.BasicRaycastInfo info = Ray.FirstHit;

if (info.mBody != null )
{
// a body was fonnd. first let's find the point we clicked, in local coordination of the body;

// while dragging, make sure the body can't fall asleep.
info.mBody.UnFreeze();
info.mBody.AutoFreeze = false;

Vector3 bodpos;
Quaternion bodorient;

info.mBody.GetPositionOrientation(out bodpos, out bodorient);

// info.mDistance is in the range [0,1]
Vector3 globalpt = mouseRay.GetPoint(1000 * info.mDistance);
Vector3 localpt = bodorient.Inverse() * (globalpt - bodpos);

//save the relevant drag information.
dragBody = info.mBody;
dragDist = (1000 * info.mDistance);
dragPoint = localpt;

dragBody.ForceCallback += new ForceCallbackHandler(dragBody_ForceCallback);

}

}
}

void dragBody_ForceCallback(Body body)
{
if (IsDrawing)
{
Vector3 campt, bodpt;
//first fine the global point the mouse is at...
Ray camray = cam.GetCameraToViewportRay(moveX, moveY);

campt = camray.GetPoint(dragDist);

//now find the global point on the body
Quaternion bodorient;
Vector3 bodpos;

body.GetPositionOrientation(out bodpos, out bodorient);

bodpt = (bodorient * dragPoint) + bodpos;

//apply the spring force
Vector3 inertia;
float mass;

body.GetMassMatrix(out mass, out inertia);

Vector3 dragforce = ((campt - bodpt) * mass) - body.Velocity;

//Add the force
body.AddGlobalForce(dragforce, bodpt);

//Body.ApplyGravityForce(body);

Vector3 gravity = new Vector3(0, -9.8f, 0) * mass;
body.AddForce(gravity);
}

}

void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W && dragBody != null)
{
moveStep = 0;
dragBody .ForceCallback +=new ForceCallbackHandler(forceCallback_w);
}
}

void forceCallback_w(Body me)
{
if (moveStep <= 100)
{
Vector3 force = new Vector3(0, 9.8f, -3000);
me.Force = force * new Vector3(0, -1, 1);
//body.AddLocalForce(force, new Vector3(0, 5, 5));
moveStep++;
}
return;
}

bool Newton_FrameStarted(FrameEvent evt)
{

m_elapsed += evt.timeSinceLastFrame*4 ;

if ((m_elapsed > m_update) && (m_elapsed < (1.0f)))
{
while (m_elapsed > m_update)
{
mWorld.Update(m_update);
m_elapsed -= m_update;
}
}
else
{
if (m_elapsed < (m_update))
{
// not enough time has passed this loop, so ignore for now.
}
else
{
mWorld.Update(m_elapsed);
m_elapsed = 0.0f; // reset the elapsed time so we don't become "eternally behind".
}
}
return true;
}

public Form1()
{
InitializeComponent();
}
}
}


I need any help and appreciate to you!

(I'm so sorry about my poor English!)