I'm glad that you found my demo useful for debugging.
I have always been a big fan of this engine so it's nice to be able to help out.

Regarding the keys for the forklift, it should be like this...
W,A,S,D = Steering & driving
Space = Brakes
Q, E = Lift the fork up and down
R, F = Tilt the fork up and down(realised though that this is not the way a real forklift works, but hey, it's just for fun)

The collisions works perfectly now(unless I set solvermode to 0, see below).

Some things that are different though compared to ver 2.33/2.34.
In 3.0 the bodies move slower, like they are under water or something.
I'm using a gravity force of -11.0f but it behaves like it's only 6 or 7(compared to 2.34)
I have set angular and linear damping to 0 but it doesn't make any difference.
Also the wheels on the forklift as well as the fork itself turns faster in 2.34 and doesn't have that "extra" inertia as you mention, in 2.34 the forkjoint stops immediately when releasing the key.
I've tried changing the joint stiffness but that doesn't help.
[EDIT] Try replacing newton.dll in the demo folder with the 2.33(2.34) dll and you will see the difference. [/EDIT]
Just remembered though that I get the same "low gravity" and joint issues in 2.34 as well, if I change the Solvermode to anything other than 0.
In 3.0 if I try to set the SolverMode to 0, the forklift won't move at all, in world/test the bodies fall through each other and world/test2 just crasch the demo.
What is the default solvermode in 3.0?
And the joints.
I have three custom joints.
One raycast joint, one wheeljoint that is almost exactly like the MultiBodyVehicle joint and one "ForkLift joint".
The code below is a bit messy.

ForkLift joint
- Code: Select all
void NewtonLiftJoint::SubmitConstraints(const NewtonJoint* joint, dFloat timestep, int threadIndex)
{
const float PIN_DIST = 50.0f;
NewtonLiftJoint* lj = static_cast<NewtonLiftJoint*>(NewtonJointGetUserData(joint));
Transform4D childTransform,parentTransform;
NewtonBodyGetMatrix(lj->bodyA, &childTransform(0,0));
if(lj->bodyB)
NewtonBodyGetMatrix(lj->bodyB, &parentTransform(0,0));
Transform4D childPivot,parentPivot;
Matrix3D rot;
rot.SetIdentity();
rot.SetRotationAboutX(lj->angle * (3.14f/180.0f));
childPivot = childTransform * ( lj->localTransformA * rot );
if(lj->bodyB)
parentPivot = parentTransform * lj->localTransformB;
else
parentPivot = lj->locatorWorldTransform;
Vector3D childFront = childPivot[0];// Pin dir(red axle)
Vector3D childRight = childPivot[1];
Vector3D childUp = childPivot[2];
Point3D childPos = childPivot.GetTranslation();
Vector3D parentFront = parentPivot[0];// Pin dir(red axle)
Vector3D parentRight = parentPivot[1];
Vector3D parentUp = parentPivot[2];
Point3D parentPos = parentPivot * lj->relPos;
// Restrict linear movement
NewtonUserJointAddLinearRow (joint, &childPos.x, &parentPos.x, &childFront.x);
NewtonUserJointAddLinearRow (joint, &childPos.x, &parentPos.x, &childRight.x);
NewtonUserJointAddLinearRow (joint, &childPos.x, &parentPos.x, &childUp.x);
// Restrict angular movement
// Using Linear rows instead which gives a more robust joint, Angular Rows has a tendency to break/give in
Vector3D pointInPinChild = parentPos + parentFront * PIN_DIST;
Vector3D pointInPinParent = childPos + childFront * PIN_DIST;
Vector3D pointInPinChild2 = parentPos + parentRight * PIN_DIST;
Vector3D pointInPinParent2 = childPos + childRight * PIN_DIST;
NewtonUserJointAddLinearRow(joint, &pointInPinParent.x, &pointInPinChild.x, &childRight.x);
NewtonUserJointAddLinearRow(joint, &pointInPinParent.x, &pointInPinChild.x, &childUp.x);
NewtonUserJointAddLinearRow(joint, &pointInPinParent2.x, &pointInPinChild2.x, &childUp.x);
}
RayCast joint
- Code: Select all
void RCVWheel::SubmitConstraints(const NewtonJoint* joint, dFloat timestep, int threadIndex)
{
const float PIN_DIST = 50.0f;
RCVWheel* w = static_cast<RCVWheel*>(NewtonJointGetUserData(joint));
RCV* r = w->chassi;
Transform4D chassiTransform;
NewtonBodyGetMatrix(r->GetBody(), &chassiTransform(0,0));
Point3D suspPos; //Hard point there the suspension connects with the chassi
suspPos = chassiTransform * w->GetTargetNode()->GetNodePosition();
Matrix3D rot;
rot.SetIdentity();
rot.SetRotationAboutZ((w->steering * w->maxSteerAngle) * (3.14f/180.0f));
Vector3D chassiFront = chassiTransform[0]; //X
Vector3D chassiRight = chassiTransform[1]; //Y
Vector3D chassiUp = chassiTransform[2]; //Z
Vector3D wheelRight = chassiTransform.GetMatrix3D() * (rot * Vector3D(0, -1, 0));
wheelRight.Normalize();
NewtonWorld* nw = TheNewtonMgr->GetWorld();
// Cast Ray
Point3D p0 = suspPos;
Point3D p1 = suspPos + chassiTransform * Vector3D(0.0f, 0.0f, -(w->suspRestLength + w->radius) );
w->hitDist = 99.0f;
w->onGround = false;
w->prevsuspLen = w->suspLen;
NewtonWorldRayCast(nw, &p0.x, &p1.x, RayCallBack, w, 0);
bool wheelLocked = false;
if(w->onGround)
{
w->suspLen = ((w->suspRestLength + w->radius) * w->hitDist) - w->radius;
Vector3D contactForward = Cross(w->hitNormal, wheelRight);
//TheEngine->Report(String<>(Magnitude(contactForward)));
Vector3D contactRight = Cross(contactForward, w->hitNormal);
Point3D chassiCOM;
NewtonBodyGetCentreOfMass(r->GetBody(), &chassiCOM.x);
chassiCOM = chassiTransform * chassiCOM; //Local COM to Global
float chassiMass, Ixx, Iyy, Izz;
NewtonBodyGetMassMatrix(r->GetBody(), &chassiMass, &Ixx, &Iyy, &Izz);
w->hitPos = suspPos + chassiTransform * Vector3D(0.0f, 0.0f, -(w->suspRestLength + w->radius) * w->hitDist);
float compression = 1.0f - w->hitDist;
float nDotUp = Dot(w->hitNormal, chassiUp);
float springForce = w->suspStiffness * chassiMass * compression * nDotUp;
float comprVel = ( w->prevsuspLen - w->suspLen ) / timestep;
float dampingForce;
if(comprVel > 0)
dampingForce = w->suspDamping * chassiMass * comprVel;
else
dampingForce = w->suspDamping * 0.5f * chassiMass * comprVel; //TODO: Add Relaxation Damping as Wheel Parameter
float normalForce = (springForce + dampingForce);
//if(compression > 0.01f )
//{
// NewtonUserJointAddLinearRow(joint, &suspPos.x, &suspPos.x, &chassiUp.x);
// //NewtonUserJointSetRowMaximumFriction(joint, 0.0f);
// NewtonUserJointSetRowMinimumFriction(joint, 0.0f);
//}
//Vector3D chassiForce = normalForce * chassiUp;
Vector3D chassiForce = normalForce * w->hitNormal;
Vector3D chassiTorque = Cross(w->hitPos - chassiCOM, chassiForce);
NewtonBodyAddForce(r->GetBody(), &chassiForce.x);
NewtonBodyAddTorque(r->GetBody(), &chassiTorque.x);
// TODO: Implement minimum suspension length to prevent wheel from going into chassi.
// Linear Row along suspension direction
float maxForce = w->suspStiffness * chassiMass * 0.3f * nDotUp;
normalForce = Min(normalForce, maxForce);
float maxFriction = normalForce * 2.8f; // TODO: Add Slip Coefficient as Wheel Parameter
Vector3D forcePos = w->hitPos + chassiTransform * Vector3D(0.0f, 0.0f, 0.4f); //Roll Reduction TODO: Add Roll Reduction as Wheel Parameter
Vector3D brakePos = w->hitPos + chassiTransform * Vector3D(0.0f, 0.0f, 0.2f); //Roll Reduction TODO: Add Roll Reduction as Wheel Parameter
float brakeForce = w->brakeTorque * w->brake;
if(brakeForce > 0.0f)
{
maxFriction -= brakeForce;
NewtonUserJointAddLinearRow(joint, &brakePos.x, &brakePos.x, &contactForward.x);
NewtonUserJointSetRowMinimumFriction(joint, -maxFriction);
NewtonUserJointSetRowMaximumFriction(joint, maxFriction);
wheelLocked = true;
}
// Lateral Friction
NewtonUserJointAddLinearRow(joint, &forcePos.x, &forcePos.x, &contactRight.x);
NewtonUserJointSetRowMinimumFriction(joint, -maxFriction);
NewtonUserJointSetRowMaximumFriction(joint, maxFriction);
// Longitudinal Friction
// TODO: Brake force / Combine with Drive Force & Lateral Friction Force and scale them to fit within a friction cone.
// Must be done before adding constraint rows
// Drive force
Vector3D chassiVelocity(0,0,0);
Vector3D chassiOmega(0,0,0);
NewtonBodyGetVelocity(r->GetBody(), &chassiVelocity.x);
NewtonBodyGetOmega(r->GetBody(), &chassiOmega.x);
chassiVelocity += Cross(chassiOmega, suspPos - chassiCOM);
w->WheelForwardVel = Dot(chassiVelocity, contactForward);
float wheelRPM = Fabs(w->WheelForwardVel / w->radius);
float torqueDamping = 0.02f; //Uhm, this makes drive force decline as the wheel rotates faster... Higher value means lower top speed
wheelRPM = Max(1.0f / torqueDamping, wheelRPM);
float latVel = Fabs(Dot(chassiVelocity, chassiRight));
float driveForce = ( w->driveTorque * w->throttle ) / (wheelRPM * torqueDamping);
if(brakeForce == 0.0f)
{
Vector3D forwardForce = contactForward * (driveForce); // TODO: Fix proper engine force and stuff :)
Vector3D forwardTorque = Cross(forcePos - chassiCOM, forwardForce);
NewtonBodyAddForce(r->GetBody(), &forwardForce.x);
NewtonBodyAddTorque(r->GetBody(), &forwardTorque.x);
if(w->hitBody)
{
Vector3D backwardForce = contactForward * (-driveForce); // TODO: Fix proper engine force and stuff :)
//Vector3D backwardTorque = Cross(forcePos - chassiCOM, forwardForce);
NewtonBodyAddForce(w->hitBody, &backwardForce.x);
}
}
}
else
{
w->suspLen = w->suspRestLength;
w->skidding = false;
if(w->driveTorque * w->throttle == 0.0f)
w->WheelForwardVel *= 0.99f; // Slow down the wheels so they don't spin forever...
else
w->WheelForwardVel = 15.0f * w->throttle; // Faking a bit here. ;)
}
// Update subnode(Wheel visuals)
if(w->subNode && wheelLocked == false)
{
Matrix3D spinRot;
spinRot.SetIdentity();
w->spinAngle += w->WheelForwardVel / (w->radius * 2.0f);
spinRot.SetRotationAboutY(w->spinAngle * (3.14f / 180.0f));
spinRot = rot * spinRot;
Point3D wheelpos(0.0f, 0.0f, -w->suspLen);
Transform4D wheeltransform(spinRot, wheelpos);
w->subNode->SetNodeTransform(wheeltransform);
w->subNode->Invalidate();
}