Fix WheeledVehicle driving and suspension raycasts

This commit is contained in:
Wojtek Figat
2021-08-20 15:30:01 +02:00
parent 09e2b737f0
commit aa224f6296
3 changed files with 66 additions and 43 deletions

View File

@@ -291,7 +291,8 @@ void WheeledVehicle::Setup()
offsets[i] = C2P(wheel.Collider->GetLocalPosition());
}
PxF32 sprungMasses[PX_MAX_NB_WHEELS];
PxVehicleComputeSprungMasses(wheels.Count(), offsets, centerOfMassOffset.p, _actor->getMass(), 1, sprungMasses);
const float mass = _actor->getMass();
PxVehicleComputeSprungMasses(wheels.Count(), offsets, centerOfMassOffset.p, mass, 1, sprungMasses);
PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(wheels.Count());
for (int32 i = 0; i < wheels.Count(); i++)
{
@@ -300,7 +301,6 @@ void WheeledVehicle::Setup()
auto& data = _wheelsData[i];
data.Collider = wheel.Collider;
data.LocalOrientation = wheel.Collider->GetLocalOrientation();
data.ChildrenPoses.Resize(0);
PxVehicleSuspensionData suspensionData;
const float suspensionFrequency = 7.0f;
@@ -324,7 +324,7 @@ void WheeledVehicle::Setup()
wheelData.mMaxHandBrakeTorque = M2ToCm2(wheel.MaxHandBrakeTorque);
PxVec3 centreOffset = centerOfMassOffset.transformInv(offsets[i]);
PxVec3 forceAppPointOffset(centreOffset.z, centreOffset.y + wheel.SuspensionForceOffset, centreOffset.z);
PxVec3 forceAppPointOffset(centreOffset.z, wheel.SuspensionForceOffset, centreOffset.z);
wheelsSimData->setTireData(i, tire);
wheelsSimData->setWheelData(i, wheelData);
@@ -333,6 +333,8 @@ void WheeledVehicle::Setup()
wheelsSimData->setWheelCentreOffset(i, centreOffset);
wheelsSimData->setSuspForceAppPointOffset(i, forceAppPointOffset);
wheelsSimData->setTireForceAppPointOffset(i, forceAppPointOffset);
wheelsSimData->setSubStepCount(4.0f * 100.0f, 3, 1);
wheelsSimData->setMinLongSlipDenominator(4.0f * 100.0f);
PxShape* wheelShape = wheel.Collider->GetPxShape();
if (wheel.Collider->IsActiveInHierarchy())
@@ -345,6 +347,9 @@ void WheeledVehicle::Setup()
wheelShape->setQueryFilterData(filter);
wheelShape->setSimulationFilterData(filter);
wheelsSimData->setSceneQueryFilterData(i, filter);
// Remove wheels from the simulation (suspension force hold the vehicle)
wheelShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
}
else
{
@@ -520,12 +525,16 @@ void WheeledVehicle::DrawPhysicsDebug(RenderView& view)
auto& wheel = _wheels[wheelIndex];
if (wheel.Collider && wheel.Collider->GetParent() == this && !wheel.Collider->GetIsTrigger())
{
const Vector3 basePos = wheel.Collider->GetPosition();
const Vector3 currentPos = basePos + Vector3(0, data.State.SuspensionOffset, 0);
const Vector3 currentPos = wheel.Collider->GetPosition();
const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0);
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, true);
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, true);
DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, true);
DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.8f, 0, true);
if (!data.State.IsInAir)
{
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.TireContactPoint, 5.0f), Color::Green, 0, true);
}
}
}
}
@@ -546,12 +555,22 @@ void WheeledVehicle::OnDebugDrawSelected()
auto& wheel = _wheels[wheelIndex];
if (wheel.Collider && wheel.Collider->GetParent() == this && !wheel.Collider->GetIsTrigger())
{
const Vector3 basePos = wheel.Collider->GetPosition();
const Vector3 currentPos = basePos + Vector3(0, data.State.SuspensionOffset, 0);
const Vector3 currentPos = wheel.Collider->GetPosition();
const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0);
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, false);
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, false);
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(P2C(_actor->getGlobalPose().transform(wheel.Collider->GetPxShape()->getLocalPose()).p), wheel.Radius * 0.11f), Color::OrangeRed * 0.8f, 0, false);
DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, false);
DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.4f, 0, false);
if (!data.State.SuspensionTraceStart.IsZero())
{
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.SuspensionTraceStart, 5.0f), Color::AliceBlue, 0, false);
DEBUG_DRAW_LINE(data.State.SuspensionTraceStart, data.State.SuspensionTraceEnd, data.State.IsInAir ? Color::Red : Color::Green, 0, false);
}
if (!data.State.IsInAir)
{
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.TireContactPoint, 5.0f), Color::Green, 0, false);
}
}
}

