How to drag objects (like in Penumbra)

A place to discuss everything related to Newton Dynamics.

Moderators: Sascha Willems, walaber

How to drag objects (like in Penumbra)

Postby LukasBanana » Fri Jun 03, 2011 1:39 pm

Hi, what is the best way to implement object-mouse-drag? I mean the effect of dragging objects like in Penumbra where you can open doors or drag switchers etc. with the mouse.
My project: SoftPixel Engine
My forum: SoftPixel Forum
User avatar
LukasBanana
 
Posts: 35
Joined: Mon Jul 27, 2009 11:55 am
Location: Germany

Re: How to drag objects (like in Penumbra)

Postby JoeJ » Sat Jun 04, 2011 3:33 am

This was the first thing i tried to do with newton.
I was not happy with the kinematic joint, it solves each axis independently, and that leads to unnatural motion.
For example a body with velocity (x=10, y=5), swinging with low power to a target point, would cancel its y motion first, then swinging only in x direction forth an back until coming to rest.
Meanwhile i could fix that writing an own custom joint, but the thing i did first works well.
The code computes force and torque to get a body to target position and orientation, it operates on center of mass.
Real dragging from an offcenter point would require modifications.

Note that Penumbra is open source, and i looked for the code for the same thing, but didn't found it :)

Code: Select all

/*
Containing class vars:
handOrn = target orientation quaternion
hand pos = target position
... interpolated values to follow point in front player camera somewhat smoothly
*/

void AccumulateForce (float timestep)
   {
      //position... (code from older newton demos)

      if (!pickedBody) return;
      float MOUSE_PICK_DAMP = 20.0f;
      float MOUSE_PICK_STIFFNESS = 150.0f;
      float ANGULAR_STIFFNESS = 0.1f;

      float mass;
      float Ixx;
      float Iyy;
      float Izz;
      sVec3 com;
      sVec3 veloc;
      sMat4 matrix;
      BodyGetMatrix(pickedBody, matrix);

      BodyGetVelocity (pickedBody, veloc);
      BodyGetMassMatrix (pickedBody, mass, Ixx, Iyy, Izz);

                sVec3 pickedForce = handPos - matrix[3]; // body position
      float mag2 = pickedForce.SqL();
      if (mag2 > 20.0f * 20.0f) pickedForce *= 20.0f / sqrt (mag2);
      sVec3 force (pickedForce * mass * MOUSE_PICK_STIFFNESS);
      sVec3 dampForce (veloc * mass * MOUSE_PICK_DAMP);
      force -= dampForce;
      sVec3 grav (0.0f, mass * GRAVITY_Y, 0.0f);
      force -= grav;

            
      BodyData *data = (BodyData*) BodyGetUserData (pickedBody); // containing force and torque vectors, which are the applied in the callback
      
      data->force += force;

      // orientation...
      sQuat q;
      BodyGetRotation (pickedBody, q);

      sVec3 curAngVel;
      BodyGetAngVel (pickedBody, curAngVel); // == NewtonBodyGetOmega
      
      sVec3 targetAngVel = AngVelFromAToB (q, handOrn) * (1 / timestep * ANGULAR_STIFFNESS);
      sVec3 torque = ConvertAngVelToTorque (targetAngVel, curAngVel, matrix, timestep, mass, Ixx, Iyy, Izz);
      data->torque += torque;

      BodyActivate (pickedBody);
   }



// utilitys...


// convert rotational offset to angular velocity (divide by time afterwards)
inline sVec3 AngVelFromAToB (const sQuat &qA, const sQuat &qB)
{

   const float matchTolerance = 0.01f;
   const float faultTolerance = 0.05f;

   sQuat q = QuatFromAToB (qA, qB);
   sVec3 *omegaDir = (sVec3*)&q;
   float sql = omegaDir->SqL();
   if (sql   < (matchTolerance * matchTolerance))
      return sVec3 (0, 0, 0);

   float length = sqrt (sql);
   if (q[3] < -1) q[3] = -1;
   if (q[3] >  1) q[3] =  1;
   sVec3 angVel = (*omegaDir / length) * (2.0 * acos(q[3]));
   if (length   < faultTolerance) angVel *= (length - matchTolerance) / (faultTolerance - matchTolerance);
   return angVel;

}

// choose shortest rotation between 2 orientations
inline sQuat QuatFromAToB (const sQuat &qA, const sQuat &qB)
{
   sQuat q;
   if (qA.Dot(qB) < 0.0f)
   {
      q[0] = qA[0]; q[1] = qA[1]; q[2] = qA[2];
      q[3] = -qA[3];
   }
   else
   {
      q[0] = -qA[0]; q[1] = -qA[1]; q[2] = -qA[2];
      q[3] = qA[3];
   }
         
   return qB * q;
}

inline sVec3 ConvertAngVelToTorque (   sVec3 &targetAngVel, sVec3 &currentAngVel, sMat4 &matrix,
                        float timestep, float mass, float Ixx, float Iyy, float Izz)
{
   sVec3 torque = (targetAngVel - currentAngVel) / timestep;
   torque = matrix.Unrotate (torque);
   torque[0] *= Ixx;
   torque[1] *= Iyy;
   torque[2] *= Izz;
   torque = matrix.Rotate (torque);
   return torque;
}



The code isn't very clean, but works.
I can pickup bodys, carry them around, reorient them, let them down.
Maybe also suited to operate on levers, doors..., as i use it to put stress on ragdolls for testing.
I'ts also stable, no jittering if pushing an object inside a wall, a case where most other physics engines fail.
Matrix and Quat rotation order is reversed against to newton math lib, and quats are (x,y,z,w), not (w,x,y,z).
User avatar
JoeJ
 
Posts: 1489
Joined: Tue Dec 21, 2010 6:18 pm

Re: How to drag objects (like in Penumbra)

Postby LukasBanana » Sun Jun 05, 2011 6:08 am

Thank you :) I will test it and maybe take a look in the Penumbra source code.
My project: SoftPixel Engine
My forum: SoftPixel Forum
User avatar
LukasBanana
 
Posts: 35
Joined: Mon Jul 27, 2009 11:55 am
Location: Germany


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 0 guests

cron