View File

@@ -172,67 +172,67 @@ public:
/// <summary>
/// Wheel placement type.
/// </summary>
API_FIELD() WheelTypes Type = WheelTypes::FrontLeft;
API_FIELD(Attributes="EditorOrder(0)") WheelTypes Type = WheelTypes::FrontLeft;
/// <summary>
/// Combined mass of the wheel and the tire in kg. Typically, a wheel has mass between 20Kg and 80Kg but can be lower and higher depending on the vehicle.
/// </summary>
API_FIELD() float Mass = 20.0f;
API_FIELD(Attributes="EditorOrder(1)") float Mass = 20.0f;
/// <summary>
/// Distance in metres between the center of the wheel and the outside rim of the tire. It is important that the value of the radius closely matches the radius of the render mesh of the wheel. Any mismatch will result in the wheels either hovering above the ground or intersecting the ground.
/// </summary>
API_FIELD() float Radius = 50.0f;
API_FIELD(Attributes="EditorOrder(2)") float Radius = 50.0f;
/// <summary>
/// Full width of the wheel in metres. This parameter has no bearing on the handling but is a very useful parameter to have when trying to render debug data relating to the wheel/tire/suspension.
/// </summary>
API_FIELD() float Width = 20.0f;
API_FIELD(Attributes="EditorOrder(3)") float Width = 20.0f;
/// <summary>
/// Max steer angle that can be achieved by the wheel (in degrees).
/// </summary>
API_FIELD(Attributes="Limit(0)") float MaxSteerAngle = 0.0f;
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Steering\"), EditorOrder(10)") float MaxSteerAngle = 0.0f;
/// <summary>
/// Damping rate applied to wheel. Specified in kilograms metres-squared per second (kg m^2 s^-1).
/// </summary>
API_FIELD(Attributes="Limit(0)") float DampingRate = 0.25f;
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Steering\"), EditorOrder(11)") float DampingRate = 0.25f;
/// <summary>
/// Max brake torque that can be applied to wheel. Specified in kilograms metres-squared per second-squared (kg m^2 s^-2)
/// </summary>
API_FIELD(Attributes="Limit(0)") float MaxBrakeTorque = 1500.0f;
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Steering\"), EditorOrder(12)") float MaxBrakeTorque = 1500.0f;
/// <summary>
/// Max handbrake torque that can be applied to wheel. Specified in kilograms metres-squared per second-squared (kg m^2 s^-2)
/// </summary>
API_FIELD(Attributes="Limit(0)") float MaxHandBrakeTorque = 2000.0f;
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Steering\"), EditorOrder(13)") float MaxHandBrakeTorque = 2000.0f;
/// <summary>
/// Collider that represents the wheel shape and it's placement. Has to be attached as a child to the vehicle. Triangle mesh collider is not supported (use convex mesh or basic shapes).
/// </summary>
API_FIELD() ScriptingObjectReference<Collider> Collider;
API_FIELD(Attributes="EditorOrder(4)") ScriptingObjectReference<Collider> Collider;
/// <summary>
/// Spring damper rate of suspension unit.
/// </summary>
API_FIELD(Attributes="Limit(0)") float SuspensionDampingRate = 1.0f;
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Suspension\"), EditorOrder(20)") float SuspensionDampingRate = 1.0f;
/// <summary>
/// The maximum offset for the suspension that wheel can go above resting location.
/// </summary>
API_FIELD(Attributes="Limit(0)") float SuspensionMaxRaise = 10.0f;
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Suspension\"), EditorOrder(21)") float SuspensionMaxRaise = 10.0f;
/// <summary>
/// The maximum offset for the suspension that wheel can go below resting location.
/// </summary>
API_FIELD(Attributes="Limit(0)") float SuspensionMaxDrop = 10.0f;
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Suspension\"), EditorOrder(22)") float SuspensionMaxDrop = 10.0f;
/// <summary>
/// The vertical offset from where suspension forces are applied.
/// </summary>
API_FIELD() float SuspensionForceOffset = 0.0f;
API_FIELD(Attributes="EditorDisplay(\"Suspension\"), EditorOrder(23)") float SuspensionForceOffset = 0.0f;
};
/// <summary>
@@ -281,6 +281,18 @@ public:
/// The compression of the suspension spring. Offsets the wheel location.
/// </summary>
API_FIELD() float SuspensionOffset = 0.0f;
#if USE_EDITOR
/// <summary>
/// The start location of the suspension raycast start (Editor only for debugging).
/// </summary>
API_FIELD() Vector3 SuspensionTraceStart = Vector3::Zero;
/// <summary>
/// The start location of the suspension raycast end (Editor only for debugging).
/// </summary>
API_FIELD() Vector3 SuspensionTraceEnd = Vector3::Zero;
#endif
};
private:
@@ -290,12 +302,6 @@ private:
Collider* Collider;
Quaternion LocalOrientation;
WheelState State;
struct ChildPose
{
Actor* Child;
Vector3 Pose;
};
Array<ChildPose, InlinedAllocation<4>> ChildrenPoses;
};
void* _drive = nullptr;

View File

@@ -789,8 +789,8 @@ void Physics::CollectResults()
{
if (WheelRaycastBatchQuery)
WheelRaycastBatchQuery->release();
WheelQueryResults.Resize(wheelsCount);
WheelQueryResults.Resize(WheelQueryResults.Capacity());
WheelQueryResults.Resize(wheelsCount, false);
WheelHitResults.Resize(wheelsCount, false);
PxBatchQueryDesc desc(wheelsCount, 0, 0);
desc.queryMemory.userRaycastResultBuffer = WheelQueryResults.Get();
desc.queryMemory.userRaycastTouchBuffer = WheelHitResults.Get();
@@ -857,23 +857,21 @@ void Physics::CollectResults()
state.SteerAngle = RadiansToDegrees * perWheel.steerAngle;
state.RotationAngle = -RadiansToDegrees * drive->mWheelsDynData.getWheelRotationAngle(j);
state.SuspensionOffset = perWheel.suspJounce;
#if USE_EDITOR
state.SuspensionTraceStart = P2C(perWheel.suspLineStart);
state.SuspensionTraceEnd = P2C(perWheel.suspLineStart + perWheel.suspLineDir * perWheel.suspLineLength);
#endif
// Rotate wheel
wheelData.Collider->SetLocalOrientation(Quaternion::Euler(0, state.SteerAngle, state.RotationAngle) * wheelData.LocalOrientation);
if (!wheelData.Collider)
continue;
auto shape = wheelData.Collider->GetPxShape();
// Apply suspension offset (cannot move collider because it breaks driving so move it's children but preserve the initial pose)
for (auto child : wheelData.Collider->Children)
{
int32 poseIndex = 0;
for (; poseIndex < wheelData.ChildrenPoses.Count(); poseIndex++)
{
if (wheelData.ChildrenPoses[poseIndex].Child == child)
break;
}
if (poseIndex == wheelData.ChildrenPoses.Count())
wheelData.ChildrenPoses.Add({ child, child->GetLocalPosition() });
child->SetPosition(wheelData.Collider->GetTransform().LocalToWorld(wheelData.ChildrenPoses[poseIndex].Pose) + Vector3(0, perWheel.suspJounce, 0));
}
// Update wheel collider transformation
auto localPose = shape->getLocalPose();
Transform t = wheelData.Collider->GetLocalTransform();
t.Orientation = Quaternion::Euler(0, state.SteerAngle, state.RotationAngle) * wheelData.LocalOrientation;
t.Translation = P2C(localPose.p) / wheelVehicle->GetScale() - t.Orientation * wheelData.Collider->GetCenter();
wheelData.Collider->SetLocalTransform(t);
}
}
}