feat(physics): wire physx sdk into build
This commit is contained in:
160
engine/third_party/physx/source/physxvehicle/src/commands/VhCommandHelpers.cpp
vendored
Normal file
160
engine/third_party/physx/source/physxvehicle/src/commands/VhCommandHelpers.cpp
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/commands/PxVehicleCommandParams.h"
|
||||
#include "vehicle2/commands/PxVehicleCommandHelpers.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
static float interpolate(const PxReal* speedVals, const PxReal* responseVals, const PxU16 nb, const PxReal speed)
|
||||
{
|
||||
if (1 == nb)
|
||||
{
|
||||
return responseVals[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
const PxReal smallestSpeed = speedVals[0];
|
||||
const PxReal largestSpeed = speedVals[nb - 1];
|
||||
if (smallestSpeed >= speed)
|
||||
{
|
||||
return responseVals[0];
|
||||
}
|
||||
else if (largestSpeed <= speed)
|
||||
{
|
||||
return responseVals[nb - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
PxU16 speedId = 0;
|
||||
while ((speedVals[speedId] < speed) && (speedId < nb))
|
||||
speedId++;
|
||||
|
||||
// Make sure that we stay in range.
|
||||
PxU16 speedLowerId = speedId - 1;
|
||||
PxU16 speeddUpperId = speedId;
|
||||
if (nb == speedId)
|
||||
speeddUpperId = nb - 1;
|
||||
if (0 == speedId)
|
||||
speedLowerId = 0;
|
||||
|
||||
return responseVals[speedLowerId] + (speed - speedVals[speedLowerId]) * (responseVals[speeddUpperId] - responseVals[speedLowerId]) / (speedVals[speeddUpperId] - speedVals[speedLowerId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PxReal PxVehicleNonLinearResponseCompute
|
||||
(const PxReal commandValue, const PxReal speed, const PxU32 wheelId, const PxVehicleCommandResponseParams& responseParams)
|
||||
{
|
||||
const PxU16 nbResponsesAtSpeeds = responseParams.nonlinearResponse.nbSpeedResponses;
|
||||
if (0 == nbResponsesAtSpeeds)
|
||||
{
|
||||
//Empty response table.
|
||||
//Use linear interpolation.
|
||||
return PxVehicleLinearResponseCompute(commandValue, wheelId, responseParams);
|
||||
}
|
||||
|
||||
const PxReal* commandValues = responseParams.nonlinearResponse.commandValues;
|
||||
const PxU16* speedResponsesPerCommandValue = responseParams.nonlinearResponse.speedResponsesPerCommandValue;
|
||||
const PxU16* nbSpeedResponsesPerCommandValue = responseParams.nonlinearResponse.nbSpeedResponsesPerCommandValue;
|
||||
const PxU16 nbCommandValues = responseParams.nonlinearResponse.nbCommandValues;
|
||||
const PxReal* speedResponses = responseParams.nonlinearResponse.speedResponses;
|
||||
|
||||
PxReal normalisedResponse = 0.0f;
|
||||
if ((1 == nbCommandValues) || (commandValues[0] >= commandValue))
|
||||
{
|
||||
//Input command value less than the smallest value in the response table or
|
||||
//there is just a single command value in the response table.
|
||||
//No need to interpolate response of two command values.
|
||||
const PxReal* speeds = speedResponses + 2*speedResponsesPerCommandValue[0];
|
||||
const PxReal* responseValues = speeds + nbSpeedResponsesPerCommandValue[0];
|
||||
const PxU16 nb = nbSpeedResponsesPerCommandValue[0];
|
||||
normalisedResponse = interpolate(speeds, responseValues, nb, speed);
|
||||
}
|
||||
else if (commandValues[nbCommandValues - 1] <= commandValue)
|
||||
{
|
||||
//Input command value greater than the largest value in the response table.
|
||||
//No need to interpolate response of two command values.
|
||||
const PxReal* speeds = speedResponses + 2*speedResponsesPerCommandValue[nbCommandValues - 1];
|
||||
const PxReal* responseValues = speeds + nbSpeedResponsesPerCommandValue[nbCommandValues - 1];
|
||||
const PxU16 nb = nbSpeedResponsesPerCommandValue[nbCommandValues - 1];
|
||||
normalisedResponse = interpolate(speeds, responseValues, nb, speed);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the id of the command value that is immediately above the input command
|
||||
PxU16 commandId = 0;
|
||||
while ((commandValues[commandId] < commandValue) && (commandId < nbCommandValues))
|
||||
{
|
||||
commandId++;
|
||||
}
|
||||
|
||||
// Make sure that we stay in range.
|
||||
PxU16 commandLowerId = commandId - 1;
|
||||
PxU16 commandUpperId = commandId;
|
||||
if (nbCommandValues == commandId)
|
||||
commandUpperId = nbCommandValues - 1;
|
||||
if (0 == commandId)
|
||||
commandLowerId = 0;
|
||||
|
||||
if (commandUpperId != commandLowerId)
|
||||
{
|
||||
float zLower;
|
||||
{
|
||||
const PxReal* speeds = speedResponses + 2*speedResponsesPerCommandValue[commandLowerId];
|
||||
const PxReal* responseValues = speeds + nbSpeedResponsesPerCommandValue[commandLowerId];
|
||||
const PxU16 nb = nbSpeedResponsesPerCommandValue[commandLowerId];
|
||||
zLower = interpolate(speeds, responseValues, nb, speed);
|
||||
}
|
||||
float zUpper;
|
||||
{
|
||||
const PxReal* speeds = speedResponses + 2*speedResponsesPerCommandValue[commandUpperId];
|
||||
const PxReal* responseValues = speeds + nbSpeedResponsesPerCommandValue[commandUpperId];
|
||||
const PxU16 nb = nbSpeedResponsesPerCommandValue[commandUpperId];
|
||||
zUpper = interpolate(speeds, responseValues, nb, speed);
|
||||
}
|
||||
const PxReal commandUpper = commandValues[commandUpperId];
|
||||
const PxReal commandLower = commandValues[commandLowerId];
|
||||
normalisedResponse = zLower + (commandValue - commandLower) * (zUpper - zLower) / (commandUpper - commandLower);
|
||||
}
|
||||
else
|
||||
{
|
||||
const PxReal* speeds = speedResponses + 2*speedResponsesPerCommandValue[commandUpperId];
|
||||
const PxReal* responseValues = speeds + nbSpeedResponsesPerCommandValue[commandUpperId];
|
||||
const PxU16 nb = nbSpeedResponsesPerCommandValue[commandUpperId];
|
||||
normalisedResponse = interpolate(speeds, responseValues, nb, speed);
|
||||
}
|
||||
}
|
||||
|
||||
return PxVehicleLinearResponseCompute(normalisedResponse, wheelId, responseParams);
|
||||
}
|
||||
|
||||
} // namespace vehicle2
|
||||
} // namespace physx
|
||||
976
engine/third_party/physx/source/physxvehicle/src/drivetrain/VhDrivetrainFunctions.cpp
vendored
Normal file
976
engine/third_party/physx/source/physxvehicle/src/drivetrain/VhDrivetrainFunctions.cpp
vendored
Normal file
@@ -0,0 +1,976 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxMemory.h"
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
#include "vehicle2/PxVehicleFunctions.h"
|
||||
#include "vehicle2/PxVehicleMaths.h"
|
||||
|
||||
#include "vehicle2/commands/PxVehicleCommandHelpers.h"
|
||||
|
||||
#include "vehicle2/drivetrain/PxVehicleDrivetrainFunctions.h"
|
||||
#include "vehicle2/drivetrain/PxVehicleDrivetrainParams.h"
|
||||
#include "vehicle2/drivetrain/PxVehicleDrivetrainStates.h"
|
||||
#include "vehicle2/drivetrain/PxVehicleDrivetrainHelpers.h"
|
||||
|
||||
#include "vehicle2/tire/PxVehicleTireStates.h"
|
||||
|
||||
#include "vehicle2/wheel/PxVehicleWheelParams.h"
|
||||
#include "vehicle2/wheel/PxVehicleWheelStates.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
void PxVehicleDirectDriveThrottleCommandResponseUpdate
|
||||
(const PxReal throttle, const PxVehicleDirectDriveTransmissionCommandState& transmissionCommands, const PxReal longitudinalSpeed,
|
||||
const PxU32 wheelId, const PxVehicleDirectDriveThrottleCommandResponseParams& responseParams,
|
||||
PxReal& throttleResponse)
|
||||
{
|
||||
//The gearing decides how we will multiply the response.
|
||||
PxF32 gearMultiplier = 0.0f;
|
||||
switch (transmissionCommands.gear)
|
||||
{
|
||||
case PxVehicleDirectDriveTransmissionCommandState::eREVERSE:
|
||||
gearMultiplier = -1.0f;
|
||||
break;
|
||||
case PxVehicleDirectDriveTransmissionCommandState::eNEUTRAL:
|
||||
gearMultiplier = 0.0f;
|
||||
break;
|
||||
case PxVehicleDirectDriveTransmissionCommandState::eFORWARD:
|
||||
gearMultiplier = 1.0f;
|
||||
break;
|
||||
}
|
||||
throttleResponse = gearMultiplier * PxVehicleNonLinearResponseCompute(throttle, longitudinalSpeed, wheelId, responseParams);
|
||||
}
|
||||
|
||||
void PxVehicleDirectDriveActuationStateUpdate
|
||||
(const PxReal brakeTorque, const PxReal driveTorque,
|
||||
PxVehicleWheelActuationState& actState)
|
||||
{
|
||||
PxMemZero(&actState, sizeof(PxVehicleWheelActuationState));
|
||||
actState.isBrakeApplied = (brakeTorque != 0.0f);
|
||||
actState.isDriveApplied = (driveTorque != 0.0f);
|
||||
}
|
||||
|
||||
void PxVehicleDirectDriveUpdate
|
||||
(const PxVehicleWheelParams& whlParams,
|
||||
const PxVehicleWheelActuationState& actState,
|
||||
const PxReal brkTorque, const PxReal drvTorque, const PxVehicleTireForce& trForce,
|
||||
const PxF32 dt,
|
||||
PxVehicleWheelRigidBody1dState& whlState)
|
||||
{
|
||||
|
||||
//w(t+dt) = w(t) + (1/inertia)*(brakeTorque + driveTorque + tireTorque)*dt - (1/inertia)*damping*w(t)*dt ) (1)
|
||||
//Apply implicit trick and rearrange.
|
||||
//w(t+dt)[1 + (1/inertia)*damping*dt] = w(t) + (1/inertia)*(brakeTorque + driveTorque + tireTorque)*dt (2)
|
||||
const PxF32 wheelRotSpeed = whlState.rotationSpeed;
|
||||
const PxF32 dtOverMOI = dt/whlParams.moi;
|
||||
const PxF32 tireTorque = trForce.wheelTorque;
|
||||
const PxF32 brakeTorque = -brkTorque*PxVehicleComputeSign(wheelRotSpeed);
|
||||
const PxF32 driveTorque = drvTorque;
|
||||
const PxF32 wheelDampingRate = whlParams.dampingRate;
|
||||
|
||||
//Integrate the wheel rotation speed.
|
||||
const PxF32 newRotSpeedNoBrakelock = (wheelRotSpeed + dtOverMOI*(tireTorque + driveTorque + brakeTorque)) / (1.0f + wheelDampingRate*dtOverMOI);
|
||||
//If the brake is applied and the sign flipped then lock the brake.
|
||||
const bool isBrakeApplied = actState.isBrakeApplied;
|
||||
const PxF32 newRotSpeedWithBrakelock = (isBrakeApplied && ((wheelRotSpeed*newRotSpeedNoBrakelock) <= 0)) ? 0.0f : newRotSpeedNoBrakelock;
|
||||
|
||||
whlState.rotationSpeed = newRotSpeedWithBrakelock;
|
||||
}
|
||||
|
||||
void PxVehicleDifferentialStateUpdate
|
||||
(const PxVehicleFourWheelDriveDifferentialLegacyParams& diffParams,
|
||||
const PxVehicleArrayData<const PxVehicleWheelRigidBody1dState>& wheelStates,
|
||||
PxVehicleDifferentialState& diffState)
|
||||
{
|
||||
diffState.setToDefault();
|
||||
|
||||
//4 wheels are connected.
|
||||
diffState.connectedWheels[0] = diffParams.frontWheelIds[0];
|
||||
diffState.connectedWheels[1] = diffParams.frontWheelIds[1];
|
||||
diffState.connectedWheels[2] = diffParams.rearWheelIds[0];
|
||||
diffState.connectedWheels[3] = diffParams.rearWheelIds[1];
|
||||
diffState.nbConnectedWheels = 4;
|
||||
|
||||
//Compute the contributions to average speed and ratios of available torque.
|
||||
PxVehicleLegacyDifferentialWheelSpeedContributionsCompute(diffParams, PxVehicleLimits::eMAX_NB_WHEELS,
|
||||
diffState.aveWheelSpeedContributionAllWheels);
|
||||
|
||||
PxVehicleLegacyDifferentialTorqueRatiosCompute(diffParams, wheelStates, PxVehicleLimits::eMAX_NB_WHEELS,
|
||||
diffState.torqueRatiosAllWheels);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxF32 computeTargetRatio
|
||||
(const PxF32 target, const PxF32 dt, const PxF32 strength, const PxF32 ratio)
|
||||
{
|
||||
const PxF32 targ = (PX_VEHICLE_FOUR_WHEEL_DIFFERENTIAL_MAXIMUM_STRENGTH == strength) ? target : PxMax(target, ratio - strength * dt);
|
||||
return targ;
|
||||
}
|
||||
|
||||
void PxVehicleDifferentialStateUpdate
|
||||
(const PxVehicleAxleDescription& axleDescription, const PxVehicleFourWheelDriveDifferentialParams& diffParams,
|
||||
const PxVehicleArrayData<const PxVehicleWheelRigidBody1dState>& wheelStates,
|
||||
const PxReal dt,
|
||||
PxVehicleDifferentialState& diffState, PxVehicleWheelConstraintGroupState& wheelConstraintGroupState)
|
||||
{
|
||||
diffState.setToDefault();
|
||||
wheelConstraintGroupState.setToDefault();
|
||||
|
||||
PxU32 nbConnectedWheels = 0;
|
||||
for (PxU32 i = 0; i < axleDescription.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = axleDescription.wheelIdsInAxleOrder[i];
|
||||
if (diffParams.torqueRatios[wheelId] != 0.0f)
|
||||
{
|
||||
diffState.connectedWheels[nbConnectedWheels] = wheelId;
|
||||
diffState.aveWheelSpeedContributionAllWheels[wheelId] = diffParams.aveWheelSpeedRatios[wheelId];
|
||||
diffState.torqueRatiosAllWheels[wheelId] = diffParams.aveWheelSpeedRatios[wheelId];
|
||||
nbConnectedWheels++;
|
||||
}
|
||||
}
|
||||
diffState.nbConnectedWheels = nbConnectedWheels;
|
||||
|
||||
if (0.0f == diffParams.frontBias && 0.0f == diffParams.rearBias && 0.0f == diffParams.centerBias)
|
||||
return;
|
||||
|
||||
if (0.0f == diffParams.rate)
|
||||
return;
|
||||
|
||||
bool frontBiasBreached = false;
|
||||
PxF32 Rf = 0.0f;
|
||||
PxF32 Tf = 0.0f;
|
||||
{
|
||||
const PxF32 bias = diffParams.frontBias;
|
||||
if (bias >= 1.0f)
|
||||
{
|
||||
const PxU32 wheel0 = diffParams.frontWheelIds[0];
|
||||
const PxU32 wheel1 = diffParams.frontWheelIds[1];
|
||||
const PxReal w0 = wheelStates[wheel0].rotationSpeed;
|
||||
const PxReal w1 = wheelStates[wheel1].rotationSpeed;
|
||||
const PxReal aw0 = PxAbs(w0);
|
||||
const PxReal aw1 = PxAbs(w1);
|
||||
const PxReal sw0 = PxVehicleComputeSign(w0);
|
||||
const PxReal sw1 = PxVehicleComputeSign(w1);
|
||||
if ((w0 != 0.0f) && (sw0 == sw1))
|
||||
{
|
||||
const PxF32 ratio = PxMax(aw0, aw1) / PxMin(aw0, aw1);
|
||||
frontBiasBreached = (ratio > bias);
|
||||
//const PxF32 target = diffParams.frontTarget + (1.0f - diffParams.strength) * (ratio - diffParams.frontTarget);
|
||||
const PxF32 target = computeTargetRatio(diffParams.frontTarget, dt, diffParams.rate, ratio);
|
||||
Tf = (aw0 > aw1) ? 1.0f / target : target;
|
||||
Rf = aw1 / aw0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool rearBiasBreached = false;
|
||||
PxF32 Rr = 0.0f;
|
||||
PxF32 Tr = 0.0f;
|
||||
{
|
||||
const PxF32 bias = diffParams.rearBias;
|
||||
if (bias >= 1.0f)
|
||||
{
|
||||
const PxU32 wheel2 = diffParams.rearWheelIds[0];
|
||||
const PxU32 wheel3 = diffParams.rearWheelIds[1];
|
||||
const PxReal w2 = wheelStates[wheel2].rotationSpeed;
|
||||
const PxReal w3 = wheelStates[wheel3].rotationSpeed;
|
||||
const PxReal aw2 = PxAbs(w2);
|
||||
const PxReal aw3 = PxAbs(w3);
|
||||
const PxReal sw2 = PxVehicleComputeSign(w2);
|
||||
const PxReal sw3 = PxVehicleComputeSign(w3);
|
||||
if ((w2 != 0.0f) && (sw2 == sw3))
|
||||
{
|
||||
const PxF32 ratio = PxMax(aw2, aw3) / PxMin(aw2, aw3);
|
||||
rearBiasBreached = (ratio > bias);
|
||||
//const PxF32 target = diffParams.rearTarget + (1.0f - diffParams.strength) * (ratio - diffParams.rearTarget);
|
||||
const PxF32 target = computeTargetRatio(diffParams.rearTarget, dt, diffParams.rate, ratio);
|
||||
Tr = (aw2 > aw3) ? 1.0f / target : target;
|
||||
Rr = aw3 / aw2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool centreBiasBrached = false;
|
||||
//PxF32 Rc = 0.0f;
|
||||
PxF32 Tc = 0.0f;
|
||||
{
|
||||
const PxF32 bias = diffParams.centerBias;
|
||||
if(bias >= 1.0f)
|
||||
{
|
||||
const PxU32 wheel0 = diffParams.frontWheelIds[0];
|
||||
const PxU32 wheel1 = diffParams.frontWheelIds[1];
|
||||
const PxU32 wheel2 = diffParams.rearWheelIds[0];
|
||||
const PxU32 wheel3 = diffParams.rearWheelIds[1];
|
||||
const PxReal w0 = wheelStates[wheel0].rotationSpeed;
|
||||
const PxReal w1 = wheelStates[wheel1].rotationSpeed;
|
||||
const PxReal w2 = wheelStates[wheel2].rotationSpeed;
|
||||
const PxReal w3 = wheelStates[wheel3].rotationSpeed;
|
||||
const PxReal aw0 = PxAbs(w0);
|
||||
const PxReal aw1 = PxAbs(w1);
|
||||
const PxReal aw2 = PxAbs(w2);
|
||||
const PxReal aw3 = PxAbs(w3);
|
||||
const PxReal sw0 = PxVehicleComputeSign(w0);
|
||||
const PxReal sw1 = PxVehicleComputeSign(w1);
|
||||
const PxReal sw2 = PxVehicleComputeSign(w2);
|
||||
const PxReal sw3 = PxVehicleComputeSign(w3);
|
||||
if ((w0 != 0.0f) && (sw0 == sw1) && (sw0 == sw2) && (sw0 == sw3))
|
||||
{
|
||||
const PxF32 ratio = PxMax(aw0 + aw1, aw2 + aw3) / PxMin(aw0 + aw1, aw2 + aw3);
|
||||
centreBiasBrached = (ratio > bias);
|
||||
//const PxF32 target = diffParams.centerTarget + (1.0f - diffParams.strength) * (ratio - diffParams.centerTarget);
|
||||
const PxF32 target = computeTargetRatio(diffParams.centerTarget, dt, diffParams.rate, ratio);
|
||||
Tc = ((aw0 + aw1) > (aw2 + aw3)) ? 1.0f / target : target;
|
||||
//Rc = (aw2 + aw3) / (aw0 + aw1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (centreBiasBrached)
|
||||
{
|
||||
PxF32 f = 0.0f;
|
||||
PxF32 r = 0.0f;
|
||||
if (frontBiasBreached && rearBiasBreached)
|
||||
{
|
||||
f = Tf;
|
||||
r = Tr;
|
||||
}
|
||||
else if (frontBiasBreached)
|
||||
{
|
||||
f = Tf;
|
||||
r = Rr;
|
||||
}
|
||||
else if (rearBiasBreached)
|
||||
{
|
||||
f = Rf;
|
||||
r = Tr;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = Rf;
|
||||
r = Rr;
|
||||
}
|
||||
|
||||
const PxU32 wheel0 = diffParams.frontWheelIds[0];
|
||||
const PxU32 wheel1 = diffParams.frontWheelIds[1];
|
||||
const PxU32 wheel2 = diffParams.rearWheelIds[0];
|
||||
const PxU32 wheel3 = diffParams.rearWheelIds[1];
|
||||
const PxU32 wheelIds[4] = { wheel0, wheel1, wheel2, wheel3 };
|
||||
const PxF32 constraintMultipliers[4] = { 1.0f, f, Tc*(1 + f) / (1 + r), r*Tc*(1 + f) / (1 + r) };
|
||||
wheelConstraintGroupState.addConstraintGroup(4, wheelIds, constraintMultipliers);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (frontBiasBreached)
|
||||
{
|
||||
const PxU32* wheelIds = diffParams.frontWheelIds;
|
||||
const PxF32 constraintMultipliers[2] = { 1.0f, Tf };
|
||||
wheelConstraintGroupState.addConstraintGroup(2, wheelIds, constraintMultipliers);
|
||||
}
|
||||
|
||||
if (rearBiasBreached)
|
||||
{
|
||||
const PxU32* wheelIds = diffParams.rearWheelIds;
|
||||
const PxF32 constraintMultipliers[2] = { 1.0f, Tr };
|
||||
wheelConstraintGroupState.addConstraintGroup(2, wheelIds, constraintMultipliers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleDifferentialStateUpdate
|
||||
(const PxVehicleAxleDescription& axleDescription, const PxVehicleMultiWheelDriveDifferentialParams& diffParams,
|
||||
PxVehicleDifferentialState& diffState)
|
||||
{
|
||||
diffState.setToDefault();
|
||||
|
||||
PxU32 nbConnectedWheels = 0;
|
||||
for (PxU32 i = 0; i < axleDescription.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = axleDescription.wheelIdsInAxleOrder[i];
|
||||
if (diffParams.torqueRatios[wheelId] != 0.0f)
|
||||
{
|
||||
diffState.connectedWheels[nbConnectedWheels] = wheelId;
|
||||
diffState.aveWheelSpeedContributionAllWheels[wheelId] = diffParams.aveWheelSpeedRatios[wheelId];
|
||||
diffState.torqueRatiosAllWheels[wheelId] = diffParams.aveWheelSpeedRatios[wheelId];
|
||||
nbConnectedWheels++;
|
||||
}
|
||||
}
|
||||
diffState.nbConnectedWheels = nbConnectedWheels;
|
||||
}
|
||||
|
||||
void PxVehicleDifferentialStateUpdate
|
||||
(const PxVehicleAxleDescription& axleDescription,
|
||||
const PxVehicleArrayData<const PxVehicleWheelParams>& wheelParams, const PxVehicleTankDriveDifferentialParams& diffParams,
|
||||
const PxReal thrust0, PxReal thrust1,
|
||||
PxVehicleDifferentialState& diffState, PxVehicleWheelConstraintGroupState& wheelConstraintGroupState)
|
||||
{
|
||||
diffState.setToDefault();
|
||||
wheelConstraintGroupState.setToDefault();
|
||||
|
||||
//Store the tank track id for each wheel.
|
||||
//Store the thrust controller id for each wheel.
|
||||
//Store 0xffffffff for wheels not in a tank track.
|
||||
PxU32 tankTrackIds[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxMemSet(tankTrackIds, 0xff, sizeof(tankTrackIds));
|
||||
PxU32 thrustControllerIds[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxMemSet(thrustControllerIds, 0xff, sizeof(thrustControllerIds));
|
||||
for (PxU32 i = 0; i < diffParams.getNbTracks(); i++)
|
||||
{
|
||||
const PxU32 thrustControllerIndex = diffParams.getThrustControllerIndex(i);
|
||||
for (PxU32 j = 0; j < diffParams.getNbWheelsInTrack(i); j++)
|
||||
{
|
||||
const PxU32 wheelId = diffParams.getWheelInTrack(j, i);
|
||||
tankTrackIds[wheelId] = i;
|
||||
thrustControllerIds[wheelId] = thrustControllerIndex;
|
||||
}
|
||||
}
|
||||
|
||||
//Treat every wheel connected to a tank track as connected to the differential but with zero torque split.
|
||||
//If a wheel is not connected to the differential but is connected to a tank track then we treat that as a connected wheel with
|
||||
//zero drive torque applied.
|
||||
//We do this because we need to treat these wheels as being coupled to other wheels in the linear equations that solve engine+wheels
|
||||
PxU32 nbConnectedWheels = 0;
|
||||
const PxReal thrusts[2] = { thrust0, thrust1 };
|
||||
for (PxU32 i = 0; i < axleDescription.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = axleDescription.wheelIdsInAxleOrder[i];
|
||||
const PxU32 tankTrackId = tankTrackIds[wheelId];
|
||||
if (diffParams.torqueRatios[wheelId] != 0.0f && 0xffffffff != tankTrackId)
|
||||
{
|
||||
//Wheel connected to diff and in a tank track.
|
||||
//Modify the default torque split using the relevant thrust.
|
||||
const PxU32 thrustId = thrustControllerIds[wheelId];
|
||||
const PxF32 torqueSplitMultiplier = thrusts[thrustId];
|
||||
diffState.aveWheelSpeedContributionAllWheels[wheelId] = diffParams.aveWheelSpeedRatios[wheelId];
|
||||
diffState.torqueRatiosAllWheels[wheelId] = diffParams.torqueRatios[wheelId] * torqueSplitMultiplier;
|
||||
diffState.connectedWheels[nbConnectedWheels] = wheelId;
|
||||
nbConnectedWheels++;
|
||||
}
|
||||
else if (diffParams.torqueRatios[wheelId] != 0.0f)
|
||||
{
|
||||
//Wheel connected to diff but not in a tank track.
|
||||
//Use the default torque split.
|
||||
diffState.aveWheelSpeedContributionAllWheels[wheelId] = diffParams.aveWheelSpeedRatios[wheelId];
|
||||
diffState.torqueRatiosAllWheels[wheelId] = diffParams.torqueRatios[wheelId];
|
||||
diffState.connectedWheels[nbConnectedWheels] = wheelId;
|
||||
nbConnectedWheels++;
|
||||
}
|
||||
else if (0xffffffff != tankTrackId)
|
||||
{
|
||||
//Wheel not connected to diff but is in a tank track.
|
||||
//Zero torque split.
|
||||
diffState.aveWheelSpeedContributionAllWheels[wheelId] = 0.0f;
|
||||
diffState.torqueRatiosAllWheels[wheelId] = 0.0f;
|
||||
diffState.connectedWheels[nbConnectedWheels] = wheelId;
|
||||
nbConnectedWheels++;
|
||||
}
|
||||
}
|
||||
diffState.nbConnectedWheels = nbConnectedWheels;
|
||||
|
||||
//Add each tank track as a constraint group.
|
||||
for (PxU32 i = 0; i < diffParams.getNbTracks(); i++)
|
||||
{
|
||||
const PxU32 nbWheelsInTrack = diffParams.getNbWheelsInTrack(i);
|
||||
if (nbWheelsInTrack >= 2)
|
||||
{
|
||||
const PxU32* wheelsInTrack = diffParams.wheelIdsInTrackOrder + diffParams.trackToWheelIds[i];
|
||||
|
||||
PxF32 multipliers[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
|
||||
const PxU32 wheelId0 = wheelsInTrack[0];
|
||||
const PxF32 wheelRadius0 = wheelParams[wheelId0].radius;
|
||||
|
||||
//for (PxU32 j = 0; j < 1; j++)
|
||||
{
|
||||
//j = 0 is a special case with multiplier = 1.0
|
||||
multipliers[0] = 1.0f;
|
||||
}
|
||||
for (PxU32 j = 1; j < nbWheelsInTrack; j++)
|
||||
{
|
||||
const PxU32 wheelIdJ = wheelsInTrack[j];
|
||||
const PxF32 wheelRadiusJ = wheelParams[wheelIdJ].radius;
|
||||
multipliers[j] = wheelRadius0 / wheelRadiusJ;
|
||||
}
|
||||
|
||||
wheelConstraintGroupState.addConstraintGroup(nbWheelsInTrack, wheelsInTrack, multipliers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleEngineDriveActuationStateUpdate
|
||||
(const PxVehicleAxleDescription& axleDescription,
|
||||
const PxVehicleGearboxParams& gearboxParams,
|
||||
const PxVehicleArrayData<const PxReal>& brakeResponseStates,
|
||||
const PxVehicleEngineDriveThrottleCommandResponseState& throttleResponseState,
|
||||
const PxVehicleGearboxState& gearboxState, const PxVehicleDifferentialState& diffState, const PxVehicleClutchCommandResponseState& clutchResponseState,
|
||||
PxVehicleArrayData<PxVehicleWheelActuationState>& actuationStates)
|
||||
{
|
||||
//Which wheels receive drive torque from the engine?
|
||||
const PxF32* diffTorqueRatios = diffState.torqueRatiosAllWheels;
|
||||
|
||||
//Work out the clutch strength.
|
||||
//If the cutch strength is zero then none of the wheels receive drive torque from the engine.
|
||||
const PxF32 K = PxVehicleClutchStrengthCompute(clutchResponseState, gearboxParams, gearboxState);
|
||||
|
||||
//Work out the applied throttle
|
||||
const PxF32 appliedThrottle = throttleResponseState.commandResponse;
|
||||
|
||||
//Ready to set the boolean actuation state that is used to compute the tire slips.
|
||||
//(Note: for a tire under drive or brake torque we compute the slip with a smaller denominator to accentuate the applied torque).
|
||||
//(Note: for a tire that is not under drive or brake torque we compute the sip with a larger denominator to smooth the vehicle slowing down).
|
||||
for(PxU32 i = 0; i < axleDescription.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = axleDescription.wheelIdsInAxleOrder[i];
|
||||
|
||||
//Reset the actuation states.
|
||||
PxVehicleWheelActuationState& actState = actuationStates[wheelId];
|
||||
PxMemZero(&actState, sizeof(PxVehicleWheelActuationState));
|
||||
|
||||
const PxF32 brakeTorque = brakeResponseStates[wheelId];
|
||||
const PxF32 diffTorqueRatio = diffTorqueRatios[wheelId];
|
||||
const bool isIntentionToAccelerate = (0.0f == brakeTorque) && (K != 0.0f) && (diffTorqueRatio != 0.0f) && (appliedThrottle != 0.0f);
|
||||
actState.isDriveApplied = isIntentionToAccelerate;
|
||||
actState.isBrakeApplied = (brakeTorque!= 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleGearCommandResponseUpdate
|
||||
(const PxU32 targetGearCommand,
|
||||
const PxVehicleGearboxParams& gearboxParams,
|
||||
PxVehicleGearboxState& gearboxState)
|
||||
{
|
||||
//Check that we're not halfway through a gear change and we need to execute a change of gear.
|
||||
//If we are halfway through a gear change then we cannot execute another until the first is complete.
|
||||
//Check that the command stays in a legal gear range.
|
||||
if ((gearboxState.currentGear == gearboxState.targetGear) && (targetGearCommand != gearboxState.currentGear) && (targetGearCommand < gearboxParams.nbRatios))
|
||||
{
|
||||
//We're not executing a gear change and we need to start one.
|
||||
//Start the gear change by
|
||||
//a)setting the target gear.
|
||||
//b)putting vehicle in neutral
|
||||
//c)set the switch time to PX_VEHICLE_GEAR_SWITCH_INITIATED to flag that we just started a gear change.
|
||||
gearboxState.currentGear = gearboxParams.neutralGear;
|
||||
gearboxState.targetGear = targetGearCommand;
|
||||
gearboxState.gearSwitchTime = PX_VEHICLE_GEAR_SWITCH_INITIATED;
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleAutoBoxUpdate
|
||||
(const PxVehicleEngineParams& engineParams, const PxVehicleGearboxParams& gearboxParams, const PxVehicleAutoboxParams& autoboxParams,
|
||||
const PxVehicleEngineState& engineState, const PxVehicleGearboxState& gearboxState,
|
||||
const PxReal dt,
|
||||
PxU32& targetGearCommand, PxVehicleAutoboxState& autoboxState,
|
||||
PxReal& throttle)
|
||||
{
|
||||
if(targetGearCommand != PxVehicleEngineDriveTransmissionCommandState::eAUTOMATIC_GEAR)
|
||||
{
|
||||
autoboxState.activeAutoboxGearShift = false;
|
||||
autoboxState.timeSinceLastShift = PX_VEHICLE_UNSPECIFIED_TIME_SINCE_LAST_SHIFT;
|
||||
return;
|
||||
}
|
||||
|
||||
//Current and target gear allow us to determine if a gear change is underway.
|
||||
const PxU32 currentGear = gearboxState.currentGear;
|
||||
const PxU32 targetGear = gearboxState.targetGear;
|
||||
|
||||
//Set to current target gear in case no gear change will be initiated.
|
||||
targetGearCommand = targetGear;
|
||||
|
||||
//If the autobox triggered a gear change and the gear change is complete then
|
||||
//reset the corresponding flag.
|
||||
if(autoboxState.activeAutoboxGearShift && (currentGear == targetGear))
|
||||
{
|
||||
autoboxState.activeAutoboxGearShift = false;
|
||||
}
|
||||
|
||||
//If the autobox triggered a gear change and the gear change is incomplete then
|
||||
//turn off the throttle pedal. This happens in autoboxes
|
||||
//to stop the driver revving the engine then damaging the
|
||||
//clutch when the clutch re-engages at the end of the gear change.
|
||||
if(autoboxState.activeAutoboxGearShift && (currentGear != targetGear))
|
||||
{
|
||||
throttle = 0.0f;
|
||||
}
|
||||
|
||||
//Only process the autobox if no gear change is underway and the time passed since
|
||||
//the last autobox gear change is greater than the autobox latency.
|
||||
if (targetGear == currentGear)
|
||||
{
|
||||
const PxF32 autoBoxSwitchTime = autoboxState.timeSinceLastShift;
|
||||
const PxF32 autoBoxLatencyTime = autoboxParams.latency;
|
||||
|
||||
if ((currentGear <= gearboxParams.neutralGear) && ((gearboxParams.neutralGear + 1) < gearboxParams.nbRatios))
|
||||
{
|
||||
// eAUTOMATIC_GEAR has been set while in neutral or one of the reverse gears
|
||||
// => switch to first
|
||||
targetGearCommand = gearboxParams.neutralGear + 1;
|
||||
throttle = 0.0f;
|
||||
autoboxState.timeSinceLastShift = 0.0f;
|
||||
autoboxState.activeAutoboxGearShift = true;
|
||||
}
|
||||
else if (autoBoxSwitchTime > autoBoxLatencyTime)
|
||||
{
|
||||
const PxF32 normalisedEngineOmega = engineState.rotationSpeed/engineParams.maxOmega;
|
||||
const PxU32 neutralGear = gearboxParams.neutralGear;
|
||||
const PxU32 nbGears = gearboxParams.nbRatios;
|
||||
const PxF32 upRatio = autoboxParams.upRatios[currentGear];
|
||||
const PxF32 downRatio = autoboxParams.downRatios[currentGear];
|
||||
|
||||
//If revs too high and not in reverse/neutral and there is a higher gear then switch up.
|
||||
//Note: never switch up from neutral to first
|
||||
//Note: never switch up from reverse to neutral
|
||||
//Note: never switch up from one reverse gear to another reverse gear.
|
||||
PX_ASSERT(currentGear > neutralGear);
|
||||
if ((normalisedEngineOmega > upRatio) && ((currentGear + 1) < nbGears))
|
||||
{
|
||||
targetGearCommand = currentGear + 1;
|
||||
throttle = 0.0f;
|
||||
autoboxState.timeSinceLastShift = 0.0f;
|
||||
autoboxState.activeAutoboxGearShift = true;
|
||||
}
|
||||
|
||||
//If revs too low and in gear higher than first then switch down.
|
||||
//Note: never switch from forward to neutral
|
||||
//Note: never switch from neutral to reverse
|
||||
//Note: never switch from reverse gear to reverse gear.
|
||||
if ((normalisedEngineOmega < downRatio) && (currentGear > (neutralGear + 1)))
|
||||
{
|
||||
targetGearCommand = currentGear - 1;
|
||||
throttle = 0.0f;
|
||||
autoboxState.timeSinceLastShift = 0.0f;
|
||||
autoboxState.activeAutoboxGearShift = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
autoboxState.timeSinceLastShift += dt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
autoboxState.timeSinceLastShift += dt;
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleGearboxUpdate(const PxVehicleGearboxParams& gearboxParams, const PxF32 dt, PxVehicleGearboxState& gearboxState)
|
||||
{
|
||||
if(gearboxState.targetGear != gearboxState.currentGear)
|
||||
{
|
||||
//If we just started a gear change then set the timer to zero.
|
||||
//This replicates legacy behaviour.
|
||||
if(gearboxState.gearSwitchTime == PX_VEHICLE_GEAR_SWITCH_INITIATED)
|
||||
gearboxState.gearSwitchTime = 0.0f;
|
||||
else
|
||||
gearboxState.gearSwitchTime += dt;
|
||||
|
||||
//If we've exceed the switch time then switch to the target gear
|
||||
//and reset the timer.
|
||||
if (gearboxState.gearSwitchTime > gearboxParams.switchTime)
|
||||
{
|
||||
gearboxState.currentGear = gearboxState.targetGear;
|
||||
gearboxState.gearSwitchTime = PX_VEHICLE_NO_GEAR_SWITCH_PENDING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void countConnectedWheelsNotInConstraintGroup
|
||||
(const PxU32* connectedWheelIds, const PxU32 nbConnectedWheelIds, const PxVehicleWheelConstraintGroupState& constraintGroups,
|
||||
PxU32 connectedWheelsNotInConstraintGroup[PxVehicleLimits::eMAX_NB_WHEELS], PxU32& nbConnectedWheelsNotInConstraintGroup)
|
||||
{
|
||||
//Record the constraint group for each wheel.
|
||||
//0xffffffff is reserved for a wheel not in a constraint group.
|
||||
PxU32 wheelConstraintGroupIds[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxMemSet(wheelConstraintGroupIds, 0xffffffff, sizeof(wheelConstraintGroupIds));
|
||||
for (PxU32 i = 0; i < constraintGroups.getNbConstraintGroups(); i++)
|
||||
{
|
||||
for (PxU32 j = 0; j < constraintGroups.getNbWheelsInConstraintGroup(i); j++)
|
||||
{
|
||||
const PxU32 wheelId = constraintGroups.getWheelInConstraintGroup(j, i);
|
||||
wheelConstraintGroupIds[wheelId] = i;
|
||||
}
|
||||
}
|
||||
|
||||
//Iterate over all connected wheels and count the number not in a group.
|
||||
for (PxU32 i = 0; i < nbConnectedWheelIds; i++)
|
||||
{
|
||||
const PxU32 wheelId = connectedWheelIds[i];
|
||||
const PxU32 constraintGroupId = wheelConstraintGroupIds[wheelId];
|
||||
if (0xffffffff == constraintGroupId)
|
||||
{
|
||||
connectedWheelsNotInConstraintGroup[nbConnectedWheelsNotInConstraintGroup] = wheelId;
|
||||
nbConnectedWheelsNotInConstraintGroup++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleEngineDrivetrainUpdate
|
||||
(const PxVehicleAxleDescription& axleDescription,
|
||||
const PxVehicleArrayData<const PxVehicleWheelParams>& wheelParams,
|
||||
const PxVehicleEngineParams& engineParams, const PxVehicleClutchParams& clutchParams, const PxVehicleGearboxParams& gearboxParams,
|
||||
const PxVehicleArrayData<const PxReal>& brakeResponseStates,
|
||||
const PxVehicleArrayData<const PxVehicleWheelActuationState>& actuationStates,
|
||||
const PxVehicleArrayData<const PxVehicleTireForce>& tireForces,
|
||||
const PxVehicleGearboxState& gearboxState,
|
||||
const PxVehicleEngineDriveThrottleCommandResponseState& throttleCommandResponseState, const PxVehicleClutchCommandResponseState& clutchCommandResponseState,
|
||||
const PxVehicleDifferentialState& diffState, const PxVehicleWheelConstraintGroupState* constraintGroupState,
|
||||
const PxReal DT,
|
||||
PxVehicleArrayData<PxVehicleWheelRigidBody1dState>& wheelRigidbody1dStates,
|
||||
PxVehicleEngineState& engineState,
|
||||
PxVehicleClutchSlipState& clutchState)
|
||||
{
|
||||
const PxF32 K = PxVehicleClutchStrengthCompute(clutchCommandResponseState, gearboxParams, gearboxState);
|
||||
const PxF32 G = PxVehicleGearRatioCompute(gearboxParams, gearboxState);
|
||||
const PxF32 engineDriveTorque = PxVehicleEngineDriveTorqueCompute(engineParams, engineState, throttleCommandResponseState);
|
||||
const PxF32 engineDampingRate = PxVehicleEngineDampingRateCompute(engineParams, gearboxParams, gearboxState, clutchCommandResponseState, throttleCommandResponseState);
|
||||
|
||||
//Arrange wheel parameters in they order they appear in the connected wheel list.
|
||||
const PxU32* connectedWheelIds = diffState.connectedWheels;
|
||||
const PxU32 nbConnectedWheelIds = diffState.nbConnectedWheels;
|
||||
PxU32 wheelIdToConnectedWheelId[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxF32 connectedWheelDiffTorqueRatios[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxF32 connectedWheelGearings[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxF32 connectedWheelAveWheelSpeedContributions[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxF32 connectedWheelMois[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxF32 connectedWheelRotSpeeds[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxF32 connectedWheelBrakeTorques[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxF32 connectedWheelTireTorques[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxF32 connectedWheelDampingRates[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
bool connectedWheelIsBrakeApplied[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
//PxF32 connectedWheelRadii[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
for(PxU32 i = 0; i < nbConnectedWheelIds; i++)
|
||||
{
|
||||
const PxU32 wheelId = connectedWheelIds[i];
|
||||
wheelIdToConnectedWheelId[wheelId] = i;
|
||||
connectedWheelDiffTorqueRatios[i] = PxAbs(diffState.torqueRatiosAllWheels[wheelId]);
|
||||
connectedWheelGearings[i] = PxVehicleComputeSign(diffState.torqueRatiosAllWheels[wheelId]);
|
||||
connectedWheelAveWheelSpeedContributions[i] = diffState.aveWheelSpeedContributionAllWheels[wheelId];
|
||||
connectedWheelMois[i] = wheelParams[wheelId].moi;
|
||||
connectedWheelRotSpeeds[i] = wheelRigidbody1dStates[wheelId].rotationSpeed;
|
||||
connectedWheelBrakeTorques[i] = -PxVehicleComputeSign(wheelRigidbody1dStates[wheelId].rotationSpeed)*brakeResponseStates[wheelId];
|
||||
connectedWheelTireTorques[i] = tireForces[wheelId].wheelTorque;
|
||||
connectedWheelDampingRates[i] = wheelParams[wheelId].dampingRate;
|
||||
connectedWheelIsBrakeApplied[i] = actuationStates[wheelId].isBrakeApplied;
|
||||
//connectedWheelRadii[i] = wheelParams[wheelId].radius;
|
||||
};
|
||||
|
||||
//Compute the clutch slip
|
||||
clutchState.setToDefault();
|
||||
PxF32 clutchSlip = 0;
|
||||
{
|
||||
PxF32 averageWheelSpeed = 0;
|
||||
for (PxU32 i = 0; i < nbConnectedWheelIds; i++)
|
||||
{
|
||||
averageWheelSpeed += connectedWheelRotSpeeds[i] * connectedWheelAveWheelSpeedContributions[i];
|
||||
}
|
||||
clutchSlip = G*averageWheelSpeed - engineState.rotationSpeed;
|
||||
}
|
||||
clutchState.clutchSlip = clutchSlip;
|
||||
|
||||
//
|
||||
//torque at clutch:
|
||||
//tc = K*{G*[alpha0*w0 + alpha1*w1 + alpha2*w2 + ..... alpha(N-1)*w(N-1)] - wEng}
|
||||
//where
|
||||
//(i) G is the gearing ratio,
|
||||
//(ii) alphai is the fractional contribution of the ith wheel to the average wheel speed at the clutch (alpha(i) is zero for undriven wheels)
|
||||
//(iii) wi is the angular speed of the ith wheel
|
||||
//(iv) K is the clutch strength
|
||||
//(v) wEng is the angular speed of the engine
|
||||
|
||||
//torque applied to ith wheel is
|
||||
//ti = G*gammai*tc + bt(i) + tt(i)
|
||||
//where
|
||||
//gammai is the fractional proportion of the clutch torque that the differential delivers to the ith wheel
|
||||
//bt(i) is the brake torque applied to the ith wheel
|
||||
//tt(i) is the tire torque applied to the ith wheel
|
||||
|
||||
//acceleration applied to ith wheel is
|
||||
//ai = G*gammai*K*{G*[alpha0*w0 + alpha1*w1 alpha2*w2 + ..... alpha(N-1)*w(N-1)] - wEng}/Ii + (bt(i) + tt(i))/Ii
|
||||
//wheer Ii is the moi of the ith wheel
|
||||
|
||||
//express ai as
|
||||
//ai = [wi(t+dt) - wi(t)]/dt
|
||||
//and rearrange
|
||||
//wi(t+dt) - wi(t)] = dt*G*gammai*K*{G*[alpha0*w0(t+dt) + alpha1*w1(t+dt) + alpha2*w2(t+dt) + ..... alpha(N-1)*w(N-1)(t+dt)] - wEng(t+dt)}/Ii + dt*(bt(i) + tt(i))/Ii
|
||||
|
||||
//Do the same for tEng (torque applied to engine)
|
||||
//tEng = -tc + engineDriveTorque
|
||||
//where engineDriveTorque is the drive torque applied to the engine
|
||||
//Assuming the engine has unit mass then
|
||||
//wEng(t+dt) -wEng(t) = -dt*K*{G*[alpha0*w0(t+dt) + alpha1*w1(t+dt) + alpha2*w2(t+dt) + ..... alpha(N-1)*w(N-1(t+dt))] - wEng(t+dt)}/Ieng + dt*engineDriveTorque]/IEng
|
||||
|
||||
//Introduce the vector w=(w0,w1,w2....w(N-1), wEng)
|
||||
//and re-express as a matrix after collecting all unknowns at (t+dt) and knowns at time t.
|
||||
//A*w(t+dt)=b(t);
|
||||
|
||||
PxVehicleMatrixNN M(nbConnectedWheelIds + 1);
|
||||
PxVehicleVectorN b(nbConnectedWheelIds + 1);
|
||||
PxVehicleVectorN result(nbConnectedWheelIds + 1);
|
||||
|
||||
const PxF32 KG = K * G;
|
||||
const PxF32 KGG = K * G*G;
|
||||
|
||||
//Wheels
|
||||
{
|
||||
for (PxU32 i = 0; i < nbConnectedWheelIds; i++)
|
||||
{
|
||||
const PxF32 dt = DT / connectedWheelMois[i];
|
||||
const PxF32 R = connectedWheelDiffTorqueRatios[i];
|
||||
const PxF32 g = connectedWheelGearings[i];
|
||||
const PxF32 dtKGGRg = dt * KGG*R*g;
|
||||
|
||||
for(PxU32 j = 0; j < nbConnectedWheelIds; j++)
|
||||
{
|
||||
M.set(i, j, dtKGGRg*connectedWheelAveWheelSpeedContributions[j]*connectedWheelGearings[j]);
|
||||
}
|
||||
M.set(i, i, 1.0f + dtKGGRg*connectedWheelAveWheelSpeedContributions[i]*connectedWheelGearings[i] + dt * connectedWheelDampingRates[i]);
|
||||
M.set(i, nbConnectedWheelIds, -dt*KG*R*g);
|
||||
b[i] = connectedWheelRotSpeeds[i] + dt * (connectedWheelBrakeTorques[i] + connectedWheelTireTorques[i]);
|
||||
result[i] = connectedWheelRotSpeeds[i];
|
||||
}
|
||||
}
|
||||
|
||||
//Engine.
|
||||
{
|
||||
const PxF32 dt = DT / engineParams.moi;
|
||||
const PxF32 dtKG = dt*K*G;
|
||||
for(PxU32 j = 0; j < nbConnectedWheelIds; j++)
|
||||
{
|
||||
M.set(nbConnectedWheelIds, j, -dtKG * connectedWheelAveWheelSpeedContributions[j]* connectedWheelGearings[j]);
|
||||
}
|
||||
M.set(nbConnectedWheelIds, nbConnectedWheelIds, 1.0f + dt * (K + engineDampingRate));
|
||||
b[nbConnectedWheelIds] = engineState.rotationSpeed + dt * engineDriveTorque;
|
||||
result[nbConnectedWheelIds] = engineState.rotationSpeed;
|
||||
}
|
||||
|
||||
if (constraintGroupState && constraintGroupState->getNbConstraintGroups() > 0)
|
||||
{
|
||||
const PxU32 nbConstraintGroups = constraintGroupState->getNbConstraintGroups();
|
||||
|
||||
//Count the wheels not in a constraint group.
|
||||
PxU32 connectedWheelsNotInConstraintGroup[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxU32 nbConnectedWheelsNotInConstraintGroup = 0;
|
||||
countConnectedWheelsNotInConstraintGroup(
|
||||
connectedWheelIds, nbConnectedWheelIds, *constraintGroupState,
|
||||
connectedWheelsNotInConstraintGroup, nbConnectedWheelsNotInConstraintGroup);
|
||||
|
||||
//After applying constraint groups:
|
||||
// number of columns remains nbConnectedWheelIds + 1
|
||||
// each row will be of length nbConnectedWheelsNotInConstraintGroup + nbConstraintGroups + 1
|
||||
PxVehicleMatrixNN A(nbConnectedWheelIds + 1);
|
||||
for (PxU32 i = 0; i < nbConnectedWheelIds + 1; i++)
|
||||
{
|
||||
//1 entry for each wheel not in a constraint group.
|
||||
for (PxU32 j = 0; j < nbConnectedWheelsNotInConstraintGroup; j++)
|
||||
{
|
||||
const PxU32 wheelId = connectedWheelsNotInConstraintGroup[j];
|
||||
const PxU32 connectedWheelId = wheelIdToConnectedWheelId[wheelId];
|
||||
const PxF32 MIJ = M.get(i, connectedWheelId);
|
||||
A.set(i, j, MIJ);
|
||||
}
|
||||
|
||||
//1 entry for each constraint group.
|
||||
for (PxU32 j = nbConnectedWheelsNotInConstraintGroup; j < nbConnectedWheelsNotInConstraintGroup + nbConstraintGroups; j++)
|
||||
{
|
||||
const PxU32 constraintGroupId = (j - nbConnectedWheelsNotInConstraintGroup);
|
||||
|
||||
PxF32 sum = 0.0f;
|
||||
//for (PxU32 k = 0; k < 1; k++)
|
||||
{
|
||||
//k = 0 is a special case with multiplier = 1.0.
|
||||
const PxU32 wheelId = constraintGroupState->getWheelInConstraintGroup(0, constraintGroupId);
|
||||
const PxF32 multiplier = 1.0f;
|
||||
const PxU32 connectedWheelId = wheelIdToConnectedWheelId[wheelId];
|
||||
const PxF32 MIK = M.get(i, connectedWheelId);
|
||||
sum += MIK * multiplier;
|
||||
}
|
||||
for (PxU32 k = 1; k < constraintGroupState->getNbWheelsInConstraintGroup(constraintGroupId); k++)
|
||||
{
|
||||
const PxU32 wheelId = constraintGroupState->getWheelInConstraintGroup(k, constraintGroupId);
|
||||
const PxF32 multiplier = constraintGroupState->getMultiplierInConstraintGroup(k, constraintGroupId);
|
||||
const PxU32 connectedWheelId = wheelIdToConnectedWheelId[wheelId];
|
||||
const PxF32 MIK = M.get(i, connectedWheelId);
|
||||
sum += MIK*multiplier;
|
||||
}
|
||||
A.set(i, j, sum);
|
||||
}
|
||||
|
||||
//1 entry for the engine.
|
||||
{
|
||||
const PxF32 MIJ = M.get(i, nbConnectedWheelIds);
|
||||
A.set(i, nbConnectedWheelsNotInConstraintGroup + nbConstraintGroups, MIJ);
|
||||
}
|
||||
}
|
||||
|
||||
const PxU32 N = (nbConnectedWheelsNotInConstraintGroup + nbConstraintGroups + 1);
|
||||
//Compute A^T * A
|
||||
PxVehicleMatrixNN ATA(N);
|
||||
for (PxU32 i = 0; i < N; i++)
|
||||
{
|
||||
for (PxU32 j = 0; j < N; j++)
|
||||
{
|
||||
PxF32 sum = 0.0f;
|
||||
for (PxU32 k = 0; k < nbConnectedWheelIds + 1; k++)
|
||||
{
|
||||
sum += A.get(k, i)*A.get(k, j);
|
||||
}
|
||||
ATA.set(i, j, sum);
|
||||
}
|
||||
}
|
||||
|
||||
//Compute A^T*b;
|
||||
PxVehicleVectorN ATb(N);
|
||||
for (PxU32 i = 0; i < N; i++)
|
||||
{
|
||||
PxF32 sum = 0;
|
||||
for (PxU32 j = 0; j < nbConnectedWheelIds + 1; j++)
|
||||
{
|
||||
sum += A.get(j, i)*b[j];
|
||||
}
|
||||
ATb[i] = sum;
|
||||
}
|
||||
|
||||
//Solve it.
|
||||
PxVehicleMatrixNNLUSolver solver;
|
||||
PxVehicleVectorN result2(N);
|
||||
solver.decomposeLU(ATA);
|
||||
solver.solve(ATb, result2);
|
||||
|
||||
//Map from result2 back to result.
|
||||
for (PxU32 j = 0; j < nbConnectedWheelsNotInConstraintGroup; j++)
|
||||
{
|
||||
const PxU32 wheelId = connectedWheelsNotInConstraintGroup[j];
|
||||
const PxU32 connectedWheelId = wheelIdToConnectedWheelId[wheelId];
|
||||
result[connectedWheelId] = result2[j];
|
||||
}
|
||||
for (PxU32 j = nbConnectedWheelsNotInConstraintGroup; j < nbConnectedWheelsNotInConstraintGroup + nbConstraintGroups; j++)
|
||||
{
|
||||
const PxU32 constraintGroupId = (j - nbConnectedWheelsNotInConstraintGroup);
|
||||
//for (PxU32 k = 0; k < 1; k++)
|
||||
{
|
||||
//k = 0 is a special case with multiplier = 1.0
|
||||
const PxU32 wheelId = constraintGroupState->getWheelInConstraintGroup(0, constraintGroupId);
|
||||
const PxF32 multiplier = 1.0f;
|
||||
const PxU32 connectedWheelId = wheelIdToConnectedWheelId[wheelId];
|
||||
result[connectedWheelId] = multiplier * result2[j];
|
||||
}
|
||||
for (PxU32 k = 1; k < constraintGroupState->getNbWheelsInConstraintGroup(constraintGroupId); k++)
|
||||
{
|
||||
const PxU32 wheelId = constraintGroupState->getWheelInConstraintGroup(k, constraintGroupId);
|
||||
const PxF32 multiplier = constraintGroupState->getMultiplierInConstraintGroup(k, constraintGroupId);
|
||||
const PxU32 connectedWheelId = wheelIdToConnectedWheelId[wheelId];
|
||||
result[connectedWheelId] = multiplier * result2[j];
|
||||
}
|
||||
}
|
||||
{
|
||||
result[nbConnectedWheelIds] = result2[nbConnectedWheelsNotInConstraintGroup + nbConstraintGroups];
|
||||
}
|
||||
}
|
||||
else if (PxVehicleClutchAccuracyMode::eBEST_POSSIBLE == clutchParams.accuracyMode)
|
||||
{
|
||||
//Solve Aw=b
|
||||
PxVehicleMatrixNNLUSolver solver;
|
||||
solver.decomposeLU(M);
|
||||
solver.solve(b, result);
|
||||
//PX_WARN_ONCE_IF(!isValid(A, b, result), "Unable to compute new PxVehicleDrive4W internal rotation speeds. Please check vehicle sim data, especially clutch strength; engine moi and damping; wheel moi and damping");
|
||||
}
|
||||
else
|
||||
{
|
||||
PxVehicleMatrixNGaussSeidelSolver solver;
|
||||
solver.solve(clutchParams.estimateIterations, 1e-10f, M, b, result);
|
||||
}
|
||||
|
||||
//Check for sanity in the resultant internal rotation speeds.
|
||||
//If the brakes are on and the wheels have switched direction then lock them at zero.
|
||||
//A consequence of this quick fix is that locked wheels remain locked until the brake is entirely released.
|
||||
//This isn't strictly mathematically or physically correct - a more accurate solution would either formulate the
|
||||
//brake as a lcp problem or repeatedly solve with constraints that locked wheels remain at zero rotation speed.
|
||||
//The physically correct solution will certainly be more expensive so let's live with the restriction that
|
||||
//locked wheels remain locked until the brake is released.
|
||||
//newOmega=result[i], oldOmega=wheelSpeeds[i], if newOmega*oldOmega<=0 and isBrakeApplied then lock wheel.
|
||||
for(PxU32 i = 0; i < nbConnectedWheelIds; i++)
|
||||
{
|
||||
result[i] = (connectedWheelIsBrakeApplied[i] && (connectedWheelRotSpeeds[i] * result[i] <= 0)) ? 0.0f : result[i];
|
||||
}
|
||||
//Clamp the engine revs.
|
||||
//Again, this is not physically or mathematically correct but the loss in behaviour will be hard to notice.
|
||||
//The alternative would be to add constraints to the solver, which would be much more expensive.
|
||||
result[nbConnectedWheelIds] = PxClamp(result[nbConnectedWheelIds], engineParams.idleOmega, engineParams.maxOmega);
|
||||
|
||||
//Copy back to the car's internal rotation speeds.
|
||||
for (PxU32 i = 0; i < nbConnectedWheelIds; i++)
|
||||
{
|
||||
const PxU32 wheelId = connectedWheelIds[i];
|
||||
wheelRigidbody1dStates[wheelId].rotationSpeed = result[i];
|
||||
}
|
||||
engineState.rotationSpeed = result[nbConnectedWheelIds];
|
||||
|
||||
//Update the undriven wheels.
|
||||
bool isDrivenWheel[PxVehicleLimits::eMAX_NB_WHEELS];
|
||||
PxMemZero(isDrivenWheel, sizeof(isDrivenWheel));
|
||||
for(PxU32 i = 0; i < nbConnectedWheelIds; i++)
|
||||
{
|
||||
const PxU32 wheelId = connectedWheelIds[i];
|
||||
isDrivenWheel[wheelId] = true;
|
||||
}
|
||||
for (PxU32 i = 0; i < axleDescription.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = axleDescription.wheelIdsInAxleOrder[i];
|
||||
if (!isDrivenWheel[wheelId])
|
||||
{
|
||||
PxVehicleDirectDriveUpdate(
|
||||
wheelParams[wheelId],
|
||||
actuationStates[wheelId],
|
||||
brakeResponseStates[wheelId], 0.0f,
|
||||
tireForces[wheelId], DT, wheelRigidbody1dStates[wheelId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleClutchCommandResponseLinearUpdate
|
||||
(const PxReal clutchCommand,
|
||||
const PxVehicleClutchCommandResponseParams& clutchResponseParams,
|
||||
PxVehicleClutchCommandResponseState& clutchResponse)
|
||||
{
|
||||
clutchResponse.normalisedCommandResponse = (1.0f - clutchCommand);
|
||||
clutchResponse.commandResponse = (1.0f - clutchCommand)*clutchResponseParams.maxResponse;
|
||||
}
|
||||
|
||||
void PxVehicleEngineDriveThrottleCommandResponseLinearUpdate
|
||||
(const PxVehicleCommandState& commands,
|
||||
PxVehicleEngineDriveThrottleCommandResponseState& throttleResponse)
|
||||
{
|
||||
throttleResponse.commandResponse = commands.throttle;
|
||||
}
|
||||
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
439
engine/third_party/physx/source/physxvehicle/src/drivetrain/VhDrivetrainHelpers.cpp
vendored
Normal file
439
engine/third_party/physx/source/physxvehicle/src/drivetrain/VhDrivetrainHelpers.cpp
vendored
Normal file
@@ -0,0 +1,439 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
#include "vehicle2/PxVehicleFunctions.h"
|
||||
#include "vehicle2/PxVehicleMaths.h"
|
||||
|
||||
#include "vehicle2/drivetrain/PxVehicleDrivetrainHelpers.h"
|
||||
#include "vehicle2/drivetrain/PxVehicleDrivetrainParams.h"
|
||||
|
||||
#include "vehicle2/wheel/PxVehicleWheelStates.h"
|
||||
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
void PxVehicleMatrixNNLUSolver::decomposeLU(const PxVehicleMatrixNN& A)
|
||||
{
|
||||
const PxU32 D = A.mSize;
|
||||
|
||||
mLU = A;
|
||||
|
||||
mDetM = 1.0f;
|
||||
|
||||
for (PxU32 k = 0; k < D - 1; ++k)
|
||||
{
|
||||
PxU32 pivot_row = k;
|
||||
PxU32 pivot_col = k;
|
||||
float abs_pivot_elem = 0.0f;
|
||||
for (PxU32 c = k; c < D; ++c)
|
||||
{
|
||||
for (PxU32 r = k; r < D; ++r)
|
||||
{
|
||||
const PxF32 abs_elem = PxAbs(mLU.get(r, c));
|
||||
if (abs_elem > abs_pivot_elem)
|
||||
{
|
||||
abs_pivot_elem = abs_elem;
|
||||
pivot_row = r;
|
||||
pivot_col = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mP[k] = pivot_row;
|
||||
if (pivot_row != k)
|
||||
{
|
||||
mDetM = -mDetM;
|
||||
for (PxU32 c = 0; c < D; ++c)
|
||||
{
|
||||
//swap(m_LU(k,c), m_LU(pivot_row,c));
|
||||
const PxF32 pivotrowc = mLU.get(pivot_row, c);
|
||||
mLU.set(pivot_row, c, mLU.get(k, c));
|
||||
mLU.set(k, c, pivotrowc);
|
||||
}
|
||||
}
|
||||
|
||||
mQ[k] = pivot_col;
|
||||
if (pivot_col != k)
|
||||
{
|
||||
mDetM = -mDetM;
|
||||
for (PxU32 r = 0; r < D; ++r)
|
||||
{
|
||||
//swap(m_LU(r,k), m_LU(r,pivot_col));
|
||||
const PxF32 rpivotcol = mLU.get(r, pivot_col);
|
||||
mLU.set(r, pivot_col, mLU.get(r, k));
|
||||
mLU.set(r, k, rpivotcol);
|
||||
}
|
||||
}
|
||||
|
||||
mDetM *= mLU.get(k, k);
|
||||
|
||||
if (mLU.get(k, k) != 0.0f)
|
||||
{
|
||||
for (PxU32 r = k + 1; r < D; ++r)
|
||||
{
|
||||
mLU.set(r, k, mLU.get(r, k) / mLU.get(k, k));
|
||||
for (PxU32 c = k + 1; c < D; ++c)
|
||||
{
|
||||
//m_LU(r,c) -= m_LU(r,k)*m_LU(k,c);
|
||||
const PxF32 rc = mLU.get(r, c);
|
||||
const PxF32 rk = mLU.get(r, k);
|
||||
const PxF32 kc = mLU.get(k, c);
|
||||
mLU.set(r, c, rc - rk * kc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mDetM *= mLU.get(D - 1, D - 1);
|
||||
}
|
||||
|
||||
bool PxVehicleMatrixNNLUSolver::solve(const PxVehicleVectorN& b, PxVehicleVectorN& x) const
|
||||
{
|
||||
const PxU32 D = x.getSize();
|
||||
|
||||
if ((b.getSize() != x.getSize()) || (b.getSize() != mLU.getSize()) || (0.0f == mDetM))
|
||||
{
|
||||
for (PxU32 i = 0; i < D; i++)
|
||||
{
|
||||
x[i] = 0.0f;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
x = b;
|
||||
|
||||
// Perform row permutation to get Pb
|
||||
for (PxU32 i = 0; i < D - 1; ++i)
|
||||
{
|
||||
//swap(x(i), x(m_P[i]));
|
||||
const PxF32 xp = x[mP[i]];
|
||||
x[mP[i]] = x[i];
|
||||
x[i] = xp;
|
||||
}
|
||||
|
||||
// Forward substitute to get (L^-1)Pb
|
||||
for (PxU32 r = 1; r < D; ++r)
|
||||
{
|
||||
for (PxU32 i = 0; i < r; ++i)
|
||||
{
|
||||
x[r] -= mLU.get(r, i)*x[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Back substitute to get (U^-1)(L^-1)Pb
|
||||
for (PxU32 r = D; r-- > 0;)
|
||||
{
|
||||
for (PxU32 i = r + 1; i < D; ++i)
|
||||
{
|
||||
x[r] -= mLU.get(r, i)*x[i];
|
||||
}
|
||||
x[r] /= mLU.get(r, r);
|
||||
}
|
||||
|
||||
// Perform column permutation to get the solution (Q^T)(U^-1)(L^-1)Pb
|
||||
for (PxU32 i = D - 1; i-- > 0;)
|
||||
{
|
||||
//swap(x(i), x(m_Q[i]));
|
||||
const PxF32 xq = x[mQ[i]];
|
||||
x[mQ[i]] = x[i];
|
||||
x[i] = xq;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PxVehicleMatrixNGaussSeidelSolver::solve(const PxU32 maxIterations, const PxF32 tolerance, const PxVehicleMatrixNN& A, const PxVehicleVectorN& b, PxVehicleVectorN& result) const
|
||||
{
|
||||
const PxU32 N = A.getSize();
|
||||
|
||||
PxVehicleVectorN DInv(N);
|
||||
PxF32 bLength2 = 0.0f;
|
||||
for (PxU32 i = 0; i < N; i++)
|
||||
{
|
||||
DInv[i] = 1.0f / A.get(i, i);
|
||||
bLength2 += (b[i] * b[i]);
|
||||
}
|
||||
|
||||
PxU32 iteration = 0;
|
||||
PxF32 error = PX_MAX_F32;
|
||||
while (iteration < maxIterations && tolerance < error)
|
||||
{
|
||||
for (PxU32 i = 0; i < N; i++)
|
||||
{
|
||||
PxF32 l = 0.0f;
|
||||
for (PxU32 j = 0; j < i; j++)
|
||||
{
|
||||
l += A.get(i, j) * result[j];
|
||||
}
|
||||
|
||||
PxF32 u = 0.0f;
|
||||
for (PxU32 j = i + 1; j < N; j++)
|
||||
{
|
||||
u += A.get(i, j) * result[j];
|
||||
}
|
||||
|
||||
result[i] = DInv[i] * (b[i] - l - u);
|
||||
}
|
||||
|
||||
//Compute the error.
|
||||
PxF32 rLength2 = 0;
|
||||
for (PxU32 i = 0; i < N; i++)
|
||||
{
|
||||
PxF32 e = -b[i];
|
||||
for (PxU32 j = 0; j < N; j++)
|
||||
{
|
||||
e += A.get(i, j) * result[j];
|
||||
}
|
||||
rLength2 += e * e;
|
||||
}
|
||||
error = (rLength2 / (bLength2 + 1e-10f));
|
||||
|
||||
iteration++;
|
||||
}
|
||||
}
|
||||
|
||||
bool PxVehicleMatrix33Solver::solve(const PxVehicleMatrixNN& A_, const PxVehicleVectorN& b_, PxVehicleVectorN& result) const
|
||||
{
|
||||
const PxF32 a = A_.get(0, 0);
|
||||
const PxF32 b = A_.get(0, 1);
|
||||
const PxF32 c = A_.get(0, 2);
|
||||
|
||||
const PxF32 d = A_.get(1, 0);
|
||||
const PxF32 e = A_.get(1, 1);
|
||||
const PxF32 f = A_.get(1, 2);
|
||||
|
||||
const PxF32 g = A_.get(2, 0);
|
||||
const PxF32 h = A_.get(2, 1);
|
||||
const PxF32 k = A_.get(2, 2);
|
||||
|
||||
const PxF32 detA = a * (e*k - f * h) - b * (k*d - f * g) + c * (d*h - e * g);
|
||||
if (0.0f == detA)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const PxF32 detAInv = 1.0f / detA;
|
||||
|
||||
const PxF32 A = (e*k - f * h);
|
||||
const PxF32 D = -(b*k - c * h);
|
||||
const PxF32 G = (b*f - c * e);
|
||||
const PxF32 B = -(d*k - f * g);
|
||||
const PxF32 E = (a*k - c * g);
|
||||
const PxF32 H = -(a*f - c * d);
|
||||
const PxF32 C = (d*h - e * g);
|
||||
const PxF32 F = -(a*h - b * g);
|
||||
const PxF32 K = (a*e - b * d);
|
||||
|
||||
result[0] = detAInv * (A*b_[0] + D * b_[1] + G * b_[2]);
|
||||
result[1] = detAInv * (B*b_[0] + E * b_[1] + H * b_[2]);
|
||||
result[2] = detAInv * (C*b_[0] + F * b_[1] + K * b_[2]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PxVehicleLegacyDifferentialWheelSpeedContributionsCompute
|
||||
(const PxVehicleFourWheelDriveDifferentialLegacyParams& diffParams,
|
||||
const PxU32 nbWheels, PxReal* diffAveWheelSpeedContributions)
|
||||
{
|
||||
PxMemZero(diffAveWheelSpeedContributions, sizeof(PxReal) * nbWheels);
|
||||
|
||||
const PxU32 wheelIds[4] =
|
||||
{
|
||||
diffParams.frontWheelIds[0],
|
||||
diffParams.frontWheelIds[1],
|
||||
diffParams.rearWheelIds[0],
|
||||
diffParams.rearWheelIds[1],
|
||||
};
|
||||
|
||||
const PxF32 frontRearSplit = diffParams.frontRearSplit;
|
||||
const PxF32 frontNegPosSplit = diffParams.frontNegPosSplit;
|
||||
const PxF32 rearNegPosSplit = diffParams.rearNegPosSplit;
|
||||
|
||||
const PxF32 oneMinusFrontRearSplit = 1.0f - diffParams.frontRearSplit;
|
||||
const PxF32 oneMinusFrontNegPosSplit = 1.0f - diffParams.frontNegPosSplit;
|
||||
const PxF32 oneMinusRearNegPosSplit = 1.0f - diffParams.rearNegPosSplit;
|
||||
|
||||
switch (diffParams.type)
|
||||
{
|
||||
case PxVehicleFourWheelDriveDifferentialLegacyParams::eDIFF_TYPE_LS_4WD:
|
||||
diffAveWheelSpeedContributions[wheelIds[0]] = frontRearSplit * frontNegPosSplit;
|
||||
diffAveWheelSpeedContributions[wheelIds[1]] = frontRearSplit * oneMinusFrontNegPosSplit;
|
||||
diffAveWheelSpeedContributions[wheelIds[2]] = oneMinusFrontRearSplit * rearNegPosSplit;
|
||||
diffAveWheelSpeedContributions[wheelIds[3]] = oneMinusFrontRearSplit * oneMinusRearNegPosSplit;
|
||||
break;
|
||||
case PxVehicleFourWheelDriveDifferentialLegacyParams::eDIFF_TYPE_LS_FRONTWD:
|
||||
diffAveWheelSpeedContributions[wheelIds[0]] = frontNegPosSplit;
|
||||
diffAveWheelSpeedContributions[wheelIds[1]] = oneMinusFrontNegPosSplit;
|
||||
diffAveWheelSpeedContributions[wheelIds[2]] = 0.0f;
|
||||
diffAveWheelSpeedContributions[wheelIds[3]] = 0.0f;
|
||||
break;
|
||||
case PxVehicleFourWheelDriveDifferentialLegacyParams::eDIFF_TYPE_LS_REARWD:
|
||||
diffAveWheelSpeedContributions[wheelIds[0]] = 0.0f;
|
||||
diffAveWheelSpeedContributions[wheelIds[1]] = 0.0f;
|
||||
diffAveWheelSpeedContributions[wheelIds[2]] = rearNegPosSplit;
|
||||
diffAveWheelSpeedContributions[wheelIds[3]] = oneMinusRearNegPosSplit;
|
||||
break;
|
||||
default:
|
||||
PX_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
PX_ASSERT(
|
||||
((diffAveWheelSpeedContributions[wheelIds[0]] + diffAveWheelSpeedContributions[wheelIds[1]] + diffAveWheelSpeedContributions[wheelIds[2]] + diffAveWheelSpeedContributions[wheelIds[3]]) >= 0.999f) &&
|
||||
((diffAveWheelSpeedContributions[wheelIds[0]] + diffAveWheelSpeedContributions[wheelIds[1]] + diffAveWheelSpeedContributions[wheelIds[2]] + diffAveWheelSpeedContributions[wheelIds[3]]) <= 1.001f));
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void splitTorque
|
||||
(const PxF32 w1, const PxF32 w2, const PxF32 diffBias, const PxF32 defaultSplitRatio,
|
||||
PxF32* t1, PxF32* t2)
|
||||
{
|
||||
PX_ASSERT(PxVehicleComputeSign(w1) == PxVehicleComputeSign(w2) && 0.0f != PxVehicleComputeSign(w1));
|
||||
const PxF32 w1Abs = PxAbs(w1);
|
||||
const PxF32 w2Abs = PxAbs(w2);
|
||||
const PxF32 omegaMax = PxMax(w1Abs, w2Abs);
|
||||
const PxF32 omegaMin = PxMin(w1Abs, w2Abs);
|
||||
const PxF32 delta = omegaMax - diffBias * omegaMin;
|
||||
const PxF32 deltaTorque = physx::intrinsics::fsel(delta, delta / omegaMax, 0.0f);
|
||||
const PxF32 f1 = physx::intrinsics::fsel(w1Abs - w2Abs, defaultSplitRatio*(1.0f - deltaTorque), defaultSplitRatio*(1.0f + deltaTorque));
|
||||
const PxF32 f2 = physx::intrinsics::fsel(w1Abs - w2Abs, (1.0f - defaultSplitRatio)*(1.0f + deltaTorque), (1.0f - defaultSplitRatio)*(1.0f - deltaTorque));
|
||||
const PxF32 denom = 1.0f / (f1 + f2);
|
||||
*t1 = f1 * denom;
|
||||
*t2 = f2 * denom;
|
||||
PX_ASSERT((*t1 + *t2) >= 0.999f && (*t1 + *t2) <= 1.001f);
|
||||
}
|
||||
|
||||
void PxVehicleLegacyDifferentialTorqueRatiosCompute
|
||||
(const PxVehicleFourWheelDriveDifferentialLegacyParams& diffParams,
|
||||
const PxVehicleArrayData<const PxVehicleWheelRigidBody1dState>& wheelOmegas,
|
||||
const PxU32 nbWheels, PxReal* diffTorqueRatios)
|
||||
{
|
||||
PxMemZero(diffTorqueRatios, sizeof(PxReal) * nbWheels);
|
||||
|
||||
const PxU32 wheelIds[4] =
|
||||
{
|
||||
diffParams.frontWheelIds[0],
|
||||
diffParams.frontWheelIds[1],
|
||||
diffParams.rearWheelIds[0],
|
||||
diffParams.rearWheelIds[1],
|
||||
};
|
||||
|
||||
const PxF32 wfl = wheelOmegas[wheelIds[0]].rotationSpeed;
|
||||
const PxF32 wfr = wheelOmegas[wheelIds[1]].rotationSpeed;
|
||||
const PxF32 wrl = wheelOmegas[wheelIds[2]].rotationSpeed;
|
||||
const PxF32 wrr = wheelOmegas[wheelIds[3]].rotationSpeed;
|
||||
|
||||
const PxF32 centreBias = diffParams.centerBias;
|
||||
const PxF32 frontBias = diffParams.frontBias;
|
||||
const PxF32 rearBias = diffParams.rearBias;
|
||||
|
||||
const PxF32 frontRearSplit = diffParams.frontRearSplit;
|
||||
const PxF32 frontLeftRightSplit = diffParams.frontNegPosSplit;
|
||||
const PxF32 rearLeftRightSplit = diffParams.rearNegPosSplit;
|
||||
|
||||
const PxF32 oneMinusFrontRearSplit = 1.0f - diffParams.frontRearSplit;
|
||||
const PxF32 oneMinusFrontLeftRightSplit = 1.0f - diffParams.frontNegPosSplit;
|
||||
const PxF32 oneMinusRearLeftRightSplit = 1.0f - diffParams.rearNegPosSplit;
|
||||
|
||||
const PxF32 swfl = PxVehicleComputeSign(wfl);
|
||||
|
||||
//Split a torque of 1 between front and rear.
|
||||
//Then split that torque between left and right.
|
||||
PxF32 torqueFrontLeft = 0;
|
||||
PxF32 torqueFrontRight = 0;
|
||||
PxF32 torqueRearLeft = 0;
|
||||
PxF32 torqueRearRight = 0;
|
||||
switch (diffParams.type)
|
||||
{
|
||||
case PxVehicleFourWheelDriveDifferentialLegacyParams::eDIFF_TYPE_LS_4WD:
|
||||
if (0.0f != swfl && swfl == PxVehicleComputeSign(wfr) && swfl == PxVehicleComputeSign(wrl) && swfl == PxVehicleComputeSign(wrr))
|
||||
{
|
||||
PxF32 torqueFront, torqueRear;
|
||||
const PxF32 omegaFront = PxAbs(wfl + wfr);
|
||||
const PxF32 omegaRear = PxAbs(wrl + wrr);
|
||||
splitTorque(omegaFront, omegaRear, centreBias, frontRearSplit, &torqueFront, &torqueRear);
|
||||
splitTorque(wfl, wfr, frontBias, frontLeftRightSplit, &torqueFrontLeft, &torqueFrontRight);
|
||||
splitTorque(wrl, wrr, rearBias, rearLeftRightSplit, &torqueRearLeft, &torqueRearRight);
|
||||
torqueFrontLeft *= torqueFront;
|
||||
torqueFrontRight *= torqueFront;
|
||||
torqueRearLeft *= torqueRear;
|
||||
torqueRearRight *= torqueRear;
|
||||
}
|
||||
else
|
||||
{
|
||||
torqueFrontLeft = frontRearSplit * frontLeftRightSplit;
|
||||
torqueFrontRight = frontRearSplit * oneMinusFrontLeftRightSplit;
|
||||
torqueRearLeft = oneMinusFrontRearSplit * rearLeftRightSplit;
|
||||
torqueRearRight = oneMinusFrontRearSplit * oneMinusRearLeftRightSplit;
|
||||
}
|
||||
break;
|
||||
|
||||
case PxVehicleFourWheelDriveDifferentialLegacyParams::eDIFF_TYPE_LS_FRONTWD:
|
||||
if (0.0f != swfl && swfl == PxVehicleComputeSign(wfr))
|
||||
{
|
||||
splitTorque(wfl, wfr, frontBias, frontLeftRightSplit, &torqueFrontLeft, &torqueFrontRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
torqueFrontLeft = frontLeftRightSplit;
|
||||
torqueFrontRight = oneMinusFrontLeftRightSplit;
|
||||
}
|
||||
break;
|
||||
|
||||
case PxVehicleFourWheelDriveDifferentialLegacyParams::eDIFF_TYPE_LS_REARWD:
|
||||
|
||||
if (0.0f != PxVehicleComputeSign(wrl) && PxVehicleComputeSign(wrl) == PxVehicleComputeSign(wrr))
|
||||
{
|
||||
splitTorque(wrl, wrr, rearBias, rearLeftRightSplit, &torqueRearLeft, &torqueRearRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
torqueRearLeft = rearLeftRightSplit;
|
||||
torqueRearRight = oneMinusRearLeftRightSplit;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PX_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
diffTorqueRatios[wheelIds[0]] = torqueFrontLeft;
|
||||
diffTorqueRatios[wheelIds[1]] = torqueFrontRight;
|
||||
diffTorqueRatios[wheelIds[2]] = torqueRearLeft;
|
||||
diffTorqueRatios[wheelIds[3]] = torqueRearRight;
|
||||
|
||||
PX_ASSERT(((torqueFrontLeft + torqueFrontRight + torqueRearLeft + torqueRearRight) >= 0.999f) && ((torqueFrontLeft + torqueFrontRight + torqueRearLeft + torqueRearRight) <= 1.001f));
|
||||
}
|
||||
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
|
||||
350
engine/third_party/physx/source/physxvehicle/src/physxActor/VhPhysXActorFunctions.cpp
vendored
Normal file
350
engine/third_party/physx/source/physxvehicle/src/physxActor/VhPhysXActorFunctions.cpp
vendored
Normal file
@@ -0,0 +1,350 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/commands/PxVehicleCommandStates.h"
|
||||
|
||||
#include "vehicle2/drivetrain/PxVehicleDrivetrainParams.h"
|
||||
#include "vehicle2/drivetrain/PxVehicleDrivetrainStates.h"
|
||||
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyStates.h"
|
||||
|
||||
#include "vehicle2/physxActor/PxVehiclePhysXActorFunctions.h"
|
||||
#include "vehicle2/physxActor/PxVehiclePhysXActorStates.h"
|
||||
|
||||
#include "vehicle2/physxConstraints/PxVehiclePhysXConstraintStates.h"
|
||||
#include "vehicle2/physxConstraints/PxVehiclePhysXConstraintHelpers.h"
|
||||
|
||||
#include "vehicle2/wheel/PxVehicleWheelParams.h"
|
||||
#include "vehicle2/wheel/PxVehicleWheelStates.h"
|
||||
|
||||
#include "PxRigidDynamic.h"
|
||||
#include "PxArticulationLink.h"
|
||||
#include "PxArticulationReducedCoordinate.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
void PxVehiclePhysxActorWakeup(
|
||||
const PxVehicleCommandState& commands,
|
||||
const PxVehicleEngineDriveTransmissionCommandState* transmissionCommands,
|
||||
const PxVehicleGearboxParams* gearParams,
|
||||
const PxVehicleGearboxState* gearState,
|
||||
PxRigidBody& physxActor,
|
||||
PxVehiclePhysXSteerState& physxSteerState)
|
||||
{
|
||||
PX_CHECK_AND_RETURN(!(physxActor.getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC), "PxVehiclePhysxActorWakeup: physxActor is kinematic. This is not supported");
|
||||
|
||||
PxRigidDynamic* rd = physxActor.is<PxRigidDynamic>();
|
||||
PxArticulationLink* link = physxActor.is<PxArticulationLink>();
|
||||
bool intentToChangeState = ((commands.throttle != 0.0f) || ((PX_VEHICLE_UNSPECIFIED_STEER_STATE != physxSteerState.previousSteerCommand) && (commands.steer != physxSteerState.previousSteerCommand)));
|
||||
if (!intentToChangeState && transmissionCommands)
|
||||
{
|
||||
PX_ASSERT(gearParams);
|
||||
PX_ASSERT(gearState);
|
||||
|
||||
// Manual gear switch (includes going from neutral or reverse to automatic)
|
||||
intentToChangeState = (gearState->currentGear == gearState->targetGear) &&
|
||||
(((transmissionCommands->targetGear != PxVehicleEngineDriveTransmissionCommandState::eAUTOMATIC_GEAR) && (gearState->targetGear != transmissionCommands->targetGear)) ||
|
||||
((transmissionCommands->targetGear == PxVehicleEngineDriveTransmissionCommandState::eAUTOMATIC_GEAR) && (gearState->currentGear <= gearParams->neutralGear)));
|
||||
}
|
||||
|
||||
if(rd && rd->isSleeping() && intentToChangeState)
|
||||
{
|
||||
rd->wakeUp();
|
||||
}
|
||||
else if(link && link->getArticulation().isSleeping() && intentToChangeState)
|
||||
{
|
||||
link->getArticulation().wakeUp();
|
||||
}
|
||||
|
||||
physxSteerState.previousSteerCommand = commands.steer;
|
||||
}
|
||||
|
||||
bool PxVehiclePhysxActorSleepCheck
|
||||
(const PxVehicleAxleDescription& axleDescription,
|
||||
const PxRigidBody& physxActor,
|
||||
const PxVehicleEngineParams* engineParams,
|
||||
PxVehicleRigidBodyState& rigidBodyState,
|
||||
PxVehiclePhysXConstraints& physxConstraints,
|
||||
PxVehicleArrayData<PxVehicleWheelRigidBody1dState>& wheelRigidBody1dStates,
|
||||
PxVehicleEngineState* engineState)
|
||||
{
|
||||
PX_CHECK_AND_RETURN_VAL(!(physxActor.getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC), "PxVehiclePhysxActorSleepCheck: physxActor is kinematic. This is not supported", false);
|
||||
|
||||
const PxRigidDynamic* rd = physxActor.is<PxRigidDynamic>();
|
||||
const PxArticulationLink* link = physxActor.is<PxArticulationLink>();
|
||||
|
||||
bool isSleeping = false;
|
||||
if (rd && rd->isSleeping())
|
||||
{
|
||||
isSleeping = true;
|
||||
}
|
||||
else if (link && link->getArticulation().isSleeping())
|
||||
{
|
||||
isSleeping = true;
|
||||
}
|
||||
|
||||
if (isSleeping)
|
||||
{
|
||||
// note: pose is not copied as isSleeping() implies that pose was not changed by the
|
||||
// simulation step (see docu). If a user explicitly calls putToSleep or manually
|
||||
// changes pose, it will only get reflected in the vehicle rigid body state once
|
||||
// the body wakes up.
|
||||
|
||||
rigidBodyState.linearVelocity = PxVec3(PxZero);
|
||||
rigidBodyState.angularVelocity = PxVec3(PxZero);
|
||||
rigidBodyState.previousLinearVelocity = PxVec3(PxZero);
|
||||
rigidBodyState.previousAngularVelocity = PxVec3(PxZero);
|
||||
|
||||
bool markConstraintsDirty = false;
|
||||
for (PxU32 i = 0; i < axleDescription.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = axleDescription.wheelIdsInAxleOrder[i];
|
||||
PxVehicleWheelRigidBody1dState& wheelState = wheelRigidBody1dStates[wheelId];
|
||||
wheelState.rotationSpeed = 0.0f;
|
||||
wheelState.correctedRotationSpeed = 0.0f;
|
||||
|
||||
// disable constraints if there are active ones. The idea is that if something
|
||||
// is crashing into a sleeping vehicle and waking it up, then the vehicle should
|
||||
// be able to move if the impact was large enough. Thus, there is also no logic
|
||||
// to reset the sticky tire timers, for example. If the impact was small, the
|
||||
// constraints should potentially kick in again in the subsequent sim step.
|
||||
PxVehiclePhysXConstraintState& constraintState = physxConstraints.constraintStates[wheelId];
|
||||
if (constraintState.tireActiveStatus[PxVehicleTireDirectionModes::eLONGITUDINAL] ||
|
||||
constraintState.tireActiveStatus[PxVehicleTireDirectionModes::eLATERAL] ||
|
||||
constraintState.suspActiveStatus)
|
||||
{
|
||||
constraintState.tireActiveStatus[PxVehicleTireDirectionModes::eLONGITUDINAL] = false;
|
||||
constraintState.tireActiveStatus[PxVehicleTireDirectionModes::eLATERAL] = false;
|
||||
constraintState.suspActiveStatus = false;
|
||||
|
||||
markConstraintsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (markConstraintsDirty)
|
||||
PxVehicleConstraintsDirtyStateUpdate(physxConstraints);
|
||||
|
||||
if (engineState)
|
||||
{
|
||||
PX_ASSERT(engineParams);
|
||||
engineState->rotationSpeed = engineParams->idleOmega;
|
||||
}
|
||||
}
|
||||
|
||||
return isSleeping;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE static void setWakeCounter(const PxReal wakeCounter, PxRigidDynamic* rd, PxArticulationLink* link)
|
||||
{
|
||||
if (rd && (!(rd->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC)))
|
||||
{
|
||||
rd->setWakeCounter(wakeCounter);
|
||||
}
|
||||
else if (link)
|
||||
{
|
||||
link->getArticulation().setWakeCounter(wakeCounter);
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehiclePhysxActorKeepAwakeCheck
|
||||
(const PxVehicleAxleDescription& axleDescription,
|
||||
const PxVehicleArrayData<const PxVehicleWheelParams>& wheelParams,
|
||||
const PxVehicleArrayData<const PxVehicleWheelRigidBody1dState>& wheelRigidBody1dStates,
|
||||
const PxReal wakeCounterThreshold,
|
||||
const PxReal wakeCounterResetValue,
|
||||
const PxVehicleGearboxState* gearState,
|
||||
const PxReal* throttle,
|
||||
PxRigidBody& physxActor)
|
||||
{
|
||||
PX_CHECK_AND_RETURN(!(physxActor.getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC), "PxVehiclePhysxActorKeepAwakeCheck: physxActor is kinematic. This is not supported");
|
||||
|
||||
PxRigidDynamic* rd = physxActor.is<PxRigidDynamic>();
|
||||
PxArticulationLink* link = physxActor.is<PxArticulationLink>();
|
||||
|
||||
PxReal wakeCounter = PX_MAX_REAL;
|
||||
if (rd)
|
||||
{
|
||||
wakeCounter = rd->getWakeCounter();
|
||||
}
|
||||
else if (link)
|
||||
{
|
||||
wakeCounter = link->getArticulation().getWakeCounter();
|
||||
}
|
||||
|
||||
if (wakeCounter < wakeCounterThreshold)
|
||||
{
|
||||
if ((throttle && ((*throttle) > 0.0f)) ||
|
||||
(gearState && (gearState->currentGear != gearState->targetGear)))
|
||||
{
|
||||
setWakeCounter(wakeCounterResetValue, rd, link);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (PxU32 i = 0; i < axleDescription.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = axleDescription.wheelIdsInAxleOrder[i];
|
||||
const PxVehicleWheelParams& wheelParam = wheelParams[wheelId];
|
||||
const PxVehicleWheelRigidBody1dState& wheelState = wheelRigidBody1dStates[wheelId];
|
||||
|
||||
// note: the translational part of the energy is ignored here as this is mainly for
|
||||
// scenarios where there is almost no translation but the wheels are spinning
|
||||
|
||||
const PxReal normalizedEnergy = (0.5f * wheelState.correctedRotationSpeed * wheelState.correctedRotationSpeed *
|
||||
wheelParam.moi) / wheelParam.mass;
|
||||
|
||||
PxReal sleepThreshold = PX_MAX_REAL;
|
||||
if (rd)
|
||||
{
|
||||
sleepThreshold = rd->getSleepThreshold();
|
||||
}
|
||||
else if (link)
|
||||
{
|
||||
sleepThreshold = link->getArticulation().getSleepThreshold();
|
||||
}
|
||||
|
||||
if (normalizedEnergy > sleepThreshold)
|
||||
{
|
||||
setWakeCounter(wakeCounterResetValue, rd, link);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleReadRigidBodyStateFromPhysXActor
|
||||
(const PxRigidBody& physxActor,
|
||||
PxVehicleRigidBodyState& rigidBodyState)
|
||||
{
|
||||
PX_CHECK_AND_RETURN(!(physxActor.getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC), "PxVehicleReadRigidBodyStateFromPhysXActor: physxActor is kinematic. This is not supported");
|
||||
|
||||
const PxRigidDynamic* rd = physxActor.is<PxRigidDynamic>();
|
||||
const PxArticulationLink* link = physxActor.is<PxArticulationLink>();
|
||||
PX_ASSERT(rd || link);
|
||||
|
||||
if(rd)
|
||||
{
|
||||
rigidBodyState.pose = physxActor.getGlobalPose()*physxActor.getCMassLocalPose();
|
||||
rigidBodyState.angularVelocity = rd->getAngularVelocity();
|
||||
rigidBodyState.linearVelocity = rd->getLinearVelocity();
|
||||
}
|
||||
else
|
||||
{
|
||||
rigidBodyState.pose = physxActor.getGlobalPose()*physxActor.getCMassLocalPose();
|
||||
rigidBodyState.angularVelocity = link->getAngularVelocity();
|
||||
rigidBodyState.linearVelocity = link->getLinearVelocity();
|
||||
}
|
||||
rigidBodyState.previousLinearVelocity = rigidBodyState.linearVelocity;
|
||||
rigidBodyState.previousAngularVelocity = rigidBodyState.angularVelocity;
|
||||
}
|
||||
|
||||
void PxVehicleWriteWheelLocalPoseToPhysXWheelShape
|
||||
(const PxTransform& wheelLocalPose, const PxTransform& wheelShapeLocalPose, PxShape* shape)
|
||||
{
|
||||
if(!shape)
|
||||
return;
|
||||
|
||||
PxRigidActor* ra = shape->getActor();
|
||||
if(!ra)
|
||||
return;
|
||||
|
||||
PxRigidBody* rb = ra->is<PxRigidBody>();
|
||||
if(!rb)
|
||||
return;
|
||||
|
||||
PX_CHECK_AND_RETURN(!(rb->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC), "PxVehicleWriteWheelLocalPoseToPhysXWheelShape: shape is attached to a kinematic actor. This is not supported");
|
||||
|
||||
//Local pose in actor frame.
|
||||
const PxTransform& localPoseCMassFrame = wheelLocalPose*wheelShapeLocalPose;
|
||||
const PxTransform cmassLocalPose = rb->getCMassLocalPose();
|
||||
const PxTransform localPoseActorFrame = cmassLocalPose * localPoseCMassFrame;
|
||||
|
||||
//Apply the local pose to the shape.
|
||||
shape->setLocalPose(localPoseActorFrame);
|
||||
}
|
||||
|
||||
void PxVehicleWriteRigidBodyStateToPhysXActor
|
||||
(const PxVehiclePhysXActorUpdateMode::Enum updateMode,
|
||||
const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxReal dt,
|
||||
PxRigidBody& rb)
|
||||
{
|
||||
PX_CHECK_AND_RETURN(!(rb.getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC), "PxVehicleWriteRigidBodyStateToPhysXActor: physxActor is kinematic. This is not supported");
|
||||
|
||||
PxRigidDynamic* rd = rb.is<PxRigidDynamic>();
|
||||
PxArticulationLink* link = rb.is<PxArticulationLink>();
|
||||
PX_ASSERT(rd || link);
|
||||
|
||||
if(rb.getScene() && // check for scene to support immediate mode style vehicles
|
||||
((rd && rd->isSleeping()) || (link && link->getArticulation().isSleeping())))
|
||||
{
|
||||
// note: sort of a safety mechanism to be able to keep running the full vehicle pipeline
|
||||
// even if the physx actor fell asleep. Without it, the vehicle state can drift from
|
||||
// physx actor state in the course of multiple simulation steps up to the point
|
||||
// where the physx actor suddenly wakes up.
|
||||
return;
|
||||
}
|
||||
|
||||
switch (updateMode)
|
||||
{
|
||||
case PxVehiclePhysXActorUpdateMode::eAPPLY_VELOCITY:
|
||||
{
|
||||
PX_ASSERT(rd);
|
||||
rd->setLinearVelocity(rigidBodyState.linearVelocity, false);
|
||||
rd->setAngularVelocity(rigidBodyState.angularVelocity, false);
|
||||
}
|
||||
break;
|
||||
case PxVehiclePhysXActorUpdateMode::eAPPLY_ACCELERATION:
|
||||
{
|
||||
const PxVec3 linAccel = (rigidBodyState.linearVelocity - rigidBodyState.previousLinearVelocity)/dt;
|
||||
const PxVec3 angAccel = (rigidBodyState.angularVelocity - rigidBodyState.previousAngularVelocity)/dt;
|
||||
if (rd)
|
||||
{
|
||||
rd->addForce(linAccel, PxForceMode::eACCELERATION, false);
|
||||
rd->addTorque(angAccel, PxForceMode::eACCELERATION, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(link);
|
||||
link->addForce(linAccel, PxForceMode::eACCELERATION, false);
|
||||
link->addTorque(angAccel, PxForceMode::eACCELERATION, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
188
engine/third_party/physx/source/physxvehicle/src/physxActor/VhPhysXActorHelpers.cpp
vendored
Normal file
188
engine/third_party/physx/source/physxvehicle/src/physxActor/VhPhysXActorHelpers.cpp
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyParams.h"
|
||||
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionHelpers.h"
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionParams.h"
|
||||
|
||||
#include "vehicle2/physxActor/PxVehiclePhysXActorStates.h"
|
||||
#include "vehicle2/physxActor/PxVehiclePhysXActorHelpers.h"
|
||||
|
||||
#include "vehicle2/wheel/PxVehicleWheelParams.h"
|
||||
|
||||
#include "cooking/PxCooking.h"
|
||||
#include "PxPhysics.h"
|
||||
#include "PxRigidDynamic.h"
|
||||
#include "PxArticulationReducedCoordinate.h"
|
||||
#include "PxArticulationLink.h"
|
||||
#include "PxScene.h"
|
||||
#include "extensions/PxDefaultStreams.h"
|
||||
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
void createShapes(
|
||||
const PxVehicleFrame& vehicleFrame,
|
||||
const PxVehiclePhysXRigidActorShapeParams& rigidActorShapeParams,
|
||||
const PxVehiclePhysXWheelParams& wheelParams, const PxVehiclePhysXWheelShapeParams& wheelShapeParams,
|
||||
PxRigidBody* rd,
|
||||
PxPhysics& physics, const PxCookingParams& params,
|
||||
PxVehiclePhysXActor& vehiclePhysXActor)
|
||||
{
|
||||
//Create a shape for the vehicle body.
|
||||
{
|
||||
PxShape* shape = physics.createShape(rigidActorShapeParams.geometry, rigidActorShapeParams.material, true);
|
||||
shape->setLocalPose(rigidActorShapeParams.localPose);
|
||||
shape->setFlags(rigidActorShapeParams.flags);
|
||||
shape->setSimulationFilterData(rigidActorShapeParams.simulationFilterData);
|
||||
shape->setQueryFilterData(rigidActorShapeParams.queryFilterData);
|
||||
rd->attachShape(*shape);
|
||||
shape->release();
|
||||
}
|
||||
|
||||
//Create shapes for wheels.
|
||||
for (PxU32 i = 0; i < wheelParams.axleDescription.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = wheelParams.axleDescription.wheelIdsInAxleOrder[i];
|
||||
const PxF32 radius = wheelParams.wheelParams[wheelId].radius;
|
||||
const PxF32 halfWidth = wheelParams.wheelParams[wheelId].halfWidth;
|
||||
|
||||
PxVec3 verts[32];
|
||||
for (PxU32 k = 0; k < 16; k++)
|
||||
{
|
||||
const PxF32 lng = radius * PxCos(k*2.0f*PxPi / 16.0f);
|
||||
const PxF32 lat = halfWidth;
|
||||
const PxF32 vrt = radius * PxSin(k*2.0f*PxPi / 16.0f);
|
||||
|
||||
const PxVec3 pos0 = vehicleFrame.getFrame()*PxVec3(lng, lat, vrt);
|
||||
const PxVec3 pos1 = vehicleFrame.getFrame()*PxVec3(lng, -lat, vrt);
|
||||
verts[2 * k + 0] = pos0;
|
||||
verts[2 * k + 1] = pos1;
|
||||
}
|
||||
|
||||
// Create descriptor for convex mesh
|
||||
PxConvexMeshDesc convexDesc;
|
||||
convexDesc.points.count = 32;
|
||||
convexDesc.points.stride = sizeof(PxVec3);
|
||||
convexDesc.points.data = verts;
|
||||
convexDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX;
|
||||
|
||||
PxConvexMesh* convexMesh = NULL;
|
||||
PxDefaultMemoryOutputStream buf;
|
||||
if (PxCookConvexMesh(params, convexDesc, buf))
|
||||
{
|
||||
PxDefaultMemoryInputData id(buf.getData(), buf.getSize());
|
||||
convexMesh = physics.createConvexMesh(id);
|
||||
}
|
||||
|
||||
PxConvexMeshGeometry convexMeshGeom(convexMesh);
|
||||
PxShape* wheelShape = physics.createShape(convexMeshGeom, wheelShapeParams.material, true);
|
||||
wheelShape->setFlags(wheelShapeParams.flags);
|
||||
wheelShape->setSimulationFilterData(wheelShapeParams.simulationFilterData);
|
||||
wheelShape->setQueryFilterData(wheelShapeParams.queryFilterData);
|
||||
|
||||
rd->attachShape(*wheelShape);
|
||||
wheelShape->release();
|
||||
convexMesh->release();
|
||||
|
||||
vehiclePhysXActor.wheelShapes[wheelId] = wheelShape;
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehiclePhysXActorCreate
|
||||
(const PxVehicleFrame& vehicleFrame,
|
||||
const PxVehiclePhysXRigidActorParams& rigidActorParams, const PxTransform& rigidActorCmassLocalPose,
|
||||
const PxVehiclePhysXRigidActorShapeParams& rigidActorShapeParams,
|
||||
const PxVehiclePhysXWheelParams& wheelParams, const PxVehiclePhysXWheelShapeParams& wheelShapeParams,
|
||||
PxPhysics& physics, const PxCookingParams& params,
|
||||
PxVehiclePhysXActor& vehiclePhysXActor)
|
||||
{
|
||||
PxRigidDynamic* rd = physics.createRigidDynamic(PxTransform(PxIdentity));
|
||||
vehiclePhysXActor.rigidBody = rd;
|
||||
PxVehiclePhysXActorConfigure(rigidActorParams, rigidActorCmassLocalPose, *rd);
|
||||
createShapes(vehicleFrame, rigidActorShapeParams, wheelParams, wheelShapeParams, rd, physics, params, vehiclePhysXActor);
|
||||
}
|
||||
|
||||
void PxVehiclePhysXActorConfigure
|
||||
(const PxVehiclePhysXRigidActorParams& rigidActorParams, const PxTransform& rigidActorCmassLocalPose,
|
||||
PxRigidBody& rigidBody)
|
||||
{
|
||||
rigidBody.setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, false);
|
||||
rigidBody.setCMassLocalPose(rigidActorCmassLocalPose);
|
||||
rigidBody.setMass(rigidActorParams.rigidBodyParams.mass);
|
||||
rigidBody.setMassSpaceInertiaTensor(rigidActorParams.rigidBodyParams.moi);
|
||||
rigidBody.setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true);
|
||||
rigidBody.setName(rigidActorParams.physxActorName);
|
||||
}
|
||||
|
||||
void PxVehiclePhysXArticulationLinkCreate
|
||||
(const PxVehicleFrame& vehicleFrame,
|
||||
const PxVehiclePhysXRigidActorParams& rigidActorParams, const PxTransform& rigidActorCmassLocalPose,
|
||||
const PxVehiclePhysXRigidActorShapeParams& rigidActorShapeParams,
|
||||
const PxVehiclePhysXWheelParams& wheelParams, const PxVehiclePhysXWheelShapeParams& wheelShapeParams,
|
||||
PxPhysics& physics, const PxCookingParams& params,
|
||||
PxVehiclePhysXActor& vehiclePhysXActor)
|
||||
{
|
||||
PxArticulationReducedCoordinate* art = physics.createArticulationReducedCoordinate();
|
||||
PxArticulationLink* link = art->createLink(NULL, PxTransform(PxIdentity));
|
||||
vehiclePhysXActor.rigidBody = link;
|
||||
PxVehiclePhysXActorConfigure(rigidActorParams, rigidActorCmassLocalPose, *link);
|
||||
createShapes(vehicleFrame, rigidActorShapeParams, wheelParams, wheelShapeParams, link, physics, params, vehiclePhysXActor);
|
||||
}
|
||||
|
||||
void PxVehiclePhysXActorDestroy
|
||||
(PxVehiclePhysXActor& vehiclePhysXActor)
|
||||
{
|
||||
PxRigidDynamic* rd = vehiclePhysXActor.rigidBody->is<PxRigidDynamic>();
|
||||
PxArticulationLink* link = vehiclePhysXActor.rigidBody->is<PxArticulationLink>();
|
||||
if(rd)
|
||||
{
|
||||
rd->release();
|
||||
vehiclePhysXActor.rigidBody = NULL;
|
||||
}
|
||||
else if(link)
|
||||
{
|
||||
PxArticulationReducedCoordinate& articulation = link->getArticulation();
|
||||
PxScene* scene = articulation.getScene();
|
||||
if(scene)
|
||||
{
|
||||
scene->removeArticulation(articulation);
|
||||
}
|
||||
articulation.release();
|
||||
vehiclePhysXActor.rigidBody = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
161
engine/third_party/physx/source/physxvehicle/src/physxConstraints/VhPhysXConstraintFunctions.cpp
vendored
Normal file
161
engine/third_party/physx/source/physxvehicle/src/physxConstraints/VhPhysXConstraintFunctions.cpp
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/physxConstraints/PxVehiclePhysXConstraintFunctions.h"
|
||||
#include "vehicle2/physxConstraints/PxVehiclePhysXConstraintHelpers.h"
|
||||
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyStates.h"
|
||||
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionParams.h"
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionStates.h"
|
||||
|
||||
#include "vehicle2/tire/PxVehicleTireStates.h"
|
||||
|
||||
#include "vehicle2/physxConstraints/PxVehiclePhysXConstraintStates.h"
|
||||
#include "vehicle2/physxConstraints/PxVehiclePhysXConstraintParams.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
|
||||
PX_FORCE_INLINE PxVec3 computeAngular
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehicleSuspensionComplianceState& suspComplianceState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxVec3& direction)
|
||||
{
|
||||
const PxVec3 cmOffset = rigidBodyState.pose.rotate(suspParams.suspensionAttachment.transform(suspComplianceState.tireForceAppPoint));
|
||||
const PxVec3 angular = cmOffset.cross(direction);
|
||||
// note: not normalized on purpose. The angular component should hold the raw cross product as that
|
||||
// is needed for the type of constraint we want to set up (see vehicleConstraintSolverPrep).
|
||||
return angular;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxVec3 computeTireAngular
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehicleSuspensionComplianceState& suspComplianceState, const PxVehicleTireDirectionState& trDirState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxVehicleTireDirectionModes::Enum direction)
|
||||
{
|
||||
return computeAngular(suspParams, suspComplianceState, rigidBodyState, trDirState.directions[direction]);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxVec3 computeSuspAngular
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehicleSuspensionComplianceState& suspComplianceState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxVec3& direction)
|
||||
{
|
||||
return computeAngular(suspParams, suspComplianceState, rigidBodyState, direction);
|
||||
}
|
||||
|
||||
void PxVehiclePhysXConstraintStatesUpdate
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehiclePhysXSuspensionLimitConstraintParams& suspensionLimitParams,
|
||||
const PxVehicleSuspensionState& suspState, const PxVehicleSuspensionComplianceState& suspComplianceState,
|
||||
const PxVec3& groundPlaneNormal,
|
||||
const PxReal tireStickyDampingLong, const PxReal tireStickyDampingLat,
|
||||
const PxVehicleTireDirectionState& trDirState, const PxVehicleTireStickyState& trStickyState,
|
||||
const PxVehicleRigidBodyState& rigidBodyState,
|
||||
PxVehiclePhysXConstraintState& cnstrtState)
|
||||
{
|
||||
cnstrtState.setToDefault();
|
||||
|
||||
//Sticky tire longitudinal
|
||||
{
|
||||
const bool isActive = trStickyState.activeStatus[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
cnstrtState.tireActiveStatus[PxVehicleTireDirectionModes::eLONGITUDINAL] = isActive;
|
||||
if (isActive)
|
||||
{
|
||||
cnstrtState.tireLinears[PxVehicleTireDirectionModes::eLONGITUDINAL] = trDirState.directions[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
cnstrtState.tireAngulars[PxVehicleTireDirectionModes::eLONGITUDINAL] = computeTireAngular(suspParams, suspComplianceState, trDirState, rigidBodyState, PxVehicleTireDirectionModes::eLONGITUDINAL);
|
||||
cnstrtState.tireDamping[PxVehicleTireDirectionModes::eLONGITUDINAL] = tireStickyDampingLong;
|
||||
}
|
||||
}
|
||||
|
||||
//Sticky tire lateral
|
||||
{
|
||||
const bool isActive = trStickyState.activeStatus[PxVehicleTireDirectionModes::eLATERAL];
|
||||
cnstrtState.tireActiveStatus[PxVehicleTireDirectionModes::eLATERAL] = isActive;
|
||||
if (isActive)
|
||||
{
|
||||
cnstrtState.tireLinears[PxVehicleTireDirectionModes::eLATERAL] = trDirState.directions[PxVehicleTireDirectionModes::eLATERAL];
|
||||
cnstrtState.tireAngulars[PxVehicleTireDirectionModes::eLATERAL] = computeTireAngular(suspParams, suspComplianceState, trDirState, rigidBodyState, PxVehicleTireDirectionModes::eLATERAL);
|
||||
cnstrtState.tireDamping[PxVehicleTireDirectionModes::eLATERAL] = tireStickyDampingLat;
|
||||
}
|
||||
}
|
||||
|
||||
//Suspension limit
|
||||
{
|
||||
if (suspState.separation >= 0.0f || PxVehiclePhysXSuspensionLimitConstraintParams::eNONE == suspensionLimitParams.directionForSuspensionLimitConstraint)
|
||||
{
|
||||
cnstrtState.suspActiveStatus = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// To maintain the wheel on the ground plane, the suspension is required to compress beyond the suspension compression limit
|
||||
// or expand beyond maximum droop (for example, top of wheel being in collision with something).
|
||||
// We manage the compression up to the limit with a suspension force.
|
||||
// Everything beyond the limits is managed with an impulse applied to the rigid body via a constraint.
|
||||
// The constraint attempts to resolve the geometric error declared in the separation state.
|
||||
// We have two choices:
|
||||
// 1) apply the impulse along the suspension dir (more like the effect of a bump stop spring)
|
||||
// 2) apply the impulse along the ground normal (more like the effect of a real tire's contact wtih the ground).
|
||||
if (PxVehiclePhysXSuspensionLimitConstraintParams::eROAD_GEOMETRY_NORMAL == suspensionLimitParams.directionForSuspensionLimitConstraint)
|
||||
{
|
||||
cnstrtState.suspActiveStatus = true;
|
||||
cnstrtState.suspGeometricError = suspState.separation;
|
||||
cnstrtState.suspLinear = groundPlaneNormal;
|
||||
cnstrtState.suspAngular = computeSuspAngular(suspParams, suspComplianceState, rigidBodyState, groundPlaneNormal);
|
||||
cnstrtState.restitution = suspensionLimitParams.restitution;
|
||||
}
|
||||
else
|
||||
{
|
||||
const PxVec3 suspDirWorldFrame = rigidBodyState.pose.rotate(suspParams.suspensionTravelDir);
|
||||
const PxF32 projection = groundPlaneNormal.dot(suspDirWorldFrame);
|
||||
if (projection != 0.0f)
|
||||
{
|
||||
cnstrtState.suspActiveStatus = true;
|
||||
cnstrtState.suspGeometricError = suspState.separation;
|
||||
const PxVec3 suspLinear = suspDirWorldFrame * PxSign(projection);
|
||||
cnstrtState.suspLinear = suspLinear;
|
||||
cnstrtState.suspAngular = computeSuspAngular(suspParams, suspComplianceState, rigidBodyState, suspLinear);
|
||||
cnstrtState.restitution = suspensionLimitParams.restitution;
|
||||
}
|
||||
else
|
||||
{
|
||||
cnstrtState.suspActiveStatus = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
112
engine/third_party/physx/source/physxvehicle/src/physxConstraints/VhPhysXConstraintHelpers.cpp
vendored
Normal file
112
engine/third_party/physx/source/physxvehicle/src/physxConstraints/VhPhysXConstraintHelpers.cpp
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxAllocator.h"
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/physxConstraints/PxVehiclePhysXConstraintStates.h"
|
||||
#include "vehicle2/physxConstraints/PxVehiclePhysXConstraintHelpers.h"
|
||||
|
||||
#include "vehicle2/physxActor/PxVehiclePhysXActorStates.h"
|
||||
|
||||
#include "PxConstraintDesc.h"
|
||||
#include "PxConstraint.h"
|
||||
#include "PxPhysics.h"
|
||||
#include "PxRigidDynamic.h"
|
||||
#include "PxArticulationLink.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
PxConstraintShaderTable gVehicleConstraintTable =
|
||||
{
|
||||
vehicleConstraintSolverPrep,
|
||||
visualiseVehicleConstraint,
|
||||
PxConstraintFlag::Enum(0)
|
||||
};
|
||||
|
||||
void PxVehicleConstraintsCreate(
|
||||
const PxVehicleAxleDescription& axleDescription,
|
||||
PxPhysics& physics, PxRigidBody& physxActor,
|
||||
PxVehiclePhysXConstraints& vehicleConstraints)
|
||||
{
|
||||
vehicleConstraints.setToDefault();
|
||||
|
||||
//Each PxConstraint has a limit of 12 1d constraints.
|
||||
//Each wheel has longitudinal, lateral and suspension limit degrees of freedom.
|
||||
//This sums up to 3 dofs per wheel and 12 dofs per 4 wheels.
|
||||
//4 wheels therefore equals 1 PxConstraint
|
||||
//Iterate over each block of 4 wheels and create a PxConstraints for each block of 4.
|
||||
PxU32 constraintIndex = 0;
|
||||
for(PxU32 i = 0; i < axleDescription.getNbWheels(); i+= PxVehiclePhysXConstraintLimits::eNB_WHEELS_PER_PXCONSTRAINT)
|
||||
{
|
||||
void* memory = PX_ALLOC(sizeof(PxVehicleConstraintConnector), PxVehicleConstraintConnector);
|
||||
PxVehicleConstraintConnector* pxConnector = PX_PLACEMENT_NEW(memory, PxVehicleConstraintConnector)(vehicleConstraints.constraintStates + i);
|
||||
PxConstraint* pxConstraint = physics.createConstraint(&physxActor, NULL, *pxConnector, gVehicleConstraintTable, sizeof(PxVehiclePhysXConstraintState)*PxVehiclePhysXConstraintLimits::eNB_WHEELS_PER_PXCONSTRAINT);
|
||||
vehicleConstraints.constraints[constraintIndex] = pxConstraint;
|
||||
vehicleConstraints.constraintConnectors[constraintIndex] = pxConnector;
|
||||
constraintIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleConstraintsDirtyStateUpdate
|
||||
(PxVehiclePhysXConstraints& vehicleConstraints)
|
||||
{
|
||||
for (PxU32 i = 0; i < PxVehiclePhysXConstraintLimits::eNB_CONSTRAINTS_PER_VEHICLE; i++)
|
||||
{
|
||||
if (vehicleConstraints.constraints[i])
|
||||
{
|
||||
vehicleConstraints.constraints[i]->markDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleConstraintsDestroy(
|
||||
PxVehiclePhysXConstraints& vehicleConstraints)
|
||||
{
|
||||
for (PxU32 i = 0; i < PxVehiclePhysXConstraintLimits::eNB_CONSTRAINTS_PER_VEHICLE; i++)
|
||||
{
|
||||
if (vehicleConstraints.constraints[i])
|
||||
{
|
||||
vehicleConstraints.constraints[i]->release();
|
||||
vehicleConstraints.constraints[i] = NULL;
|
||||
}
|
||||
|
||||
if (vehicleConstraints.constraintConnectors[i])
|
||||
{
|
||||
vehicleConstraints.constraintConnectors[i]->~PxVehicleConstraintConnector();
|
||||
PX_FREE(vehicleConstraints.constraintConnectors[i]);
|
||||
vehicleConstraints.constraintConnectors[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
231
engine/third_party/physx/source/physxvehicle/src/physxRoadGeometry/VhPhysXRoadGeometryFunctions.cpp
vendored
Normal file
231
engine/third_party/physx/source/physxvehicle/src/physxRoadGeometry/VhPhysXRoadGeometryFunctions.cpp
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/roadGeometry/PxVehicleRoadGeometryState.h"
|
||||
#include "vehicle2/physxRoadGeometry/PxVehiclePhysXRoadGeometryFunctions.h"
|
||||
#include "vehicle2/physxRoadGeometry/PxVehiclePhysXRoadGeometryParams.h"
|
||||
#include "vehicle2/physxRoadGeometry/PxVehiclePhysXRoadGeometryState.h"
|
||||
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyStates.h"
|
||||
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionHelpers.h"
|
||||
|
||||
#include "extensions/PxRigidBodyExt.h"
|
||||
|
||||
#include "PxScene.h"
|
||||
#include "PxShape.h"
|
||||
#include "PxRigidActor.h"
|
||||
#include "PxMaterial.h"
|
||||
#include "geometry/PxMeshScale.h"
|
||||
#include "geometry/PxConvexMeshGeometry.h"
|
||||
#include "geometry/PxGeometryQuery.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
PX_FORCE_INLINE PxF32 computeMaterialFriction(const PxShape* hitShape, const PxU32 hitFaceIndex,
|
||||
const PxVehiclePhysXMaterialFrictionParams& materialFrictionParams, PxMaterial*& hitMaterial)
|
||||
{
|
||||
PxBaseMaterial* baseMaterial = hitShape->getMaterialFromInternalFaceIndex(hitFaceIndex);
|
||||
PX_ASSERT(!baseMaterial || baseMaterial->getConcreteType()==PxConcreteType::eMATERIAL);
|
||||
hitMaterial = static_cast<PxMaterial*>(baseMaterial);
|
||||
PxReal hitFriction = materialFrictionParams.defaultFriction;
|
||||
for(PxU32 i = 0; i < materialFrictionParams.nbMaterialFrictions; i++)
|
||||
{
|
||||
if(materialFrictionParams.materialFrictions[i].material == hitMaterial)
|
||||
{
|
||||
hitFriction = materialFrictionParams.materialFrictions[i].friction;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hitFriction;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxVec3 computeVelocity(const PxRigidActor& actor, const PxVec3& hitPoint)
|
||||
{
|
||||
return actor.is<PxRigidBody>() ? PxRigidBodyExt::getVelocityAtPos(*actor.is<PxRigidBody>(), hitPoint) : PxVec3(PxZero);
|
||||
}
|
||||
|
||||
template<typename THitBuffer>
|
||||
PX_FORCE_INLINE void copyHitInfo(const THitBuffer& hitBuffer, PxMaterial* hitMaterial,
|
||||
PxVehiclePhysXRoadGeometryQueryState& physxRoadGeometryState)
|
||||
{
|
||||
physxRoadGeometryState.actor = hitBuffer.actor;
|
||||
physxRoadGeometryState.shape = hitBuffer.shape;
|
||||
physxRoadGeometryState.material = hitMaterial;
|
||||
physxRoadGeometryState.hitPosition = hitBuffer.position;
|
||||
}
|
||||
|
||||
void PxVehiclePhysXRoadGeometryQueryUpdate
|
||||
(const PxVehicleWheelParams& wheelParams, const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehiclePhysXRoadGeometryQueryType::Enum queryType,
|
||||
PxQueryFilterCallback* filterCallback, const PxQueryFilterData& filterData,
|
||||
const PxVehiclePhysXMaterialFrictionParams& materialFrictionParams,
|
||||
const PxF32 steerAngle, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxScene& scene, const PxConvexMesh* unitCylinderSweepMesh,
|
||||
const PxVehicleFrame& frame,
|
||||
PxVehicleRoadGeometryState& roadGeomState,
|
||||
PxVehiclePhysXRoadGeometryQueryState* physxRoadGeometryState)
|
||||
{
|
||||
if(PxVehiclePhysXRoadGeometryQueryType::eRAYCAST == queryType)
|
||||
{
|
||||
//Assume no hits until we know otherwise.
|
||||
roadGeomState.setToDefault();
|
||||
|
||||
//Compute the start pos, dir and length of raycast.
|
||||
PxVec3 v, w;
|
||||
PxF32 dist;
|
||||
PxVehicleComputeSuspensionRaycast(frame, wheelParams, suspParams, steerAngle, rigidBodyState.pose, v, w, dist);
|
||||
|
||||
//Perform the raycast.
|
||||
PxRaycastBuffer buff;
|
||||
scene.raycast(v, w, dist, buff, PxHitFlag::eDEFAULT, filterData, filterCallback);
|
||||
|
||||
//Process the raycast result.
|
||||
if(buff.hasBlock && buff.block.distance != 0.0f)
|
||||
{
|
||||
const PxPlane hitPlane(v + w * buff.block.distance, buff.block.normal);
|
||||
roadGeomState.plane = hitPlane;
|
||||
roadGeomState.hitState = true;
|
||||
PxMaterial* hitMaterial;
|
||||
roadGeomState.friction = computeMaterialFriction(buff.block.shape, buff.block.faceIndex, materialFrictionParams,
|
||||
hitMaterial);
|
||||
roadGeomState.velocity = computeVelocity(*buff.block.actor, buff.block.position);
|
||||
|
||||
if (physxRoadGeometryState)
|
||||
{
|
||||
copyHitInfo(buff.block, hitMaterial, *physxRoadGeometryState);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (physxRoadGeometryState)
|
||||
physxRoadGeometryState->setToDefault();
|
||||
}
|
||||
}
|
||||
else if(PxVehiclePhysXRoadGeometryQueryType::eSWEEP == queryType)
|
||||
{
|
||||
PX_ASSERT(unitCylinderSweepMesh);
|
||||
|
||||
//Assume no hits until we know otherwise.
|
||||
roadGeomState.setToDefault();
|
||||
|
||||
//Compute the start pose, dir and length of sweep.
|
||||
PxTransform T;
|
||||
PxVec3 w;
|
||||
PxF32 dist;
|
||||
PxVehicleComputeSuspensionSweep(frame, suspParams, steerAngle, rigidBodyState.pose, T, w, dist);
|
||||
|
||||
//Scale the unit cylinder.
|
||||
const PxVec3 scale = PxVehicleComputeTranslation(frame, wheelParams.radius, wheelParams.halfWidth, wheelParams.radius).abs();
|
||||
const PxMeshScale meshScale(scale, PxQuat(PxIdentity));
|
||||
const PxConvexMeshGeometry convMeshGeom(const_cast<PxConvexMesh*>(unitCylinderSweepMesh), meshScale);
|
||||
|
||||
//Perform the sweep.
|
||||
PxSweepBuffer buff;
|
||||
scene.sweep(convMeshGeom, T, w, dist, buff, PxHitFlag::eDEFAULT | PxHitFlag::eMTD, filterData, filterCallback);
|
||||
|
||||
//Process the sweep result.
|
||||
if (buff.hasBlock && buff.block.distance >= 0.0f)
|
||||
{
|
||||
//Sweep started outside scene geometry.
|
||||
const PxPlane hitPlane(buff.block.position, buff.block.normal);
|
||||
roadGeomState.plane = hitPlane;
|
||||
roadGeomState.hitState = true;
|
||||
PxMaterial* hitMaterial;
|
||||
roadGeomState.friction = computeMaterialFriction(buff.block.shape, buff.block.faceIndex, materialFrictionParams,
|
||||
hitMaterial);
|
||||
roadGeomState.velocity = computeVelocity(*buff.block.actor, buff.block.position);
|
||||
|
||||
if (physxRoadGeometryState)
|
||||
{
|
||||
copyHitInfo(buff.block, hitMaterial, *physxRoadGeometryState);
|
||||
}
|
||||
}
|
||||
else if (buff.hasBlock && buff.block.distance < 0.0f)
|
||||
{
|
||||
//The sweep started inside scene geometry.
|
||||
//We want to have another go but this time starting outside the hit geometry because this is the most reliable
|
||||
//way to get a hit plane.
|
||||
//-buff.block.distance is the distance we need to move along buff.block.normal to be outside the hit geometry.
|
||||
//Note that buff.block.distance can be a vanishingly small number. Moving along the normal by a vanishingly
|
||||
//small number might not push us out of overlap due to numeric precision of the overlap test.
|
||||
//We want to move a numerically significant distance to guarantee that we change the overlap status
|
||||
//at the start pose of the sweep.
|
||||
//We achieve this by choosing a minimum translation that is numerically significant.
|
||||
//Any number will do but we choose the wheel radius because this ought to be a numerically significant value.
|
||||
//We're only sweeping against the hit shape and not against the scene
|
||||
//so we don't risk hitting other stuff by moving a numerically significant distance.
|
||||
const PxVec3 unitDir = -buff.block.normal;
|
||||
const PxF32 maxDist = PxMax(wheelParams.radius, -buff.block.distance);
|
||||
const PxGeometry& geom0 = convMeshGeom;
|
||||
const PxTransform pose0(T.p + buff.block.normal*(maxDist*1.01f), T.q);
|
||||
const PxGeometry& geom1 = buff.block.shape->getGeometry();
|
||||
const PxTransform pose1 = buff.block.actor->getGlobalPose()*buff.block.shape->getLocalPose();
|
||||
PxGeomSweepHit buff2;
|
||||
const bool b2 = PxGeometryQuery::sweep(
|
||||
unitDir, maxDist*1.02f,
|
||||
geom0, pose0, geom1, pose1, buff2, PxHitFlag::eDEFAULT | PxHitFlag::eMTD);
|
||||
|
||||
if (b2 && buff2.distance > 0.0f)
|
||||
{
|
||||
//Sweep started outside scene geometry.
|
||||
const PxPlane hitPlane(buff2.position, buff2.normal);
|
||||
roadGeomState.plane = hitPlane;
|
||||
roadGeomState.hitState = true;
|
||||
PxMaterial* hitMaterial;
|
||||
roadGeomState.friction = computeMaterialFriction(buff.block.shape, buff.block.faceIndex, materialFrictionParams,
|
||||
hitMaterial);
|
||||
roadGeomState.velocity = computeVelocity(*buff.block.actor, buff.block.position);
|
||||
|
||||
if (physxRoadGeometryState)
|
||||
{
|
||||
copyHitInfo(buff.block, hitMaterial, *physxRoadGeometryState);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (physxRoadGeometryState)
|
||||
physxRoadGeometryState->setToDefault();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (physxRoadGeometryState)
|
||||
physxRoadGeometryState->setToDefault();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
@@ -0,0 +1,87 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/physxRoadGeometry/PxVehiclePhysXRoadGeometryHelpers.h"
|
||||
|
||||
#include "cooking/PxConvexMeshDesc.h"
|
||||
#include "cooking/PxCooking.h"
|
||||
#include "extensions/PxDefaultStreams.h"
|
||||
#include "PxPhysics.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
PxConvexMesh* PxVehicleUnitCylinderSweepMeshCreate
|
||||
(const PxVehicleFrame& runtimeFrame, PxPhysics& physics, const PxCookingParams& params)
|
||||
{
|
||||
const PxMat33 mat33 = runtimeFrame.getFrame();
|
||||
const PxQuat frame(mat33);
|
||||
const PxReal radius = 1.0f;
|
||||
const PxReal halfWidth = 1.0f;
|
||||
|
||||
#define NB_CIRCUMFERENCE_POINTS 64
|
||||
PxVec3 points[2 * NB_CIRCUMFERENCE_POINTS];
|
||||
for (PxU32 i = 0; i < NB_CIRCUMFERENCE_POINTS; i++)
|
||||
{
|
||||
const PxF32 cosTheta = PxCos(i * PxPi * 2.0f / float(NB_CIRCUMFERENCE_POINTS));
|
||||
const PxF32 sinTheta = PxSin(i * PxPi * 2.0f / float(NB_CIRCUMFERENCE_POINTS));
|
||||
const PxF32 x = radius * cosTheta;
|
||||
const PxF32 z = radius * sinTheta;
|
||||
points[2 * i + 0] = frame.rotate(PxVec3(x, -halfWidth, z));
|
||||
points[2 * i + 1] = frame.rotate(PxVec3(x, +halfWidth, z));
|
||||
}
|
||||
|
||||
// Create descriptor for convex mesh
|
||||
PxConvexMeshDesc convexDesc;
|
||||
convexDesc.points.count = sizeof(points)/sizeof(PxVec3);
|
||||
convexDesc.points.stride = sizeof(PxVec3);
|
||||
convexDesc.points.data = points;
|
||||
convexDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX;
|
||||
|
||||
PxConvexMesh* convexMesh = NULL;
|
||||
PxDefaultMemoryOutputStream buf;
|
||||
if (PxCookConvexMesh(params, convexDesc, buf))
|
||||
{
|
||||
PxDefaultMemoryInputData id(buf.getData(), buf.getSize());
|
||||
convexMesh = physics.createConvexMesh(id);
|
||||
}
|
||||
|
||||
return convexMesh;
|
||||
}
|
||||
|
||||
void PxVehicleUnitCylinderSweepMeshDestroy(PxConvexMesh* mesh)
|
||||
{
|
||||
mesh->release();
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
168
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdAttributeHandles.h
vendored
Normal file
168
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdAttributeHandles.h
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vehicle2/pvd/PxVehiclePvdHelpers.h"
|
||||
#include "VhPvdWriter.h"
|
||||
|
||||
|
||||
#if !PX_DOXYGEN
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
#endif
|
||||
|
||||
struct PxVehiclePvdAttributeHandles
|
||||
{
|
||||
#if PX_SUPPORT_OMNI_PVD
|
||||
|
||||
/////////////////////
|
||||
//RIGID BODY
|
||||
/////////////////////////
|
||||
|
||||
RigidBodyParams rigidBodyParams;
|
||||
RigidBodyState rigidBodyState;
|
||||
|
||||
/////////////////////////
|
||||
//SUSP STATE CALC PARAMS
|
||||
/////////////////////////
|
||||
|
||||
SuspStateCalcParams suspStateCalcParams;
|
||||
|
||||
/////////////////////////
|
||||
//CONTROL ATTRIBUTES
|
||||
/////////////////////////
|
||||
|
||||
WheelResponseParams brakeCommandResponseParams;
|
||||
WheelResponseParams steerCommandResponseParams;
|
||||
AckermannParams ackermannParams;
|
||||
WheelResponseStates brakeCommandResponseStates;
|
||||
WheelResponseStates steerCommandResponseStates;
|
||||
|
||||
/////////////////////////////////
|
||||
//WHEEL ATTACHMENT ATTRIBUTES
|
||||
/////////////////////////////////
|
||||
|
||||
WheelParams wheelParams;
|
||||
WheelActuationState wheelActuationState;
|
||||
WheelRigidBody1dState wheelRigidBody1dState;
|
||||
WheelLocalPoseState wheelLocalPoseState;
|
||||
RoadGeometryState roadGeomState;
|
||||
SuspParams suspParams;
|
||||
SuspCompParams suspCompParams;
|
||||
SuspForceParams suspForceParams;
|
||||
SuspState suspState;
|
||||
SuspCompState suspCompState;
|
||||
SuspForce suspForce;
|
||||
TireParams tireParams;
|
||||
TireDirectionState tireDirectionState;
|
||||
TireSpeedState tireSpeedState;
|
||||
TireSlipState tireSlipState;
|
||||
TireStickyState tireStickyState;
|
||||
TireGripState tireGripState;
|
||||
TireCamberState tireCamberState;
|
||||
TireForce tireForce;
|
||||
WheelAttachment wheelAttachment;
|
||||
|
||||
///////////////////////
|
||||
//ANTIROLL BARS
|
||||
///////////////////////
|
||||
|
||||
AntiRollParams antiRollParams;
|
||||
AntiRollForce antiRollForce;
|
||||
|
||||
///////////////////////////////////
|
||||
//DIRECT DRIVETRAIN
|
||||
///////////////////////////////////
|
||||
|
||||
DirectDriveCommandState directDriveCommandState;
|
||||
DirectDriveTransmissionCommandState directDriveTransmissionCommandState;
|
||||
WheelResponseParams directDriveThrottleCommandResponseParams;
|
||||
DirectDriveThrottleResponseState directDriveThrottleCommandResponseState;
|
||||
DirectDrivetrain directDrivetrain;
|
||||
|
||||
//////////////////////////////////
|
||||
//ENGINE DRIVETRAIN ATTRIBUTES
|
||||
//////////////////////////////////
|
||||
|
||||
EngineDriveCommandState engineDriveCommandState;
|
||||
EngineDriveTransmissionCommandState engineDriveTransmissionCommandState;
|
||||
TankDriveTransmissionCommandState tankDriveTransmissionCommandState;
|
||||
ClutchResponseParams clutchCommandResponseParams;
|
||||
ClutchParams clutchParams;
|
||||
EngineParams engineParams;
|
||||
GearboxParams gearboxParams;
|
||||
AutoboxParams autoboxParams;
|
||||
MultiWheelDiffParams multiwheelDiffParams;
|
||||
FourWheelDiffParams fourwheelDiffParams;
|
||||
TankDiffParams tankDiffParams;
|
||||
ClutchResponseState clutchResponseState;
|
||||
ThrottleResponseState throttleResponseState;
|
||||
EngineState engineState;
|
||||
GearboxState gearboxState;
|
||||
AutoboxState autoboxState;
|
||||
DiffState diffState;
|
||||
ClutchSlipState clutchSlipState;
|
||||
EngineDrivetrain engineDrivetrain;
|
||||
|
||||
//////////////////////////////////////
|
||||
//PHYSX WHEEL ATTACHMENT INTEGRATION
|
||||
//////////////////////////////////////
|
||||
|
||||
PhysXSuspensionLimitConstraintParams physxSuspLimitConstraintParams;
|
||||
PhysXWheelShape physxWheelShape;
|
||||
PhysXRoadGeomState physxRoadGeomState;
|
||||
PhysXConstraintState physxConstraintState;
|
||||
PhysXMaterialFriction physxMaterialFriction;
|
||||
PhysXWheelAttachment physxWheelAttachment;
|
||||
|
||||
////////////////////
|
||||
//PHYSX RIGID ACTOR
|
||||
////////////////////
|
||||
|
||||
PhysXRoadGeometryQueryParams physxRoadGeometryQueryParams;
|
||||
PhysXRigidActor physxRigidActor;
|
||||
PhysXSteerState physxSteerState;
|
||||
|
||||
//////////////////////////////////
|
||||
//VEHICLE ATTRIBUTES
|
||||
//////////////////////////////////
|
||||
|
||||
Vehicle vehicle;
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#if !PX_DOXYGEN
|
||||
} // namespace vehicle2
|
||||
} // namespace physx
|
||||
#endif
|
||||
|
||||
1889
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdFunctions.cpp
vendored
Normal file
1889
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdFunctions.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
446
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdHelpers.cpp
vendored
Normal file
446
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdHelpers.cpp
vendored
Normal file
@@ -0,0 +1,446 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/pvd/PxVehiclePvdHelpers.h"
|
||||
#include "foundation/PxAllocatorCallback.h"
|
||||
#include "VhPvdAttributeHandles.h"
|
||||
#include "VhPvdObjectHandles.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
#if PX_SUPPORT_OMNI_PVD
|
||||
|
||||
///////////////////////////////
|
||||
//ATTRIBUTE REGISTRATION
|
||||
///////////////////////////////
|
||||
|
||||
PxVehiclePvdAttributeHandles* PxVehiclePvdAttributesCreate(PxAllocatorCallback& allocator, OmniPvdWriter& omniWriter)
|
||||
{
|
||||
PxVehiclePvdAttributeHandles* attributeHandles =
|
||||
reinterpret_cast<PxVehiclePvdAttributeHandles*>(
|
||||
allocator.allocate(sizeof(PxVehiclePvdAttributeHandles), "PxVehiclePvdAttributeHandles", PX_FL));
|
||||
PxMemZero(attributeHandles, sizeof(PxVehiclePvdAttributeHandles));
|
||||
|
||||
//Rigid body
|
||||
attributeHandles->rigidBodyParams = registerRigidBodyParams(omniWriter);
|
||||
attributeHandles->rigidBodyState = registerRigidBodyState(omniWriter);
|
||||
|
||||
//Susp state calc params.
|
||||
attributeHandles->suspStateCalcParams = registerSuspStateCalcParams(omniWriter);
|
||||
|
||||
//Controls
|
||||
attributeHandles->steerCommandResponseParams = registerSteerResponseParams(omniWriter);
|
||||
attributeHandles->brakeCommandResponseParams = registerBrakeResponseParams(omniWriter);
|
||||
attributeHandles->steerCommandResponseStates = registerSteerResponseStates(omniWriter);
|
||||
attributeHandles->brakeCommandResponseStates = registerBrakeResponseStates(omniWriter);
|
||||
attributeHandles->ackermannParams = registerAckermannParams(omniWriter);
|
||||
|
||||
//Wheel attachment
|
||||
attributeHandles->wheelParams = registerWheelParams(omniWriter);
|
||||
attributeHandles->wheelActuationState = registerWheelActuationState(omniWriter);
|
||||
attributeHandles->wheelRigidBody1dState = registerWheelRigidBody1dState(omniWriter);
|
||||
attributeHandles->wheelLocalPoseState = registerWheelLocalPoseState(omniWriter);
|
||||
attributeHandles->roadGeomState = registerRoadGeomState(omniWriter);
|
||||
attributeHandles->suspParams = registerSuspParams(omniWriter);
|
||||
attributeHandles->suspCompParams = registerSuspComplianceParams(omniWriter);
|
||||
attributeHandles->suspForceParams = registerSuspForceParams(omniWriter);
|
||||
attributeHandles->suspState = registerSuspState(omniWriter);
|
||||
attributeHandles->suspCompState = registerSuspComplianceState(omniWriter);
|
||||
attributeHandles->suspForce = registerSuspForce(omniWriter);
|
||||
attributeHandles->tireParams = registerTireParams(omniWriter);
|
||||
attributeHandles->tireDirectionState = registerTireDirectionState(omniWriter);
|
||||
attributeHandles->tireSpeedState = registerTireSpeedState(omniWriter);
|
||||
attributeHandles->tireSlipState = registerTireSlipState(omniWriter);
|
||||
attributeHandles->tireStickyState = registerTireStickyState(omniWriter);
|
||||
attributeHandles->tireGripState = registerTireGripState(omniWriter);
|
||||
attributeHandles->tireCamberState = registerTireCamberState(omniWriter);
|
||||
attributeHandles->tireForce = registerTireForce(omniWriter);
|
||||
attributeHandles->wheelAttachment = registerWheelAttachment(omniWriter);
|
||||
|
||||
//Antiroll
|
||||
attributeHandles->antiRollParams = registerAntiRollParams(omniWriter);
|
||||
attributeHandles->antiRollForce = registerAntiRollForce(omniWriter);
|
||||
|
||||
//Direct drivetrain
|
||||
attributeHandles->directDriveThrottleCommandResponseParams = registerDirectDriveThrottleResponseParams(omniWriter);
|
||||
attributeHandles->directDriveCommandState = registerDirectDriveCommandState(omniWriter);
|
||||
attributeHandles->directDriveTransmissionCommandState = registerDirectDriveTransmissionCommandState(omniWriter);
|
||||
attributeHandles->directDriveThrottleCommandResponseState = registerDirectDriveThrottleResponseState(omniWriter);
|
||||
attributeHandles->directDrivetrain = registerDirectDrivetrain(omniWriter);
|
||||
|
||||
//Engine drivetrain
|
||||
attributeHandles->engineDriveCommandState = registerEngineDriveCommandState(omniWriter);
|
||||
attributeHandles->engineDriveTransmissionCommandState = registerEngineDriveTransmissionCommandState(omniWriter);
|
||||
attributeHandles->tankDriveTransmissionCommandState = registerTankDriveTransmissionCommandState(omniWriter,
|
||||
attributeHandles->engineDriveTransmissionCommandState.CH);
|
||||
attributeHandles->clutchCommandResponseParams = registerClutchResponseParams(omniWriter);
|
||||
attributeHandles->clutchParams = registerClutchParams(omniWriter);
|
||||
attributeHandles->engineParams = registerEngineParams(omniWriter);
|
||||
attributeHandles->gearboxParams = registerGearboxParams(omniWriter);
|
||||
attributeHandles->autoboxParams = registerAutoboxParams(omniWriter);
|
||||
attributeHandles->multiwheelDiffParams = registerMultiWheelDiffParams(omniWriter);
|
||||
attributeHandles->fourwheelDiffParams = registerFourWheelDiffParams(omniWriter, attributeHandles->multiwheelDiffParams.CH);
|
||||
attributeHandles->tankDiffParams = registerTankDiffParams(omniWriter, attributeHandles->multiwheelDiffParams.CH);
|
||||
attributeHandles->clutchResponseState = registerClutchResponseState(omniWriter);
|
||||
attributeHandles->throttleResponseState = registerThrottleResponseState(omniWriter);
|
||||
attributeHandles->engineState = registerEngineState(omniWriter);
|
||||
attributeHandles->gearboxState = registerGearboxState(omniWriter);
|
||||
attributeHandles->autoboxState = registerAutoboxState(omniWriter);
|
||||
attributeHandles->diffState = registerDiffState(omniWriter);
|
||||
attributeHandles->clutchSlipState = registerClutchSlipState(omniWriter);
|
||||
attributeHandles->engineDrivetrain = registerEngineDrivetrain(omniWriter);
|
||||
|
||||
//Physx wheel attachment
|
||||
attributeHandles->physxSuspLimitConstraintParams = registerSuspLimitConstraintParams(omniWriter);
|
||||
attributeHandles->physxWheelShape = registerPhysXWheelShape(omniWriter);
|
||||
attributeHandles->physxRoadGeomState = registerPhysXRoadGeomState(omniWriter);
|
||||
attributeHandles->physxConstraintState = registerPhysXConstraintState(omniWriter);
|
||||
attributeHandles->physxWheelAttachment = registerPhysXWheelAttachment(omniWriter);
|
||||
attributeHandles->physxMaterialFriction = registerPhysXMaterialFriction(omniWriter);
|
||||
|
||||
//Physx rigid actor
|
||||
attributeHandles->physxRoadGeometryQueryParams = registerPhysXRoadGeometryQueryParams(omniWriter);
|
||||
attributeHandles->physxRigidActor = registerPhysXRigidActor(omniWriter);
|
||||
attributeHandles->physxSteerState = registerPhysXSteerState(omniWriter);
|
||||
|
||||
//Vehicle
|
||||
attributeHandles->vehicle = registerVehicle(omniWriter);
|
||||
|
||||
return attributeHandles;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
//ATTRIBUTE DESTRUCTION
|
||||
///////////////////////////////
|
||||
|
||||
void PxVehiclePvdAttributesRelease(PxAllocatorCallback& allocator, PxVehiclePvdAttributeHandles& attributeHandles)
|
||||
{
|
||||
allocator.deallocate(&attributeHandles);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
//OBJECT REGISTRATION
|
||||
////////////////////////////////////////
|
||||
|
||||
PxVehiclePvdObjectHandles* PxVehiclePvdObjectCreate
|
||||
(const PxU32 nbWheels, const PxU32 nbAntirolls, const PxU32 maxNbPhysXMaterialFrictions,
|
||||
const OmniPvdContextHandle contextHandle,
|
||||
PxAllocatorCallback& allocator)
|
||||
{
|
||||
const PxU32 byteSize =
|
||||
sizeof(PxVehiclePvdObjectHandles) +
|
||||
sizeof(OmniPvdObjectHandle)*nbWheels*(
|
||||
1 + //OmniPvdObjectHandle* wheelAttachmentOHs;
|
||||
1 + //OmniPvdObjectHandle* wheelParamsOHs;
|
||||
1 + //OmniPvdObjectHandle* wheelActuationStateOHs;
|
||||
1 + //OmniPvdObjectHandle* wheelRigidBody1dStateOHs;
|
||||
1 + //OmniPvdObjectHandle* wheelLocalPoseStateOHs;
|
||||
1 + //OmniPvdObjectHandle* roadGeomStateOHs;
|
||||
1 + //OmniPvdObjectHandle* suspParamsOHs;
|
||||
1 + //OmniPvdObjectHandle* suspCompParamsOHs;
|
||||
1 + //OmniPvdObjectHandle* suspForceParamsOHs;
|
||||
1 + //OmniPvdObjectHandle* suspStateOHs;
|
||||
1 + //OmniPvdObjectHandle* suspCompStateOHs;
|
||||
1 + //OmniPvdObjectHandle* suspForceOHs;
|
||||
1 + //OmniPvdObjectHandle* tireParamsOHs;
|
||||
1 + //OmniPvdObjectHandle* tireDirectionStateOHs;
|
||||
1 + //OmniPvdObjectHandle* tireSpeedStateOHs;
|
||||
1 + //OmniPvdObjectHandle* tireSlipStateOHs;
|
||||
1 + //OmniPvdObjectHandle* tireStickyStateOHs;
|
||||
1 + //OmniPvdObjectHandle* tireGripStateOHs;
|
||||
1 + //OmniPvdObjectHandle* tireCamberStateOHs;
|
||||
1 + //OmniPvdObjectHandle* tireForceOHs;
|
||||
1 + //OmniPvdObjectHandle* physxWheelAttachmentOHs;
|
||||
1 + //OmniPvdObjectHandle* physxWheelShapeOHs;
|
||||
1 + //OmniPvdObjectHandle* physxConstraintParamOHs;
|
||||
1 + //OmniPvdObjectHandle* physxConstraintStateOHs;
|
||||
1 + //OmniPvdObjectHandle* physxRoadGeomStateOHs;
|
||||
1 + //OmniPvdObjectHandle* physxMaterialFrictionSetOHs;
|
||||
maxNbPhysXMaterialFrictions + //OmniPvdObjectHandle* physxMaterialFrictionOHs;
|
||||
1) + //OmniPvdObjectHandle* physxRoadGeomQueryFilterDataOHs;
|
||||
sizeof(OmniPvdObjectHandle)*nbAntirolls*(
|
||||
1); //OmniPvdObjectHandle* antiRollParamOHs
|
||||
|
||||
|
||||
PxU8* buffer = reinterpret_cast<PxU8*>(allocator.allocate(byteSize, "PxVehiclePvdObjectHandles", PX_FL));
|
||||
#if PX_ENABLE_ASSERTS
|
||||
PxU8* start = buffer;
|
||||
#endif
|
||||
PxMemZero(buffer, byteSize);
|
||||
|
||||
PxVehiclePvdObjectHandles* objectHandles = reinterpret_cast<PxVehiclePvdObjectHandles*>(buffer);
|
||||
buffer += sizeof(PxVehiclePvdObjectHandles);
|
||||
|
||||
if(nbWheels != 0)
|
||||
{
|
||||
objectHandles->wheelAttachmentOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->wheelParamsOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->wheelActuationStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->wheelRigidBody1dStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->wheelLocalPoseStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->roadGeomStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->suspParamsOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->suspCompParamsOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->suspForceParamsOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->suspStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->suspCompStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->suspForceOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->tireParamsOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->tireDirectionStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->tireSpeedStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->tireSlipStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->tireStickyStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->tireGripStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->tireCamberStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->tireForceOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->physxWheelAttachmentOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->physxConstraintParamOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->physxWheelShapeOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->physxConstraintStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->physxRoadGeomStateOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
if(maxNbPhysXMaterialFrictions != 0)
|
||||
{
|
||||
objectHandles->physxMaterialFrictionSetOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
objectHandles->physxMaterialFrictionOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels*maxNbPhysXMaterialFrictions;
|
||||
}
|
||||
objectHandles->physxRoadGeomQueryFilterDataOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbWheels;
|
||||
}
|
||||
|
||||
if(nbAntirolls != 0)
|
||||
{
|
||||
objectHandles->antiRollParamOHs = reinterpret_cast<OmniPvdObjectHandle*>(buffer);
|
||||
buffer += sizeof(OmniPvdObjectHandle)*nbAntirolls;
|
||||
}
|
||||
|
||||
objectHandles->nbWheels = nbWheels;
|
||||
objectHandles->nbPhysXMaterialFrictions = maxNbPhysXMaterialFrictions;
|
||||
objectHandles->nbAntirolls = nbAntirolls;
|
||||
|
||||
objectHandles->contextHandle = contextHandle;
|
||||
|
||||
PX_ASSERT((start + byteSize) == buffer);
|
||||
|
||||
return objectHandles;
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
//OBJECT DESTRUCTION
|
||||
////////////////////////////////////
|
||||
|
||||
PX_FORCE_INLINE void destroyObject
|
||||
(OmniPvdWriter& omniWriter, OmniPvdContextHandle ch,
|
||||
OmniPvdObjectHandle oh)
|
||||
{
|
||||
// note: "0" needs to be replaced with a marker for invalid object handle as soon as PVD
|
||||
// provides it (and PxVehiclePvdObjectCreate needs to initialize accordingly or
|
||||
// compile time assert that the value is 0 for now)
|
||||
if(oh != 0)
|
||||
omniWriter.destroyObject(ch, oh);
|
||||
}
|
||||
|
||||
void PxVehiclePvdObjectRelease
|
||||
(OmniPvdWriter& ow, PxAllocatorCallback& allocator, PxVehiclePvdObjectHandles& oh)
|
||||
{
|
||||
const OmniPvdContextHandle ch = oh.contextHandle;
|
||||
|
||||
//rigid body
|
||||
destroyObject(ow, ch, oh.rigidBodyParamsOH);
|
||||
destroyObject(ow, ch, oh.rigidBodyStateOH);
|
||||
|
||||
//susp state calc params
|
||||
destroyObject(ow, ch, oh.suspStateCalcParamsOH);
|
||||
|
||||
//controls
|
||||
for(PxU32 i = 0; i < 2; i++)
|
||||
{
|
||||
destroyObject(ow, ch, oh.brakeResponseParamOHs[i]);
|
||||
}
|
||||
destroyObject(ow, ch, oh.steerResponseParamsOH);
|
||||
destroyObject(ow, ch, oh.brakeResponseStateOH);
|
||||
destroyObject(ow, ch, oh.steerResponseStateOH);
|
||||
destroyObject(ow, ch, oh.ackermannParamsOH);
|
||||
|
||||
//Wheel attachments
|
||||
for(PxU32 i = 0; i < oh.nbWheels; i++)
|
||||
{
|
||||
destroyObject(ow, ch, oh.wheelParamsOHs[i]);
|
||||
destroyObject(ow, ch, oh.wheelActuationStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.wheelRigidBody1dStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.wheelLocalPoseStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.suspParamsOHs[i]);
|
||||
destroyObject(ow, ch, oh.suspCompParamsOHs[i]);
|
||||
destroyObject(ow, ch, oh.suspForceParamsOHs[i]);
|
||||
destroyObject(ow, ch, oh.suspStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.suspCompStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.suspForceOHs[i]);
|
||||
destroyObject(ow, ch, oh.tireParamsOHs[i]);
|
||||
destroyObject(ow, ch, oh.tireDirectionStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.tireSpeedStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.tireSlipStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.tireStickyStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.tireGripStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.tireCamberStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.tireForceOHs[i]);
|
||||
destroyObject(ow, ch, oh.wheelAttachmentOHs[i]);
|
||||
}
|
||||
|
||||
//Antiroll
|
||||
for(PxU32 i = 0; i < oh.nbAntirolls; i++)
|
||||
{
|
||||
destroyObject(ow, ch, oh.antiRollParamOHs[i]);
|
||||
}
|
||||
destroyObject(ow, ch, oh.antiRollTorqueOH);
|
||||
|
||||
//direct drive
|
||||
destroyObject(ow, ch, oh.directDriveCommandStateOH);
|
||||
destroyObject(ow, ch, oh.directDriveTransmissionCommandStateOH);
|
||||
destroyObject(ow, ch, oh.directDriveThrottleResponseParamsOH);
|
||||
destroyObject(ow, ch, oh.directDriveThrottleResponseStateOH);
|
||||
destroyObject(ow, ch, oh.directDrivetrainOH);
|
||||
|
||||
//engine drive
|
||||
destroyObject(ow, ch, oh.engineDriveCommandStateOH);
|
||||
destroyObject(ow, ch, oh.engineDriveTransmissionCommandStateOH);
|
||||
destroyObject(ow, ch, oh.clutchResponseParamsOH);
|
||||
destroyObject(ow, ch, oh.clutchParamsOH);
|
||||
destroyObject(ow, ch, oh.engineParamsOH);
|
||||
destroyObject(ow, ch, oh.gearboxParamsOH);
|
||||
destroyObject(ow, ch, oh.autoboxParamsOH);
|
||||
destroyObject(ow, ch, oh.differentialParamsOH);
|
||||
destroyObject(ow, ch, oh.clutchResponseStateOH);
|
||||
destroyObject(ow, ch, oh.engineDriveThrottleResponseStateOH);
|
||||
destroyObject(ow, ch, oh.engineStateOH);
|
||||
destroyObject(ow, ch, oh.gearboxStateOH);
|
||||
destroyObject(ow, ch, oh.autoboxStateOH);
|
||||
destroyObject(ow, ch, oh.diffStateOH);
|
||||
destroyObject(ow, ch, oh.clutchSlipStateOH);
|
||||
destroyObject(ow, ch, oh.engineDrivetrainOH);
|
||||
|
||||
//PhysX Wheel attachments
|
||||
for(PxU32 i = 0; i < oh.nbWheels; i++)
|
||||
{
|
||||
destroyObject(ow, ch, oh.physxConstraintParamOHs[i]);
|
||||
destroyObject(ow, ch, oh.physxWheelShapeOHs[i]);
|
||||
destroyObject(ow, ch, oh.physxRoadGeomStateOHs[i]);
|
||||
destroyObject(ow, ch, oh.physxConstraintStateOHs[i]);
|
||||
for(PxU32 j = 0; j < oh.nbPhysXMaterialFrictions; j++)
|
||||
{
|
||||
const PxU32 id = i*oh.nbPhysXMaterialFrictions + j;
|
||||
destroyObject(ow, ch, oh.physxMaterialFrictionOHs[id]);
|
||||
}
|
||||
destroyObject(ow, ch, oh.physxWheelAttachmentOHs[i]);
|
||||
}
|
||||
|
||||
//Physx rigid actor
|
||||
destroyObject(ow, ch, oh.physxRoadGeomQueryParamOH);
|
||||
destroyObject(ow, ch, oh.physxRoadGeomQueryDefaultFilterDataOH);
|
||||
for (PxU32 i = 0; i < oh.nbWheels; i++)
|
||||
{
|
||||
destroyObject(ow, ch, oh.physxRoadGeomQueryFilterDataOHs[i]);
|
||||
// safe even if not using per wheel filter data since it should hold the
|
||||
// invalid handle value and thus destroyObject will do nothing
|
||||
}
|
||||
destroyObject(ow, ch, oh.physxRigidActorOH);
|
||||
destroyObject(ow, ch, oh.physxSteerStateOH);
|
||||
|
||||
//Free the memory.
|
||||
allocator.deallocate(&oh);
|
||||
}
|
||||
|
||||
#else //#if PX_SUPPORT_OMNI_PVD
|
||||
|
||||
PxVehiclePvdAttributeHandles* PxVehiclePvdAttributesCreate(PxAllocatorCallback& allocator, OmniPvdWriter& omniWriter)
|
||||
{
|
||||
PX_UNUSED(allocator);
|
||||
PX_UNUSED(omniWriter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PxVehiclePvdAttributesRelease(PxAllocatorCallback& allocator, PxVehiclePvdAttributeHandles& attributeHandles)
|
||||
{
|
||||
PX_UNUSED(allocator);
|
||||
PX_UNUSED(attributeHandles);
|
||||
}
|
||||
|
||||
PxVehiclePvdObjectHandles* PxVehiclePvdObjectCreate
|
||||
(const PxU32 nbWheels, const PxU32 nbAntirolls, const PxU32 maxNbPhysXMaterialFrictions,
|
||||
const PxU64 contextHandle,
|
||||
PxAllocatorCallback& allocator)
|
||||
{
|
||||
PX_UNUSED(nbWheels);
|
||||
PX_UNUSED(nbAntirolls);
|
||||
PX_UNUSED(maxNbPhysXMaterialFrictions);
|
||||
PX_UNUSED(contextHandle);
|
||||
PX_UNUSED(allocator);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PxVehiclePvdObjectRelease
|
||||
(OmniPvdWriter& ow, PxAllocatorCallback& allocator, PxVehiclePvdObjectHandles& oh)
|
||||
{
|
||||
PX_UNUSED(ow);
|
||||
PX_UNUSED(allocator);
|
||||
PX_UNUSED(oh);
|
||||
}
|
||||
|
||||
#endif //#if PX_SUPPORT_OMNI_PVD
|
||||
|
||||
|
||||
} // namespace vehicle2
|
||||
} // namespace physx
|
||||
136
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdObjectHandles.h
vendored
Normal file
136
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdObjectHandles.h
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vehicle2/PxVehicleLimits.h"
|
||||
#if PX_SUPPORT_OMNI_PVD
|
||||
#include "OmniPvdWriter.h"
|
||||
#endif
|
||||
#include "foundation/PxMemory.h"
|
||||
|
||||
|
||||
#if !PX_DOXYGEN
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
#endif
|
||||
|
||||
struct PxVehiclePvdObjectHandles
|
||||
{
|
||||
#if PX_SUPPORT_OMNI_PVD
|
||||
|
||||
OmniPvdObjectHandle vehicleOH;
|
||||
|
||||
OmniPvdObjectHandle rigidBodyParamsOH;
|
||||
OmniPvdObjectHandle rigidBodyStateOH;
|
||||
|
||||
OmniPvdObjectHandle suspStateCalcParamsOH;
|
||||
|
||||
OmniPvdObjectHandle brakeResponseParamOHs[2];
|
||||
OmniPvdObjectHandle steerResponseParamsOH;
|
||||
OmniPvdObjectHandle brakeResponseStateOH;
|
||||
OmniPvdObjectHandle steerResponseStateOH;
|
||||
OmniPvdObjectHandle ackermannParamsOH;
|
||||
|
||||
OmniPvdObjectHandle directDriveCommandStateOH;
|
||||
OmniPvdObjectHandle directDriveTransmissionCommandStateOH;
|
||||
OmniPvdObjectHandle directDriveThrottleResponseParamsOH;
|
||||
OmniPvdObjectHandle directDriveThrottleResponseStateOH;
|
||||
OmniPvdObjectHandle directDrivetrainOH;
|
||||
|
||||
OmniPvdObjectHandle engineDriveCommandStateOH;
|
||||
OmniPvdObjectHandle engineDriveTransmissionCommandStateOH;
|
||||
OmniPvdObjectHandle clutchResponseParamsOH;
|
||||
OmniPvdObjectHandle clutchParamsOH;
|
||||
OmniPvdObjectHandle engineParamsOH;
|
||||
OmniPvdObjectHandle gearboxParamsOH;
|
||||
OmniPvdObjectHandle autoboxParamsOH;
|
||||
OmniPvdObjectHandle differentialParamsOH;
|
||||
OmniPvdObjectHandle clutchResponseStateOH;
|
||||
OmniPvdObjectHandle engineDriveThrottleResponseStateOH;
|
||||
OmniPvdObjectHandle engineStateOH;
|
||||
OmniPvdObjectHandle gearboxStateOH;
|
||||
OmniPvdObjectHandle autoboxStateOH;
|
||||
OmniPvdObjectHandle diffStateOH;
|
||||
OmniPvdObjectHandle clutchSlipStateOH;
|
||||
OmniPvdObjectHandle engineDrivetrainOH;
|
||||
|
||||
OmniPvdObjectHandle* wheelAttachmentOHs;
|
||||
OmniPvdObjectHandle* wheelParamsOHs;
|
||||
OmniPvdObjectHandle* wheelActuationStateOHs;
|
||||
OmniPvdObjectHandle* wheelRigidBody1dStateOHs;
|
||||
OmniPvdObjectHandle* wheelLocalPoseStateOHs;
|
||||
OmniPvdObjectHandle* roadGeomStateOHs;
|
||||
OmniPvdObjectHandle* suspParamsOHs;
|
||||
OmniPvdObjectHandle* suspCompParamsOHs;
|
||||
OmniPvdObjectHandle* suspForceParamsOHs;
|
||||
OmniPvdObjectHandle* suspStateOHs;
|
||||
OmniPvdObjectHandle* suspCompStateOHs;
|
||||
OmniPvdObjectHandle* suspForceOHs;
|
||||
OmniPvdObjectHandle* tireParamsOHs;
|
||||
OmniPvdObjectHandle* tireDirectionStateOHs;
|
||||
OmniPvdObjectHandle* tireSpeedStateOHs;
|
||||
OmniPvdObjectHandle* tireSlipStateOHs;
|
||||
OmniPvdObjectHandle* tireStickyStateOHs;
|
||||
OmniPvdObjectHandle* tireGripStateOHs;
|
||||
OmniPvdObjectHandle* tireCamberStateOHs;
|
||||
OmniPvdObjectHandle* tireForceOHs;
|
||||
|
||||
OmniPvdObjectHandle* physxWheelAttachmentOHs;
|
||||
OmniPvdObjectHandle* physxWheelShapeOHs;
|
||||
OmniPvdObjectHandle* physxConstraintParamOHs;
|
||||
OmniPvdObjectHandle* physxConstraintStateOHs;
|
||||
OmniPvdObjectHandle* physxRoadGeomStateOHs;
|
||||
OmniPvdObjectHandle physxSteerStateOH;
|
||||
OmniPvdObjectHandle* physxMaterialFrictionSetOHs;
|
||||
OmniPvdObjectHandle* physxMaterialFrictionOHs;
|
||||
|
||||
OmniPvdObjectHandle physxRoadGeomQueryParamOH;
|
||||
OmniPvdObjectHandle physxRoadGeomQueryDefaultFilterDataOH;
|
||||
OmniPvdObjectHandle* physxRoadGeomQueryFilterDataOHs;
|
||||
OmniPvdObjectHandle physxRigidActorOH;
|
||||
|
||||
OmniPvdObjectHandle* antiRollParamOHs;
|
||||
OmniPvdObjectHandle antiRollTorqueOH;
|
||||
|
||||
PxU32 nbWheels;
|
||||
PxU32 nbPhysXMaterialFrictions;
|
||||
PxU32 nbAntirolls;
|
||||
|
||||
OmniPvdContextHandle contextHandle;
|
||||
|
||||
#endif //PX_SUPPORT_OMNI_PVD
|
||||
};
|
||||
|
||||
#if !PX_DOXYGEN
|
||||
} // namespace vehicle2
|
||||
} // namespace physx
|
||||
#endif
|
||||
|
||||
1780
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdWriter.cpp
vendored
Normal file
1780
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdWriter.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1034
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdWriter.h
vendored
Normal file
1034
engine/third_party/physx/source/physxvehicle/src/pvd/VhPvdWriter.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
150
engine/third_party/physx/source/physxvehicle/src/rigidBody/VhRigidBodyFunctions.cpp
vendored
Normal file
150
engine/third_party/physx/source/physxvehicle/src/rigidBody/VhRigidBodyFunctions.cpp
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxMat33.h"
|
||||
#include "foundation/PxTransform.h"
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyFunctions.h"
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyStates.h"
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyParams.h"
|
||||
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionStates.h"
|
||||
|
||||
#include "vehicle2/tire/PxVehicleTireStates.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
PX_FORCE_INLINE void transformInertiaTensor(const PxVec3& invD, const PxMat33& M, PxMat33& mIInv)
|
||||
{
|
||||
const float axx = invD.x*M(0, 0), axy = invD.x*M(1, 0), axz = invD.x*M(2, 0);
|
||||
const float byx = invD.y*M(0, 1), byy = invD.y*M(1, 1), byz = invD.y*M(2, 1);
|
||||
const float czx = invD.z*M(0, 2), czy = invD.z*M(1, 2), czz = invD.z*M(2, 2);
|
||||
|
||||
mIInv(0, 0) = axx * M(0, 0) + byx * M(0, 1) + czx * M(0, 2);
|
||||
mIInv(1, 1) = axy * M(1, 0) + byy * M(1, 1) + czy * M(1, 2);
|
||||
mIInv(2, 2) = axz * M(2, 0) + byz * M(2, 1) + czz * M(2, 2);
|
||||
|
||||
mIInv(0, 1) = mIInv(1, 0) = axx * M(1, 0) + byx * M(1, 1) + czx * M(1, 2);
|
||||
mIInv(0, 2) = mIInv(2, 0) = axx * M(2, 0) + byx * M(2, 1) + czx * M(2, 2);
|
||||
mIInv(1, 2) = mIInv(2, 1) = axy * M(2, 0) + byy * M(2, 1) + czy * M(2, 2);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void integrateBody
|
||||
(const PxF32 mass, const PxVec3& moi, const PxVec3& force, const PxVec3& torque, const PxF32 dt,
|
||||
PxVec3& linvel, PxVec3& angvel, PxTransform& t)
|
||||
{
|
||||
const PxF32 inverseMass = 1.0f/mass;
|
||||
const PxVec3 inverseMOI(1.0f/moi.x, 1.0f/moi.y, 1.0f/moi.z);
|
||||
|
||||
//Integrate linear velocity.
|
||||
linvel += force * (inverseMass*dt);
|
||||
|
||||
//Integrate angular velocity.
|
||||
PxMat33 inverseInertia;
|
||||
transformInertiaTensor(inverseMOI, PxMat33(t.q), inverseInertia);
|
||||
angvel += inverseInertia * (torque*dt);
|
||||
|
||||
//Integrate position.
|
||||
t.p += linvel * dt;
|
||||
|
||||
//Integrate quaternion.
|
||||
PxQuat wq(angvel.x, angvel.y, angvel.z, 0.0f);
|
||||
PxQuat q = t.q;
|
||||
PxQuat qdot = wq * q*(dt*0.5f);
|
||||
q += qdot;
|
||||
q.normalize();
|
||||
t.q = q;
|
||||
}
|
||||
|
||||
void PxVehicleRigidBodyUpdate
|
||||
(const PxVehicleAxleDescription& axleDescription, const PxVehicleRigidBodyParams& rigidBodyParams,
|
||||
const PxVehicleArrayData<const PxVehicleSuspensionForce>& suspensionForces,
|
||||
const PxVehicleArrayData<const PxVehicleTireForce>& tireForces,
|
||||
const PxVehicleAntiRollTorque* antiRollTorque,
|
||||
const PxReal dt, const PxVec3& gravity,
|
||||
PxVehicleRigidBodyState& rigidBodyState)
|
||||
{
|
||||
//Sum all the forces and torques.
|
||||
const PxU32 nbAxles = axleDescription.getNbAxles();
|
||||
PxVec3 force(PxZero);
|
||||
PxVec3 torque(PxZero);
|
||||
for (PxU32 i = 0; i < nbAxles; i++)
|
||||
{
|
||||
PxVec3 axleSuspForce(PxZero);
|
||||
PxVec3 axleTireLongForce(PxZero);
|
||||
PxVec3 axleTireLatForce(PxZero);
|
||||
PxVec3 axleSuspTorque(PxZero);
|
||||
PxVec3 axleTireLongTorque(PxZero);
|
||||
PxVec3 axleTireLatTorque(PxZero);
|
||||
for (PxU32 j = 0; j < axleDescription.getNbWheelsOnAxle(i); j++)
|
||||
{
|
||||
const PxU32 wheelId = axleDescription.getWheelOnAxle(j, i);
|
||||
const PxVehicleSuspensionForce& suspForce = suspensionForces[wheelId];
|
||||
const PxVehicleTireForce& tireForce = tireForces[wheelId];
|
||||
axleSuspForce += suspForce.force;
|
||||
axleTireLongForce += tireForce.forces[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
axleTireLatForce += tireForce.forces[PxVehicleTireDirectionModes::eLATERAL];
|
||||
axleSuspTorque += suspForce.torque;
|
||||
axleTireLongTorque += tireForce.torques[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
axleTireLatTorque += tireForce.torques[PxVehicleTireDirectionModes::eLATERAL];
|
||||
}
|
||||
const PxVec3 axleForce = axleSuspForce + axleTireLongForce + axleTireLatForce;
|
||||
const PxVec3 axleTorque = axleSuspTorque + axleTireLongTorque + axleTireLatTorque;
|
||||
force += axleForce;
|
||||
torque += axleTorque;
|
||||
}
|
||||
force += gravity * rigidBodyParams.mass;
|
||||
force += rigidBodyState.externalForce;
|
||||
torque += rigidBodyState.externalTorque;
|
||||
torque += (antiRollTorque ? antiRollTorque->antiRollTorque : PxVec3(PxZero));
|
||||
|
||||
//Rigid body params.
|
||||
const PxF32 mass = rigidBodyParams.mass;
|
||||
const PxVec3& moi = rigidBodyParams.moi;
|
||||
|
||||
//Perform the integration.
|
||||
PxTransform& t = rigidBodyState.pose;
|
||||
PxVec3& linvel = rigidBodyState.linearVelocity;
|
||||
PxVec3& angvel = rigidBodyState.angularVelocity;
|
||||
integrateBody(
|
||||
mass, moi,
|
||||
force, torque, dt,
|
||||
linvel, angvel, t);
|
||||
|
||||
//Reset the accumulated external forces after using them.
|
||||
rigidBodyState.externalForce = PxVec3(PxZero);
|
||||
rigidBodyState.externalTorque = PxVec3(PxZero);
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
96
engine/third_party/physx/source/physxvehicle/src/steering/VhSteeringFunctions.cpp
vendored
Normal file
96
engine/third_party/physx/source/physxvehicle/src/steering/VhSteeringFunctions.cpp
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/commands/PxVehicleCommandHelpers.h"
|
||||
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyStates.h"
|
||||
|
||||
#include "vehicle2/steering/PxVehicleSteeringParams.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
void PxVehicleSteerCommandResponseUpdate
|
||||
(const PxReal steer, const PxReal longitudinalSpeed,
|
||||
const PxU32 wheelId, const PxVehicleSteerCommandResponseParams& responseParams,
|
||||
PxReal& steerResponse)
|
||||
{
|
||||
PxReal sign = PxSign(steer);
|
||||
steerResponse = sign * PxVehicleNonLinearResponseCompute(PxAbs(steer), longitudinalSpeed, wheelId, responseParams);
|
||||
}
|
||||
|
||||
void PxVehicleAckermannSteerUpdate
|
||||
(const PxReal steer,
|
||||
const PxVehicleSteerCommandResponseParams& steerResponseParams, const PxVehicleSizedArrayData<const PxVehicleAckermannParams>& ackermannParams,
|
||||
PxVehicleArrayData<PxReal>& steerResponseStates)
|
||||
{
|
||||
for (PxU32 i = 0; i < ackermannParams.size; i++)
|
||||
{
|
||||
const PxVehicleAckermannParams& ackParams = ackermannParams[i];
|
||||
if (ackParams.strength > 0.0f)
|
||||
{
|
||||
//Axle yaw is the average of the two wheels.
|
||||
const PxF32 axleYaw =
|
||||
(PxVehicleLinearResponseCompute(steer, ackParams.wheelIds[0], steerResponseParams) +
|
||||
PxVehicleLinearResponseCompute(steer, ackParams.wheelIds[1], steerResponseParams))*0.5f;
|
||||
if (axleYaw != 0.0f)
|
||||
{
|
||||
//Work out the ackermann steer for +ve steer then swap and negate the steer angles if the steer is -ve.
|
||||
|
||||
//Uncorrected yaw angle.
|
||||
//One of the wheels will adopt this angle.
|
||||
//The other will be corrected.
|
||||
const PxF32 posWheelYaw = PxAbs(axleYaw);
|
||||
|
||||
//Work out the yaw of the other wheel.
|
||||
PxF32 negWheelCorrectedYaw;
|
||||
{
|
||||
const PxF32 dz = ackParams.wheelBase;
|
||||
const PxF32 dx = ackParams.trackWidth + ackParams.wheelBase / PxTan(posWheelYaw);
|
||||
const PxF32 negWheelPerfectYaw = PxAtan(dz / dx);
|
||||
negWheelCorrectedYaw = posWheelYaw + ackParams.strength*(negWheelPerfectYaw - posWheelYaw);
|
||||
}
|
||||
|
||||
//Now assign axleYaw and negWheelCorrectedYaw to the correct wheels with the correct signs.
|
||||
const PxF32 negWheelFinalYaw = intrinsics::fsel(axleYaw, negWheelCorrectedYaw, -posWheelYaw);
|
||||
const PxF32 posWheelFinalYaw = intrinsics::fsel(axleYaw, posWheelYaw, -negWheelCorrectedYaw);
|
||||
|
||||
//Apply the per axle distributions to each wheel on the axle that is affected by this Ackermann correction.
|
||||
steerResponseStates[ackParams.wheelIds[0]] = negWheelFinalYaw;
|
||||
steerResponseStates[ackParams.wheelIds[1]] = posWheelFinalYaw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
717
engine/third_party/physx/source/physxvehicle/src/suspension/VhSuspensionFunctions.cpp
vendored
Normal file
717
engine/third_party/physx/source/physxvehicle/src/suspension/VhSuspensionFunctions.cpp
vendored
Normal file
@@ -0,0 +1,717 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/roadGeometry/PxVehicleRoadGeometryState.h"
|
||||
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyStates.h"
|
||||
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionParams.h"
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionFunctions.h"
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionHelpers.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
#define VH_SUSPENSION_NO_INTERSECTION_MARKER FLT_MIN
|
||||
|
||||
PX_FORCE_INLINE void computeJounceAndSeparation(const PxF32 depth, const PxF32 suspDirDotPlaneNormal,
|
||||
const PxF32 suspTravelDist, const PxF32 previousJounce,
|
||||
PxF32& jounce, PxF32& separation)
|
||||
{
|
||||
if (suspDirDotPlaneNormal != 0.0f)
|
||||
{
|
||||
if (depth <= 0.0f)
|
||||
{
|
||||
//There is overlap at max droop
|
||||
|
||||
const PxF32 suspDeltaToDepthZero = depth / suspDirDotPlaneNormal;
|
||||
|
||||
if ((suspDeltaToDepthZero > 0.0f) && (suspDeltaToDepthZero <= suspTravelDist))
|
||||
{
|
||||
//The wheel can be placed on the plane for a jounce between max droop and max compression.
|
||||
jounce = suspDeltaToDepthZero;
|
||||
separation = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (suspDeltaToDepthZero > suspTravelDist)
|
||||
{
|
||||
//There is overlap even at max compression. Compute the depth at max
|
||||
//compression.
|
||||
jounce = suspTravelDist;
|
||||
separation = (depth * (suspDeltaToDepthZero - suspTravelDist)) / suspDeltaToDepthZero;
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(suspDeltaToDepthZero <= 0.0f);
|
||||
|
||||
//There is overlap at max droop and in addition, the suspension would have to expand
|
||||
//beyond max droop to move out of plane contact. This scenario can be reached, for
|
||||
//example, if a car rolls over or if something touches a wheel from "above".
|
||||
jounce = 0.0f;
|
||||
separation = depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//At max droop there is no overlap => let the suspension fully expand.
|
||||
//Note that this check is important because without it, you can get unexpected
|
||||
//behavior like the wheel compressing just so that it touches the plane again.
|
||||
|
||||
jounce = 0.0f;
|
||||
separation = VH_SUSPENSION_NO_INTERSECTION_MARKER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//The suspension direction and hit normal are perpendicular, thus no change to
|
||||
//suspension jounce will change the distance to the plane.
|
||||
|
||||
if (depth >= 0.0f)
|
||||
{
|
||||
jounce = 0.0f;
|
||||
separation = VH_SUSPENSION_NO_INTERSECTION_MARKER;
|
||||
}
|
||||
else
|
||||
{
|
||||
jounce = (previousJounce != PX_VEHICLE_UNSPECIFIED_JOUNCE) ? previousJounce : suspTravelDist;
|
||||
separation = depth;
|
||||
// note: since The suspension direction and hit normal are perpendicular, the
|
||||
// depth will be the same for all jounce values
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void intersectRayPlane
|
||||
(const PxVehicleFrame& frame, const PxVehicleWheelParams& wheelParams, const PxVehicleSuspensionParams& suspParams,
|
||||
const PxF32 steerAngle, const PxVehicleRoadGeometryState& roadGeomState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxF32 previousJounce,
|
||||
PxVec3& suspDir, PxF32& jounce, PxF32& separation)
|
||||
{
|
||||
//Compute the position on the wheel surface along the suspension direction that is closest to
|
||||
//the plane (for the purpose of computing the separation from the plane). The wheel center position
|
||||
//is chosen at max droop (zero jounce).
|
||||
PxVehicleSuspensionState suspState;
|
||||
suspState.setToDefault(0.0f);
|
||||
const PxTransform wheelPose = PxVehicleComputeWheelPose(frame, suspParams, suspState, 0.0f, 0.0f, steerAngle,
|
||||
rigidBodyState.pose, 0.0f);
|
||||
|
||||
suspDir = PxVehicleComputeSuspensionDirection(suspParams, rigidBodyState.pose);
|
||||
const PxPlane& hitPlane = roadGeomState.plane;
|
||||
const PxF32 suspDirDotPlaneNormal = suspDir.dot(hitPlane.n);
|
||||
|
||||
PxVec3 wheelRefPoint;
|
||||
if (suspDirDotPlaneNormal < 0.0f)
|
||||
{
|
||||
wheelRefPoint = wheelPose.p + (suspDir * wheelParams.radius);
|
||||
//The "wheel bottom" has to be placed on the plane to resolve collision
|
||||
}
|
||||
else if (suspDirDotPlaneNormal > 0.0f)
|
||||
{
|
||||
wheelRefPoint = wheelPose.p - (suspDir * wheelParams.radius);
|
||||
//The "wheel top" has to be placed on the plane to resolve collision
|
||||
}
|
||||
else
|
||||
{
|
||||
//The hit normal and susp dir are prependicular
|
||||
//-> any point along the suspension direction will do to compute the depth
|
||||
wheelRefPoint = wheelPose.p;
|
||||
}
|
||||
|
||||
//Compute the penetration depth of the reference point with respect to the plane
|
||||
const PxF32 depth = hitPlane.n.dot(wheelRefPoint) + hitPlane.d;
|
||||
|
||||
//How far along the susp dir do we have to move to place the wheel exactly on the plane.
|
||||
computeJounceAndSeparation(depth, suspDirDotPlaneNormal, suspParams.suspensionTravelDist, previousJounce,
|
||||
jounce, separation);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE bool intersectPlanes(const PxPlane& a, const PxPlane& b, PxVec3& v, PxVec3& w)
|
||||
{
|
||||
const PxF32 n1x = a.n.x;
|
||||
const PxF32 n1y = a.n.y;
|
||||
const PxF32 n1z = a.n.z;
|
||||
const PxF32 n1d = a.d;
|
||||
|
||||
const PxF32 n2x = b.n.x;
|
||||
const PxF32 n2y = b.n.y;
|
||||
const PxF32 n2z = b.n.z;
|
||||
const PxF32 n2d = b.d;
|
||||
|
||||
PxF32 dx = (n1y * n2z) - (n1z * n2y);
|
||||
PxF32 dy = (n1z * n2x) - (n1x * n2z);
|
||||
PxF32 dz = (n1x * n2y) - (n1y * n2x);
|
||||
|
||||
const PxF32 dx2 = dx * dx;
|
||||
const PxF32 dy2 = dy * dy;
|
||||
const PxF32 dz2 = dz * dz;
|
||||
|
||||
PxF32 px, py, pz;
|
||||
if ((dz2 > dy2) && (dz2 > dx2) && (dz2 > 0))
|
||||
{
|
||||
px = ((n1y * n2d) - (n2y * n1d)) / dz;
|
||||
py = ((n2x * n1d) - (n1x * n2d)) / dz;
|
||||
pz = 0;
|
||||
}
|
||||
else if ((dy2 > dx2) && (dy2 > 0))
|
||||
{
|
||||
px = -((n1z * n2d) - (n2z * n1d)) / dy;
|
||||
py = 0;
|
||||
pz = -((n2x * n1d) - (n1x * n2d)) / dy;
|
||||
}
|
||||
else if (dx2 > 0)
|
||||
{
|
||||
px = 0;
|
||||
py = ((n1z * n2d) - (n2z * n1d)) / dx;
|
||||
pz = ((n2y * n1d) - (n1y * n2d)) / dx;
|
||||
}
|
||||
else
|
||||
{
|
||||
px = 0;
|
||||
py = 0;
|
||||
pz = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
const PxF32 ld = PxSqrt(dx2 + dy2 + dz2);
|
||||
|
||||
dx /= ld;
|
||||
dy /= ld;
|
||||
dz /= ld;
|
||||
|
||||
w = PxVec3(dx, dy, dz);
|
||||
v = PxVec3(px, py, pz);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// This method computes how much a wheel cylinder object at max droop (fully elongated suspension)
|
||||
// has to be pushed along the suspension direction to end up just touching the plane provided in
|
||||
// the road geometry state.
|
||||
//
|
||||
// output:
|
||||
// suspDir: suspension direction in the world frame
|
||||
// jounce: the suspension jounce.
|
||||
// jounce=0 the wheel is at max droop
|
||||
// jounce>0 the suspension is compressed by length jounce (up to max compression = suspensionTravelDist)
|
||||
//
|
||||
// The jounce value will be set to 0 (in the case of no overlap) or to the previous jounce
|
||||
// (in the case of overlap) for the following special cases:
|
||||
// - the plane normal and the wheel lateral axis are parallel
|
||||
// - the plane normal and the suspension direction are perpendicular
|
||||
// separation: 0 if the suspension can move between max droop and max compression to place
|
||||
// the wheel on the ground.
|
||||
// A negative value denotes by how much the wheel cylinder penetrates (along the hit
|
||||
// plane normal) into the ground for the computed jounce.
|
||||
// A positive value denotes that the wheel does not touch the ground.
|
||||
//
|
||||
PX_FORCE_INLINE void intersectCylinderPlane
|
||||
(const PxVehicleFrame& frame,
|
||||
const PxVehicleWheelParams& whlParams, const PxVehicleSuspensionParams& suspParams,
|
||||
const PxF32 steerAngle, const PxVehicleRoadGeometryState& roadGeomState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxF32 previousJounce,
|
||||
PxVec3& suspDir, PxF32& jounce, PxF32& separation)
|
||||
{
|
||||
const PxPlane& hitPlane = roadGeomState.plane;
|
||||
const PxF32 radius = whlParams.radius;
|
||||
const PxF32 halfWidth = whlParams.halfWidth;
|
||||
|
||||
//Compute the wheel pose at zero jounce ie at max droop.
|
||||
PxTransform wheelPoseAtZeroJounce;
|
||||
{
|
||||
PxTransform start;
|
||||
PxF32 dist;
|
||||
PxVehicleComputeSuspensionSweep(frame, suspParams, steerAngle, rigidBodyState.pose, start, suspDir, dist);
|
||||
wheelPoseAtZeroJounce = PxTransform(start.p + suspDir*dist, start.q);
|
||||
}
|
||||
|
||||
//Compute the plane of the wheel.
|
||||
PxPlane wheelPlane;
|
||||
{
|
||||
wheelPlane = PxPlane(wheelPoseAtZeroJounce.p, wheelPoseAtZeroJounce.rotate(frame.getLatAxis()));
|
||||
}
|
||||
|
||||
//Intersect the plane of the wheel with the hit plane.
|
||||
//This generates an intersection edge.
|
||||
PxVec3 intersectionEdgeV, intersectionEdgeW;
|
||||
const bool intersectPlaneSuccess = intersectPlanes(wheelPlane, hitPlane, intersectionEdgeV, intersectionEdgeW);
|
||||
|
||||
PxF32 depth;
|
||||
if (intersectPlaneSuccess)
|
||||
{
|
||||
//Compute the position on the intersection edge that is closest to the wheel centre.
|
||||
PxVec3 closestPointOnIntersectionEdge;
|
||||
{
|
||||
const PxVec3& p = wheelPoseAtZeroJounce.p;
|
||||
const PxVec3& dir = intersectionEdgeW;
|
||||
const PxVec3& v = intersectionEdgeV;
|
||||
const PxF32 t = (p - v).dot(dir);
|
||||
closestPointOnIntersectionEdge = v + dir * t;
|
||||
}
|
||||
|
||||
//Compute the vector that joins the wheel centre to the intersection edge;
|
||||
PxVec3 dir;
|
||||
{
|
||||
const PxF32 wheelCentreD = hitPlane.n.dot(wheelPoseAtZeroJounce.p) + hitPlane.d;
|
||||
dir = ((wheelCentreD >= 0) ? closestPointOnIntersectionEdge - wheelPoseAtZeroJounce.p : wheelPoseAtZeroJounce.p - closestPointOnIntersectionEdge);
|
||||
dir.normalize();
|
||||
}
|
||||
|
||||
//Compute the point on the disc diameter that will be the closest to the hit plane or the deepest inside the hit plane.
|
||||
const PxVec3 pos = wheelPoseAtZeroJounce.p + dir*radius;
|
||||
|
||||
//Now compute the maximum depth of the inside and outside discs against the plane.
|
||||
{
|
||||
const PxVec3& latDir = wheelPlane.n;
|
||||
const PxF32 signDot = PxVehicleComputeSign(hitPlane.n.dot(latDir));
|
||||
const PxVec3 deepestPos = pos - latDir * (signDot*halfWidth);
|
||||
depth = hitPlane.n.dot(deepestPos) + hitPlane.d;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//The hit plane normal and the wheel lateral axis are parallel
|
||||
|
||||
//Now compute the maximum depth of the inside and outside discs against the plane.
|
||||
const PxVec3& latDir = wheelPlane.n;
|
||||
const PxF32 signDot = PxVehicleComputeSign(hitPlane.n.dot(latDir));
|
||||
depth = hitPlane.d - halfWidth - (signDot*wheelPlane.d);
|
||||
|
||||
// examples:
|
||||
// halfWidth = 0.5
|
||||
//
|
||||
// wheelPlane.d hitplane.d depth
|
||||
//=============================================
|
||||
// -3 -> -3.5 -> -1
|
||||
// 3 <- -3.5 -> -1
|
||||
//
|
||||
// -3 -> 3.5 <- 0
|
||||
// 3 <- 3.5 <- 0
|
||||
//
|
||||
}
|
||||
|
||||
//How far along the susp dir do we have to move to place the wheel exactly on the plane.
|
||||
const PxF32 suspDirDotPlaneNormal = hitPlane.n.dot(suspDir);
|
||||
computeJounceAndSeparation(depth, suspDirDotPlaneNormal, suspParams.suspensionTravelDist, previousJounce,
|
||||
jounce, separation);
|
||||
}
|
||||
|
||||
static void limitSuspensionExpansionVelocity
|
||||
(const PxReal jounceSpeed, const PxReal previousJounceSpeed, const PxReal previousJounce,
|
||||
const PxReal suspStiffness, const PxReal suspDamping,
|
||||
const PxVec3& suspDirWorld, const PxReal wheelMass,
|
||||
const PxReal dt, const PxVec3& gravity, const bool hasGroundHit,
|
||||
PxVehicleSuspensionState& suspState)
|
||||
{
|
||||
PX_ASSERT(jounceSpeed < 0.0f); // don't call this method if the suspension is not expanding
|
||||
|
||||
// The suspension is expanding. Check if the suspension can expand fast enough to actually reach the
|
||||
// target jounce within the given time step.
|
||||
|
||||
// Without the suspension elongating, the wheel would end up in the air. Compute the suspension force
|
||||
// that pushes the wheel towards the ground. Note that gravity is ignored here as it applies to sprung
|
||||
// mass and wheel equally.
|
||||
const PxReal springForceAlongSuspDir = (previousJounce * suspStiffness);
|
||||
const PxReal suspDirVelSpring = (springForceAlongSuspDir / wheelMass) * dt;
|
||||
const PxReal dampingForceAlongSuspDir = (previousJounceSpeed * suspDamping); // note: negative jounce speed = expanding
|
||||
const PxReal suspDirVelDamping = (dampingForceAlongSuspDir / wheelMass) * dt;
|
||||
PxReal suspDirVel = suspDirVelSpring - previousJounceSpeed;
|
||||
// add damping part but such that it does not flip the velocity sign (covering case of
|
||||
// crazily high damping values)
|
||||
const PxReal suspDirVelTmp = suspDirVel + suspDirVelDamping;
|
||||
if (suspDirVel >= 0.0f)
|
||||
suspDirVel = PxMax(0.0f, suspDirVelTmp);
|
||||
else
|
||||
suspDirVel = PxMin(0.0f, suspDirVelTmp);
|
||||
|
||||
const PxReal gravitySuspDir = gravity.dot(suspDirWorld);
|
||||
|
||||
PxReal velocityThreshold;
|
||||
if (hasGroundHit)
|
||||
{
|
||||
velocityThreshold = (gravitySuspDir > 0.0f) ? suspDirVel + (gravitySuspDir * dt) : suspDirVel;
|
||||
// gravity is considered too as it affects the wheel and can close the distance to the ground
|
||||
// too. External forces acting on the sprung mass are ignored as those propagate
|
||||
// through the suspension to the wheel.
|
||||
// If gravity points in the opposite direction of the suspension travel direction, it is
|
||||
// ignored. The suspension should never elongate more than what's given by the current delta
|
||||
// jounce (defined by jounceSpeed, i.e., jounceSpeed < -suspDirVel has to hold all the time
|
||||
// for the clamping to take place).
|
||||
}
|
||||
else
|
||||
{
|
||||
velocityThreshold = suspDirVel;
|
||||
// if there was no hit detected, the gravity will not be taken into account since there is no
|
||||
// ground to move towards.
|
||||
}
|
||||
|
||||
if (jounceSpeed < (-velocityThreshold))
|
||||
{
|
||||
// The suspension can not expand fast enough to place the wheel on the ground. As a result,
|
||||
// the scenario is interpreted as if there was no hit and the wheels end up in air. The
|
||||
// jounce is adjusted based on the clamped velocity to not have it snap to the target immediately.
|
||||
// note: could consider applying the suspension force to the sprung mass too but the complexity
|
||||
// seems high enough already.
|
||||
|
||||
const PxReal expansionDelta = suspDirVel * dt;
|
||||
const PxReal clampedJounce = previousJounce - expansionDelta;
|
||||
|
||||
PX_ASSERT(clampedJounce >= 0.0f);
|
||||
// No need to cover the case of a negative jounce as the input jounce speed is expected to make
|
||||
// sure that no negative jounce would result (and the speed considered here is smaller than the
|
||||
// non-clamped input jounce speed).
|
||||
|
||||
if (suspState.separation >= 0.0f) // do not adjust separation if ground penetration was detected
|
||||
{
|
||||
suspState.separation = clampedJounce - suspState.jounce;
|
||||
}
|
||||
suspState.jounce = clampedJounce;
|
||||
suspState.jounceSpeed = -suspDirVel;
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleSuspensionStateUpdate
|
||||
(const PxVehicleWheelParams& whlParams, const PxVehicleSuspensionParams& suspParams, const PxVehicleSuspensionStateCalculationParams& suspStateCalcParams,
|
||||
const PxReal suspStiffness, const PxReal suspDamping,
|
||||
const PxF32 steerAngle, const PxVehicleRoadGeometryState& roadGeomState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxReal dt, const PxVehicleFrame& frame, const PxVec3& gravity,
|
||||
PxVehicleSuspensionState& suspState)
|
||||
{
|
||||
const PxReal prevJounce = suspState.jounce;
|
||||
const PxReal prevJounceSpeed = suspState.jounceSpeed;
|
||||
|
||||
suspState.setToDefault(0.0f, VH_SUSPENSION_NO_INTERSECTION_MARKER);
|
||||
|
||||
if(!roadGeomState.hitState)
|
||||
{
|
||||
if (suspStateCalcParams.limitSuspensionExpansionVelocity && (prevJounce != PX_VEHICLE_UNSPECIFIED_JOUNCE))
|
||||
{
|
||||
if (prevJounce > 0.0f)
|
||||
{
|
||||
PX_ASSERT(suspState.jounce == 0.0f); // the expectation is that setToDefault() above does this
|
||||
const PxReal jounceSpeed = (-prevJounce) / dt;
|
||||
const PxVec3 suspDirWorld = PxVehicleComputeSuspensionDirection(suspParams, rigidBodyState.pose);
|
||||
limitSuspensionExpansionVelocity(jounceSpeed, prevJounceSpeed, prevJounce,
|
||||
suspStiffness, suspDamping, suspDirWorld, whlParams.mass, dt, gravity, false,
|
||||
suspState);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PxVec3 suspDir;
|
||||
PxF32 currJounce;
|
||||
PxF32 separation;
|
||||
switch(suspStateCalcParams.suspensionJounceCalculationType)
|
||||
{
|
||||
case PxVehicleSuspensionJounceCalculationType::eRAYCAST:
|
||||
{
|
||||
//Compute the distance along the suspension direction that places the wheel on the ground plane.
|
||||
intersectRayPlane(frame, whlParams, suspParams, steerAngle, roadGeomState, rigidBodyState,
|
||||
prevJounce,
|
||||
suspDir, currJounce, separation);
|
||||
}
|
||||
break;
|
||||
case PxVehicleSuspensionJounceCalculationType::eSWEEP:
|
||||
{
|
||||
//Compute the distance along the suspension direction that places the wheel on the ground plane.
|
||||
intersectCylinderPlane(frame, whlParams, suspParams, steerAngle, roadGeomState, rigidBodyState,
|
||||
prevJounce,
|
||||
suspDir, currJounce, separation);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
PX_ASSERT(false);
|
||||
currJounce = 0.0f;
|
||||
separation = VH_SUSPENSION_NO_INTERSECTION_MARKER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
suspState.jounce = currJounce;
|
||||
suspState.jounceSpeed = (PX_VEHICLE_UNSPECIFIED_JOUNCE != prevJounce) ? (currJounce - prevJounce) / dt : 0.0f;
|
||||
suspState.separation = separation;
|
||||
|
||||
if (suspStateCalcParams.limitSuspensionExpansionVelocity && (suspState.jounceSpeed < 0.0f))
|
||||
{
|
||||
limitSuspensionExpansionVelocity(suspState.jounceSpeed, prevJounceSpeed, prevJounce,
|
||||
suspStiffness, suspDamping, suspDir, whlParams.mass, dt, gravity, true,
|
||||
suspState);
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleSuspensionComplianceUpdate
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehicleSuspensionComplianceParams& compParams,
|
||||
const PxVehicleSuspensionState& suspState,
|
||||
PxVehicleSuspensionComplianceState& compState)
|
||||
{
|
||||
compState.setToDefault();
|
||||
|
||||
//Compliance is normalised in range (0,1) with:
|
||||
//0 being fully elongated (ie jounce = 0)
|
||||
//1 being fully compressed (ie jounce = maxTravelDist)
|
||||
const PxF32 jounce = suspState.jounce;
|
||||
const PxF32 maxTravelDist = suspParams.suspensionTravelDist;
|
||||
const PxF32 r = jounce/maxTravelDist;
|
||||
|
||||
//Camber and toe relative the wheel reference pose.
|
||||
{
|
||||
compState.camber = compParams.wheelCamberAngle.interpolate(r);
|
||||
compState.toe = compParams.wheelToeAngle.interpolate(r);
|
||||
}
|
||||
|
||||
//Tire force application point as an offset from wheel reference pose.
|
||||
{
|
||||
compState.tireForceAppPoint = compParams.tireForceAppPoint.interpolate(r);
|
||||
}
|
||||
|
||||
//Susp force application point as an offset from wheel reference pose.
|
||||
{
|
||||
compState.suspForceAppPoint = compParams.suspForceAppPoint.interpolate(r);
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void setSuspensionForceAndTorque
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehicleRoadGeometryState& roadGeomState, const PxVehicleSuspensionComplianceState& suspComplianceState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxF32 suspForceMagnitude, const PxF32 normalForceMagnitude,
|
||||
PxVehicleSuspensionForce& suspForce)
|
||||
{
|
||||
const PxVec3 r = rigidBodyState.pose.rotate(suspParams.suspensionAttachment.transform(suspComplianceState.suspForceAppPoint));
|
||||
const PxVec3 f = roadGeomState.plane.n*suspForceMagnitude;
|
||||
suspForce.force = f;
|
||||
suspForce.torque = r.cross(f);
|
||||
suspForce.normalForce = normalForceMagnitude;
|
||||
}
|
||||
|
||||
void PxVehicleSuspensionForceUpdate
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehicleSuspensionForceParams& suspForceParams,
|
||||
const PxVehicleRoadGeometryState& roadGeom, const PxVehicleSuspensionState& suspState,
|
||||
const PxVehicleSuspensionComplianceState& compState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxVec3& gravity, const PxReal vehicleMass,
|
||||
PxVehicleSuspensionForce& suspForces)
|
||||
{
|
||||
suspForces.setToDefault();
|
||||
|
||||
//If the wheel cannot touch the ground then carry on with zero force.
|
||||
if (!PxVehicleIsWheelOnGround(suspState))
|
||||
return;
|
||||
|
||||
//For the following computations, the external force Fe acting on the suspension
|
||||
//is seen as the sum of two forces Fe0 and Fe1. Fe0 acts along the suspension
|
||||
//direction while Fe1 is the part perpendicular to Fe0. The suspension spring
|
||||
//force Fs0 works against Fe0, while the suspension "collision" force Fs1 works
|
||||
//against Fe1 (can be seen as a force that is trying to push the suspension
|
||||
//into the ground in a direction where the spring can not do anything against
|
||||
//it because it's perpendicular to the spring direction).
|
||||
//For the system to be at rest, we require Fs0 = -Fe0 and Fs1 = -Fe1
|
||||
//The forces Fe0 and Fe1 can each be split further into parts that act along
|
||||
//the ground patch normal and parts that act parallel to the ground patch.
|
||||
//Fs0 and Fs1 work against the former as the ground prevents the suspension
|
||||
//from penetrating. However, to work against the latter, friction would have
|
||||
//to be considered. The current model does not do this (or rather: it is the
|
||||
//tire model that deals with forces parallel to the ground patch). As a result,
|
||||
//only the force parts of Fs0 and Fs1 perpendicular to the ground patch are
|
||||
//considered here. Furthermore, Fs1 is set to zero, if the external force is
|
||||
//not pushing the suspension towards the ground patch (imagine a vehicle with
|
||||
//a "tilted" suspension direction "driving" up a wall. No "collision" force
|
||||
//should be added in such a scenario).
|
||||
|
||||
PxF32 suspForceMagnitude = 0.0f;
|
||||
{
|
||||
const PxF32 jounce = suspState.jounce;
|
||||
const PxF32 stiffness = suspForceParams.stiffness;
|
||||
const PxF32 jounceSpeed = suspState.jounceSpeed;
|
||||
const PxF32 damping = suspForceParams.damping;
|
||||
|
||||
const PxVec3 suspDirWorld = PxVehicleComputeSuspensionDirection(suspParams, rigidBodyState.pose);
|
||||
const PxVec3 suspSpringForce = suspDirWorld * (-(jounce*stiffness + jounceSpeed*damping));
|
||||
const PxF32 suspSpringForceProjected = roadGeom.plane.n.dot(suspSpringForce);
|
||||
suspForceMagnitude = suspSpringForceProjected;
|
||||
|
||||
const PxVec3 comToSuspWorld = rigidBodyState.pose.rotate(suspParams.suspensionAttachment.p);
|
||||
const PxVec3 externalForceLin = (gravity * vehicleMass) + rigidBodyState.externalForce;
|
||||
|
||||
const PxReal comToSuspDistSqr = comToSuspWorld.magnitudeSquared();
|
||||
PxVec3 externalForceAng;
|
||||
if (comToSuspDistSqr > 0.0f)
|
||||
{
|
||||
// t = r x F
|
||||
// t x r = (r x F) x r = -[r x (r x F)] = -[((r o F) * r) - ((r o r) * F)]
|
||||
// r and F perpendicular (r o F = 0) => = (r o r) * F = |r|^2 * F
|
||||
|
||||
externalForceAng = (rigidBodyState.externalTorque.cross(comToSuspWorld)) / comToSuspDistSqr;
|
||||
}
|
||||
else
|
||||
externalForceAng = PxVec3(PxZero);
|
||||
|
||||
const PxVec3 externalForce = externalForceLin + externalForceAng;
|
||||
|
||||
const PxVec3 externalForceSusp = externalForce * (suspForceParams.sprungMass / vehicleMass);
|
||||
if (roadGeom.plane.n.dot(externalForceSusp) < 0.0f)
|
||||
{
|
||||
const PxF32 suspDirExternalForceMagn = suspDirWorld.dot(externalForceSusp);
|
||||
const PxVec3 collisionForce = externalForceSusp - (suspDirWorld * suspDirExternalForceMagn);
|
||||
const PxF32 suspCollisionForceProjected = -roadGeom.plane.n.dot(collisionForce);
|
||||
suspForceMagnitude += suspCollisionForceProjected;
|
||||
}
|
||||
}
|
||||
|
||||
setSuspensionForceAndTorque(suspParams, roadGeom, compState, rigidBodyState, suspForceMagnitude, suspForceMagnitude, suspForces);
|
||||
}
|
||||
|
||||
void PxVehicleSuspensionLegacyForceUpdate
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehicleSuspensionForceLegacyParams& suspForceParamsLegacy,
|
||||
const PxVehicleRoadGeometryState& roadGeomState, const PxVehicleSuspensionState& suspState,
|
||||
const PxVehicleSuspensionComplianceState& compState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxVec3& gravity,
|
||||
PxVehicleSuspensionForce& suspForces)
|
||||
{
|
||||
suspForces.setToDefault();
|
||||
|
||||
//If the wheel cannot touch the ground then carry on with zero force.
|
||||
if (!PxVehicleIsWheelOnGround(suspState))
|
||||
return;
|
||||
|
||||
PxF32 suspForceMagnitude = 0.0f;
|
||||
{
|
||||
//Get the params for the legacy model.
|
||||
//const PxF32 restDistance = suspForceParamsLegacy.restDistance;
|
||||
const PxF32 sprungMass = suspForceParamsLegacy.sprungMass;
|
||||
const PxF32 restDistance = suspForceParamsLegacy.restDistance;
|
||||
|
||||
//Get the non-legacy params.
|
||||
const PxF32 stiffness = suspForceParamsLegacy.stiffness;
|
||||
const PxF32 damperRate = suspForceParamsLegacy.damping;
|
||||
const PxF32 maxTravelDist = suspParams.suspensionTravelDist;
|
||||
|
||||
//Suspension state.
|
||||
const PxF32 jounce = suspState.jounce;
|
||||
const PxF32 jounceSpeed = suspState.jounceSpeed;
|
||||
|
||||
//Decompose gravity into a term along w and a term perpendicular to w
|
||||
//gravity = w*alpha + T*beta
|
||||
//where T is a unit vector perpendicular to w; alpha and beta are scalars.
|
||||
//The vector w*alpha*mass is the component of gravitational force that acts along the spring direction.
|
||||
//The vector T*beta*mass is the component of gravitational force that will be resisted by the spring
|
||||
//because the spring only supports a single degree of freedom along w.
|
||||
//We only really need to know T*beta so don't bother calculating T or beta.
|
||||
const PxVec3 w = PxVehicleComputeSuspensionDirection(suspParams, rigidBodyState.pose);
|
||||
|
||||
const PxF32 gravitySuspDir = gravity.dot(w);
|
||||
const PxF32 alpha = PxMax(0.0f, gravitySuspDir);
|
||||
const PxVec3 TTimesBeta = (0.0f != alpha) ? gravity - w * alpha : PxVec3(0, 0, 0);
|
||||
//Compute the magnitude of the force along w.
|
||||
PxF32 suspensionForceW =
|
||||
PxMax(0.0f,
|
||||
sprungMass*alpha + //force to support sprung mass at zero jounce
|
||||
stiffness*(jounce + restDistance - maxTravelDist)); //linear spring
|
||||
suspensionForceW += jounceSpeed * damperRate; //damping
|
||||
|
||||
//Compute the total force acting on the suspension.
|
||||
//Remember that the spring force acts along -w.
|
||||
//Remember to account for the term perpendicular to w and that it acts along -TTimesBeta
|
||||
suspForceMagnitude = roadGeomState.plane.n.dot(-w * suspensionForceW - TTimesBeta * sprungMass);
|
||||
|
||||
}
|
||||
|
||||
setSuspensionForceAndTorque(suspParams, roadGeomState, compState, rigidBodyState, suspForceMagnitude, suspForceMagnitude, suspForces);
|
||||
}
|
||||
|
||||
void PxVehicleAntiRollForceUpdate
|
||||
(const PxVehicleArrayData<const PxVehicleSuspensionParams>& suspensionParams,
|
||||
const PxVehicleSizedArrayData<const PxVehicleAntiRollForceParams>& antiRollParams,
|
||||
const PxVehicleArrayData<const PxVehicleSuspensionState>& suspensionStates,
|
||||
const PxVehicleArrayData<const PxVehicleSuspensionComplianceState>& complianceStates,
|
||||
const PxVehicleRigidBodyState& rigidBodyState,
|
||||
PxVehicleAntiRollTorque& antiRollTorque)
|
||||
{
|
||||
antiRollTorque.setToDefault();
|
||||
|
||||
for (PxU32 i = 0; i < antiRollParams.size; i++)
|
||||
{
|
||||
if (antiRollParams[i].stiffness != 0.0f)
|
||||
{
|
||||
const PxU32 w0 = antiRollParams[i].wheel0;
|
||||
const PxU32 w1 = antiRollParams[i].wheel1;
|
||||
|
||||
const bool w0InAir = (0.0f == suspensionStates[w0].jounce);
|
||||
const bool w1InAir = (0.0f == suspensionStates[w1].jounce);
|
||||
|
||||
if (!w0InAir || !w1InAir)
|
||||
{
|
||||
//Compute the difference in jounce and compute the force.
|
||||
const PxF32 w0Jounce = suspensionStates[w0].jounce;
|
||||
const PxF32 w1Jounce = suspensionStates[w1].jounce;
|
||||
const PxF32 antiRollForceMag = (w0Jounce - w1Jounce) * antiRollParams[i].stiffness;
|
||||
|
||||
//Apply the antiRollForce postiviely to wheel0, negatively to wheel 1
|
||||
PxU32 wheelIds[2] = { 0xffffffff, 0xffffffff };
|
||||
PxF32 antiRollForceMags[2];
|
||||
PxU32 numWheelIds = 0;
|
||||
if (!w0InAir)
|
||||
{
|
||||
wheelIds[numWheelIds] = w0;
|
||||
antiRollForceMags[numWheelIds] = -antiRollForceMag;
|
||||
numWheelIds++;
|
||||
}
|
||||
if (!w1InAir)
|
||||
{
|
||||
wheelIds[numWheelIds] = w1;
|
||||
antiRollForceMags[numWheelIds] = +antiRollForceMag;
|
||||
numWheelIds++;
|
||||
}
|
||||
|
||||
for (PxU32 j = 0; j < numWheelIds; j++)
|
||||
{
|
||||
const PxU32 wheelId = wheelIds[j];
|
||||
const PxVec3& antiRollForceDir = suspensionParams[wheelId].suspensionTravelDir;
|
||||
const PxVec3 antiRollForce = antiRollForceDir * antiRollForceMags[j];
|
||||
const PxVec3 r = suspensionParams[wheelId].suspensionAttachment.transform(complianceStates[wheelId].suspForceAppPoint);
|
||||
antiRollTorque.antiRollTorque += rigidBodyState.pose.rotate(r.cross(antiRollForce));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
214
engine/third_party/physx/source/physxvehicle/src/suspension/VhSuspensionHelpers.cpp
vendored
Normal file
214
engine/third_party/physx/source/physxvehicle/src/suspension/VhSuspensionHelpers.cpp
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
#include "vehicle2/PxVehicleMaths.h"
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionHelpers.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
#define DETERMINANT_THRESHOLD (1e-6f)
|
||||
|
||||
bool PxVehicleComputeSprungMasses(const PxU32 numSprungMasses, const PxVec3* sprungMassCoordinates, const PxReal totalMass, const PxVehicleAxes::Enum gravityDir, PxReal* sprungMasses)
|
||||
{
|
||||
if (numSprungMasses < 1)
|
||||
return false;
|
||||
|
||||
if (numSprungMasses > PxVehicleLimits::eMAX_NB_WHEELS)
|
||||
return false;
|
||||
|
||||
if (totalMass <= 0.0f)
|
||||
return false;
|
||||
|
||||
if (!sprungMassCoordinates || !sprungMasses)
|
||||
return false;
|
||||
|
||||
const PxVec3 centreOfMass(PxZero);
|
||||
|
||||
PxU32 gravityDirection = 0xffffffff;
|
||||
switch (gravityDir)
|
||||
{
|
||||
case PxVehicleAxes::eNegX:
|
||||
case PxVehicleAxes::ePosX:
|
||||
gravityDirection = 0;
|
||||
break;
|
||||
case PxVehicleAxes::eNegY:
|
||||
case PxVehicleAxes::ePosY:
|
||||
gravityDirection = 1;
|
||||
break;
|
||||
case PxVehicleAxes::eNegZ:
|
||||
case PxVehicleAxes::ePosZ:
|
||||
gravityDirection = 2;
|
||||
break;
|
||||
default:
|
||||
PX_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (1 == numSprungMasses)
|
||||
{
|
||||
sprungMasses[0] = totalMass;
|
||||
}
|
||||
else if (2 == numSprungMasses)
|
||||
{
|
||||
PxVec3 v = sprungMassCoordinates[0];
|
||||
v[gravityDirection] = 0;
|
||||
PxVec3 w = sprungMassCoordinates[1] - sprungMassCoordinates[0];
|
||||
w[gravityDirection] = 0;
|
||||
w.normalize();
|
||||
|
||||
PxVec3 cm = centreOfMass;
|
||||
cm[gravityDirection] = 0;
|
||||
PxF32 t = w.dot(cm - v);
|
||||
PxVec3 p = v + w * t;
|
||||
|
||||
PxVec3 x0 = sprungMassCoordinates[0];
|
||||
x0[gravityDirection] = 0;
|
||||
PxVec3 x1 = sprungMassCoordinates[1];
|
||||
x1[gravityDirection] = 0;
|
||||
const PxF32 r0 = (x0 - p).dot(w);
|
||||
const PxF32 r1 = (x1 - p).dot(w);
|
||||
|
||||
if (PxAbs(r0 - r1) <= DETERMINANT_THRESHOLD)
|
||||
return false;
|
||||
|
||||
const PxF32 m0 = totalMass * r1 / (r1 - r0);
|
||||
const PxF32 m1 = totalMass - m0;
|
||||
|
||||
sprungMasses[0] = m0;
|
||||
sprungMasses[1] = m1;
|
||||
}
|
||||
else if (3 == numSprungMasses)
|
||||
{
|
||||
const PxU32 d0 = (gravityDirection + 1) % 3;
|
||||
const PxU32 d1 = (gravityDirection + 2) % 3;
|
||||
|
||||
PxVehicleMatrixNN A(3);
|
||||
PxVehicleVectorN b(3);
|
||||
A.set(0, 0, sprungMassCoordinates[0][d0]);
|
||||
A.set(0, 1, sprungMassCoordinates[1][d0]);
|
||||
A.set(0, 2, sprungMassCoordinates[2][d0]);
|
||||
A.set(1, 0, sprungMassCoordinates[0][d1]);
|
||||
A.set(1, 1, sprungMassCoordinates[1][d1]);
|
||||
A.set(1, 2, sprungMassCoordinates[2][d1]);
|
||||
A.set(2, 0, 1.f);
|
||||
A.set(2, 1, 1.f);
|
||||
A.set(2, 2, 1.f);
|
||||
b[0] = totalMass * centreOfMass[d0];
|
||||
b[1] = totalMass * centreOfMass[d1];
|
||||
b[2] = totalMass;
|
||||
|
||||
PxVehicleVectorN result(3);
|
||||
PxVehicleMatrixNNLUSolver solver;
|
||||
solver.decomposeLU(A);
|
||||
if (PxAbs(solver.getDet()) <= DETERMINANT_THRESHOLD)
|
||||
return false;
|
||||
solver.solve(b, result);
|
||||
|
||||
sprungMasses[0] = result[0];
|
||||
sprungMasses[1] = result[1];
|
||||
sprungMasses[2] = result[2];
|
||||
}
|
||||
else if (numSprungMasses >= 4)
|
||||
{
|
||||
const PxU32 d0 = (gravityDirection + 1) % 3;
|
||||
const PxU32 d1 = (gravityDirection + 2) % 3;
|
||||
|
||||
const PxF32 mbar = totalMass / (numSprungMasses*1.0f);
|
||||
|
||||
//See http://en.wikipedia.org/wiki/Lagrange_multiplier
|
||||
//particularly the section on multiple constraints.
|
||||
|
||||
//3 Constraint equations.
|
||||
//g0 = sum_ xi*mi=xcm
|
||||
//g1 = sum_ zi*mi=zcm
|
||||
//g2 = sum_ mi = totalMass
|
||||
//Minimisation function to achieve solution with minimum mass variance.
|
||||
//f = sum_ (mi - mave)^2
|
||||
//Lagrange terms (N equations, N+3 unknowns)
|
||||
//2*mi - xi*lambda0 - zi*lambda1 - 1*lambda2 = 2*mave
|
||||
|
||||
PxVehicleMatrixNN A(numSprungMasses + 3);
|
||||
PxVehicleVectorN b(numSprungMasses + 3);
|
||||
|
||||
//g0, g1, g2
|
||||
for (PxU32 i = 0; i < numSprungMasses; i++)
|
||||
{
|
||||
A.set(0, i, sprungMassCoordinates[i][d0]); //g0
|
||||
A.set(1, i, sprungMassCoordinates[i][d1]); //g1
|
||||
A.set(2, i, 1.0f); //g2
|
||||
}
|
||||
for (PxU32 i = numSprungMasses; i < numSprungMasses + 3; i++)
|
||||
{
|
||||
A.set(0, i, 0); //g0 independent of lambda0,lambda1,lambda2
|
||||
A.set(1, i, 0); //g1 independent of lambda0,lambda1,lambda2
|
||||
A.set(2, i, 0); //g2 independent of lambda0,lambda1,lambda2
|
||||
}
|
||||
b[0] = totalMass * (centreOfMass[d0]); //g0
|
||||
b[1] = totalMass * (centreOfMass[d1]); //g1
|
||||
b[2] = totalMass; //g2
|
||||
|
||||
//Lagrange terms.
|
||||
for (PxU32 i = 0; i < numSprungMasses; i++)
|
||||
{
|
||||
//Off-diagonal terms from the derivative of f
|
||||
for (PxU32 j = 0; j < numSprungMasses; j++)
|
||||
{
|
||||
A.set(i + 3, j, 0);
|
||||
}
|
||||
//Diagonal term from the derivative of f
|
||||
A.set(i + 3, i, 2.f);
|
||||
|
||||
//Derivative of g
|
||||
A.set(i + 3, numSprungMasses + 0, sprungMassCoordinates[i][d0]);
|
||||
A.set(i + 3, numSprungMasses + 1, sprungMassCoordinates[i][d1]);
|
||||
A.set(i + 3, numSprungMasses + 2, 1.0f);
|
||||
|
||||
//rhs.
|
||||
b[i + 3] = 2 * mbar;
|
||||
}
|
||||
|
||||
//Solve Ax=b
|
||||
PxVehicleVectorN result(numSprungMasses + 3);
|
||||
PxVehicleMatrixNNLUSolver solver;
|
||||
solver.decomposeLU(A);
|
||||
solver.solve(b, result);
|
||||
if (PxAbs(solver.getDet()) <= DETERMINANT_THRESHOLD)
|
||||
return false;
|
||||
for (PxU32 i = 0; i < numSprungMasses; i++)
|
||||
{
|
||||
sprungMasses[i] = result[i];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
720
engine/third_party/physx/source/physxvehicle/src/tire/VhTireFunctions.cpp
vendored
Normal file
720
engine/third_party/physx/source/physxvehicle/src/tire/VhTireFunctions.cpp
vendored
Normal file
@@ -0,0 +1,720 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/drivetrain/PxVehicleDrivetrainStates.h"
|
||||
|
||||
#include "vehicle2/rigidBody/PxVehicleRigidBodyStates.h"
|
||||
|
||||
#include "vehicle2/roadGeometry/PxVehicleRoadGeometryState.h"
|
||||
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionHelpers.h"
|
||||
|
||||
#include "vehicle2/tire/PxVehicleTireFunctions.h"
|
||||
#include "vehicle2/tire/PxVehicleTireParams.h"
|
||||
|
||||
#include "vehicle2/wheel/PxVehicleWheelHelpers.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
PX_FORCE_INLINE PxF32 computeFilteredNormalisedTireLoad
|
||||
(const PxF32 xmin, const PxF32 ymin, const PxF32 xmax, const PxF32 ymax, const PxF32 x)
|
||||
{
|
||||
if (x <= xmin)
|
||||
{
|
||||
return ymin;
|
||||
}
|
||||
else if (x >= xmax)
|
||||
{
|
||||
return ymax;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (ymin + (x - xmin)*(ymax - ymin)/ (xmax - xmin));
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleTireDirsLegacyUpdate
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxReal steerAngle, const PxVehicleRoadGeometryState& rdGeomState, const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxVehicleFrame& frame,
|
||||
PxVehicleTireDirectionState& trSlipDirs)
|
||||
{
|
||||
trSlipDirs.setToDefault();
|
||||
|
||||
//If there are no hits we'll have no ground plane.
|
||||
if (!rdGeomState.hitState)
|
||||
return;
|
||||
|
||||
|
||||
//Compute wheel orientation with zero compliance, zero steer and zero
|
||||
//rotation. Ignore rotation because it plays no role due to radial
|
||||
//symmetry of wheel. Steer will be applied to the pose so we can
|
||||
//ignore when computing the orientation. Compliance ought to be applied but
|
||||
//we're not doing this in legacy code.
|
||||
const PxQuat wheelOrientation = PxVehicleComputeWheelOrientation(frame, suspParams, 0.0f, 0.0f, 0.0f,
|
||||
rigidBodyState.pose.q, 0.0f);
|
||||
|
||||
//We need lateral dir and hit norm to project wheel into ground plane.
|
||||
const PxVec3 latDir = wheelOrientation.rotate(frame.getLatAxis());
|
||||
const PxVec3& hitNorm = rdGeomState.plane.n;
|
||||
|
||||
//Compute the tire axes in the ground plane.
|
||||
PxVec3 tLongRaw = latDir.cross(hitNorm);
|
||||
PxVec3 tLatRaw = hitNorm.cross(tLongRaw);
|
||||
tLongRaw.normalize();
|
||||
tLatRaw.normalize();
|
||||
|
||||
//Rotate the tire using the steer angle.
|
||||
const PxF32 yawAngle = steerAngle;
|
||||
const PxF32 cosWheelSteer = PxCos(yawAngle);
|
||||
const PxF32 sinWheelSteer = PxSin(yawAngle);
|
||||
const PxVec3 tLong = tLongRaw * cosWheelSteer + tLatRaw * sinWheelSteer;
|
||||
const PxVec3 tLat = tLatRaw * cosWheelSteer - tLongRaw * sinWheelSteer;
|
||||
|
||||
trSlipDirs.directions[PxVehicleTireDirectionModes::eLATERAL] = tLat;
|
||||
trSlipDirs.directions[PxVehicleTireDirectionModes::eLONGITUDINAL] = tLong;
|
||||
}
|
||||
|
||||
void PxVehicleTireDirsUpdate
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxReal steerAngle, const PxVec3& groundNormal, bool isWheelOnGround,
|
||||
const PxVehicleSuspensionComplianceState& compState,
|
||||
const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxVehicleFrame& frame,
|
||||
PxVehicleTireDirectionState& trSlipDirs)
|
||||
{
|
||||
trSlipDirs.setToDefault();
|
||||
|
||||
//Skip if the suspension could not push the wheel to the ground.
|
||||
if (!isWheelOnGround)
|
||||
return;
|
||||
|
||||
//Compute the wheel quaternion in the world frame.
|
||||
//Ignore rotation because it plays no role due to radial symmetry of wheel.
|
||||
const PxQuat wheelOrientation = PxVehicleComputeWheelOrientation(frame, suspParams, compState.camber, compState.toe, steerAngle,
|
||||
rigidBodyState.pose.q, 0.0f);
|
||||
|
||||
//We need lateral dir and hit norm to project wheel into ground plane.
|
||||
const PxVec3 latDir = wheelOrientation.rotate(frame.getLatAxis());
|
||||
|
||||
//Compute the tire axes in the ground plane.
|
||||
PxVec3 lng = latDir.cross(groundNormal);
|
||||
PxVec3 lat = groundNormal.cross(lng);
|
||||
lng.normalize();
|
||||
lat.normalize();
|
||||
|
||||
//Set the direction vectors.
|
||||
trSlipDirs.directions[PxVehicleTireDirectionModes::eLATERAL] = lat;
|
||||
trSlipDirs.directions[PxVehicleTireDirectionModes::eLONGITUDINAL] = lng;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxF32 computeLateralSlip
|
||||
(const PxF32 lngSpeed, const PxF32 latSpeed, const PxF32 minLatSlipDenominator)
|
||||
{
|
||||
const PxF32 latSlip = PxAtan(latSpeed / (PxAbs(lngSpeed) + minLatSlipDenominator));
|
||||
return latSlip;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxF32 computeLongitudionalSlip
|
||||
(const bool useLegacyLongSlipCalculation,
|
||||
const PxF32 longSpeed,
|
||||
const PxF32 wheelOmega, const PxF32 wheelRadius,
|
||||
const PxF32 minPassiveLongSlipDenominator, const PxF32 minActiveLongSlipDenominator,
|
||||
const bool isAccelApplied, const bool isBrakeApplied)
|
||||
{
|
||||
const PxF32 longSpeedAbs = PxAbs(longSpeed);
|
||||
const PxF32 wheelSpeed = wheelOmega * wheelRadius;
|
||||
const PxF32 wheelSpeedAbs = PxAbs(wheelSpeed);
|
||||
|
||||
PxF32 lngSlip = 0.0f;
|
||||
|
||||
//If nothing is moving just avoid a divide by zero and set the long slip to zero.
|
||||
if (longSpeed == 0 && wheelOmega == 0)
|
||||
{
|
||||
lngSlip = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isBrakeApplied || isAccelApplied)
|
||||
{
|
||||
//Wheel experiencing an applied torque.
|
||||
//Use the raw denominator value plus an offset to avoid anything approaching a divide by zero.
|
||||
//When accelerating from rest the small denominator will generate really quite large
|
||||
//slip values, which will, in turn, generate large longitudinal forces. With large
|
||||
//time-steps this might lead to a temporary oscillation in longSlip direction and an
|
||||
//oscillation in wheel speed direction. The amplitude of the oscillation should be low
|
||||
//unless the timestep is really large.
|
||||
//There's not really an obvious solution to this without setting the denominator offset higher
|
||||
//(or decreasing the timestep). Setting the denominator higher affects handling everywhere so
|
||||
//settling for a potential temporary oscillation is probably the least worst compromise.
|
||||
if (useLegacyLongSlipCalculation)
|
||||
{
|
||||
lngSlip = (wheelSpeed - longSpeed) / (PxMax(longSpeedAbs, wheelSpeedAbs) + minActiveLongSlipDenominator);
|
||||
}
|
||||
else
|
||||
{
|
||||
lngSlip = (wheelSpeed - longSpeed) / (longSpeedAbs + minActiveLongSlipDenominator);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Wheel not experiencing an applied torque.
|
||||
//If the denominator becomes too small then the longSlip becomes large and the longitudinal force
|
||||
//can overshoot zero at large timesteps. This can be really noticeable so it's harder to justify
|
||||
//not taking action. Further, the car isn't being actually driven so there is a strong case to fiddle
|
||||
//with the denominator because it doesn't really affect active handling.
|
||||
//Don't let the denominator fall below a user-specified value. This can be tuned upwards until the
|
||||
//oscillation in the sign of longSlip disappears.
|
||||
if (useLegacyLongSlipCalculation)
|
||||
{
|
||||
lngSlip = (wheelSpeed - longSpeed) / (PxMax(minPassiveLongSlipDenominator, PxMax(longSpeedAbs, wheelSpeedAbs)));
|
||||
}
|
||||
else
|
||||
{
|
||||
lngSlip = (wheelSpeed - longSpeed) / (longSpeedAbs + minPassiveLongSlipDenominator);
|
||||
}
|
||||
}
|
||||
}
|
||||
return lngSlip;
|
||||
}
|
||||
|
||||
void PxVehicleTireSlipSpeedsUpdate
|
||||
(const PxVehicleWheelParams& whlParams, const PxVehicleSuspensionParams& suspParams,
|
||||
const PxF32 steerAngle, const PxVehicleSuspensionState& suspStates, const PxVehicleTireDirectionState& trSlipDirs,
|
||||
const PxVehicleRigidBodyState& rigidBodyState, const PxVehicleRoadGeometryState& roadGeometryState,
|
||||
const PxVehicleFrame& frame,
|
||||
PxVehicleTireSpeedState& trSpeedState)
|
||||
{
|
||||
trSpeedState.setToDefault();
|
||||
|
||||
//Compute the position of the bottom of the wheel (placed on the ground plane).
|
||||
PxVec3 wheelBottomPos;
|
||||
{
|
||||
PxVec3 v,w;
|
||||
PxF32 dist;
|
||||
PxVehicleComputeSuspensionRaycast(frame, whlParams, suspParams, steerAngle, rigidBodyState.pose, v, w, dist);
|
||||
wheelBottomPos = v + w*(dist - suspStates.jounce);
|
||||
}
|
||||
|
||||
//Compute the rigid body velocity at the bottom of the wheel (placed on the ground plane).
|
||||
PxVec3 wheelBottomVel;
|
||||
{
|
||||
const PxVec3 r = wheelBottomPos - rigidBodyState.pose.p;
|
||||
wheelBottomVel = rigidBodyState.linearVelocity + rigidBodyState.angularVelocity.cross(r) - roadGeometryState.velocity;
|
||||
}
|
||||
|
||||
//Comput the velocities along lateral and longitudinal tire directions.
|
||||
trSpeedState.speedStates[PxVehicleTireDirectionModes::eLONGITUDINAL] = wheelBottomVel.dot(trSlipDirs.directions[PxVehicleTireDirectionModes::eLONGITUDINAL]);
|
||||
trSpeedState.speedStates[PxVehicleTireDirectionModes::eLATERAL] = wheelBottomVel.dot(trSlipDirs.directions[PxVehicleTireDirectionModes::eLATERAL]);
|
||||
}
|
||||
|
||||
|
||||
void vehicleTireSlipsUpdate
|
||||
(const PxVehicleWheelParams& whlParams,
|
||||
const PxVehicleTireSlipParams& trSlipParams, const bool useLegacyLongSlipCalculation,
|
||||
const PxVehicleWheelActuationState& actState, PxVehicleTireSpeedState& trSpeedState, const PxVehicleWheelRigidBody1dState& whlRigidBody1dState,
|
||||
PxVehicleTireSlipState& trSlipState)
|
||||
{
|
||||
trSlipState.setToDefault();
|
||||
|
||||
PxF32 latSlip = 0.0f;
|
||||
{
|
||||
const PxF32 lngSpeed = trSpeedState.speedStates[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
const PxF32 latSpeed = trSpeedState.speedStates[PxVehicleTireDirectionModes::eLATERAL];
|
||||
const PxF32 minLatSlipDenominator = trSlipParams.minLatSlipDenominator;
|
||||
latSlip = computeLateralSlip(lngSpeed, latSpeed, minLatSlipDenominator);
|
||||
}
|
||||
|
||||
PxF32 lngSlip = 0.0f;
|
||||
{
|
||||
const PxF32 lngSpeed = trSpeedState.speedStates[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
const PxF32 wheelRotSpeed = whlRigidBody1dState.rotationSpeed;
|
||||
const PxF32 wheelRadius = whlParams.radius;
|
||||
const PxF32 minPassiveLngSlipDenominator = trSlipParams.minPassiveLongSlipDenominator;
|
||||
const PxF32 minActiveLngSlipDenominator = trSlipParams.minActiveLongSlipDenominator;
|
||||
const bool isBrakeApplied = actState.isBrakeApplied;
|
||||
const bool isAccelApplied = actState.isDriveApplied;
|
||||
lngSlip = computeLongitudionalSlip(
|
||||
useLegacyLongSlipCalculation,
|
||||
lngSpeed, wheelRotSpeed, wheelRadius,
|
||||
minPassiveLngSlipDenominator, minActiveLngSlipDenominator,
|
||||
isAccelApplied, isBrakeApplied);
|
||||
}
|
||||
|
||||
trSlipState.slips[PxVehicleTireDirectionModes::eLATERAL] = latSlip;
|
||||
trSlipState.slips[PxVehicleTireDirectionModes::eLONGITUDINAL] = lngSlip;
|
||||
}
|
||||
|
||||
void PxVehicleTireSlipsUpdate
|
||||
(const PxVehicleWheelParams& whlParams,
|
||||
const PxVehicleTireSlipParams& trSlipParams,
|
||||
const PxVehicleWheelActuationState& actState, PxVehicleTireSpeedState& trSpeedState, const PxVehicleWheelRigidBody1dState& whlRigidBody1dState,
|
||||
PxVehicleTireSlipState& trSlipState)
|
||||
{
|
||||
vehicleTireSlipsUpdate(
|
||||
whlParams, trSlipParams, false,
|
||||
actState, trSpeedState, whlRigidBody1dState,
|
||||
trSlipState);
|
||||
}
|
||||
|
||||
void PxVehicleTireSlipsLegacyUpdate
|
||||
(const PxVehicleWheelParams& whlParams,
|
||||
const PxVehicleTireSlipParams& trSlipParams,
|
||||
const PxVehicleWheelActuationState& actState, PxVehicleTireSpeedState& trSpeedState, const PxVehicleWheelRigidBody1dState& whlRigidBody1dState,
|
||||
PxVehicleTireSlipState& trSlipState)
|
||||
{
|
||||
vehicleTireSlipsUpdate(
|
||||
whlParams, trSlipParams, true,
|
||||
actState, trSpeedState, whlRigidBody1dState,
|
||||
trSlipState);
|
||||
|
||||
}
|
||||
|
||||
void PxVehicleTireCamberAnglesUpdate
|
||||
(const PxVehicleSuspensionParams& suspParams,
|
||||
const PxReal steerAngle, const PxVec3& groundNormal, bool isWheelOnGround,
|
||||
const PxVehicleSuspensionComplianceState& compState,
|
||||
const PxVehicleRigidBodyState& rigidBodyState,
|
||||
const PxVehicleFrame& frame,
|
||||
PxVehicleTireCamberAngleState& trCamberAngleState)
|
||||
{
|
||||
trCamberAngleState.setToDefault();
|
||||
|
||||
//Use zero camber if the suspension could not push the wheel to the ground.
|
||||
if (!isWheelOnGround)
|
||||
return;
|
||||
|
||||
//Compute the wheel quaternion in the world frame.
|
||||
//Ignore rotation due to radial symmetry.
|
||||
const PxQuat wheelOrientation = PxVehicleComputeWheelOrientation(frame, suspParams, compState.camber, compState.toe, steerAngle,
|
||||
rigidBodyState.pose.q, 0.0f);
|
||||
|
||||
//Compute the axes of the wheel.
|
||||
const PxVec3 latDir = wheelOrientation.rotate(frame.getLatAxis());
|
||||
const PxVec3 lngDir = wheelOrientation.rotate(frame.getLngAxis());
|
||||
|
||||
//Project normal into lateral/vertical plane.
|
||||
//Start with:
|
||||
//n = lat*alpha + lng*beta + vrt*delta
|
||||
//Want to work out
|
||||
//T = n - lng*beta
|
||||
// = n - lng*(n.dot(lng))
|
||||
//Don't forget to normalise T.
|
||||
//For the angle theta to look for we have:
|
||||
//T.vrtDir = cos(theta)
|
||||
//However, the cosine destroys the sign of the angle, thus we
|
||||
//use:
|
||||
//T.latDir = cos(pi/2 - theta) = sin(theta) (latDir and vrtDir are perpendicular)
|
||||
const PxF32 beta = groundNormal.dot(lngDir);
|
||||
PxVec3 T = groundNormal - lngDir * beta;
|
||||
T.normalize();
|
||||
const PxF32 sinTheta = T.dot(latDir);
|
||||
const PxF32 theta = PxAsin(sinTheta);
|
||||
trCamberAngleState.camberAngle = theta;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxF32 updateLowLngSpeedTimer
|
||||
(const PxF32 lngSpeed, const PxF32 wheelOmega, const PxF32 wheelRadius, const PxF32 lngThresholdSpeed,
|
||||
const bool isIntentionToAccelerate, const PxF32 dt, const PxF32 lowLngSpeedTime)
|
||||
{
|
||||
//If the tire is rotating slowly and the longitudinal speed is slow then increment the slow longitudinal speed timer.
|
||||
//If the intention of the driver is to accelerate the vehicle then reset the timer because the intention has been signalled NOT to bring
|
||||
//the wheel to rest.
|
||||
PxF32 newLowSpeedTime = 0.0f;
|
||||
if ((PxAbs(lngSpeed) < lngThresholdSpeed) && (PxAbs(wheelOmega*wheelRadius) < lngThresholdSpeed) && !isIntentionToAccelerate)
|
||||
{
|
||||
newLowSpeedTime = lowLngSpeedTime + dt;
|
||||
}
|
||||
else
|
||||
{
|
||||
newLowSpeedTime = 0;
|
||||
}
|
||||
return newLowSpeedTime;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void activateStickyFrictionLngConstraint
|
||||
(const PxF32 longSpeed, const PxF32 wheelOmega, const PxF32 lowLngSpeedTime, const bool isIntentionToBrake,
|
||||
const PxF32 thresholdSpeed, const PxF32 thresholdTime,
|
||||
bool& stickyTireActiveFlag)
|
||||
{
|
||||
//Setup the sticky friction constraint to bring the vehicle to rest at the tire contact point.
|
||||
//The idea here is to resolve the singularity of the tire long slip at low vz by replacing the long force with a velocity constraint.
|
||||
//Only do this if we can guarantee that the intention is to bring the car to rest (no accel pedal applied).
|
||||
//We're going to replace the longitudinal tire force with the sticky friction so set the long slip to zero to ensure zero long force.
|
||||
//Apply sticky friction to this tire if
|
||||
//(1) the wheel is locked (this means the brake/handbrake must be on) and the longitudinal speed at the tire contact point is vanishingly small.
|
||||
//(2) the accumulated time of low longitudinal speed is greater than a threshold.
|
||||
stickyTireActiveFlag = false;
|
||||
if (((PxAbs(longSpeed) < thresholdSpeed) && (0.0f == wheelOmega) && isIntentionToBrake) || (lowLngSpeedTime > thresholdTime))
|
||||
{
|
||||
stickyTireActiveFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxF32 updateLowLatSpeedTimer
|
||||
(const PxF32 latSpeed, const bool isIntentionToAccelerate, const PxF32 timestep, const PxF32 thresholdSpeed, const PxF32 lowSpeedTime)
|
||||
{
|
||||
//If the lateral speed is slow then increment the slow lateral speed timer.
|
||||
//If the intention of the driver is to accelerate the vehicle then reset the timer because the intention has been signalled NOT to bring
|
||||
//the wheel to rest.
|
||||
PxF32 newLowSpeedTime = lowSpeedTime;
|
||||
if ((PxAbs(latSpeed) < thresholdSpeed) && !isIntentionToAccelerate)
|
||||
{
|
||||
newLowSpeedTime += timestep;
|
||||
}
|
||||
else
|
||||
{
|
||||
newLowSpeedTime = 0;
|
||||
}
|
||||
return newLowSpeedTime;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void activateStickyFrictionLatConstraint
|
||||
(const bool lowSpeedLngTimerActive,
|
||||
const PxF32 lowLatSpeedTimer, const PxF32 thresholdTime,
|
||||
bool& stickyTireActiveFlag)
|
||||
{
|
||||
//Setup the sticky friction constraint to bring the vehicle to rest at the tire contact point.
|
||||
//Only do this if we can guarantee that the intention is to bring the car to rest (no accel pedal applied).
|
||||
//We're going to replace the lateral tire force with the sticky friction so set the lat slip to zero to ensure zero lat force.
|
||||
//Apply sticky friction to this tire if
|
||||
//(1) the low longitudinal speed timer is > 0.
|
||||
//(2) the accumulated time of low longitudinal speed is greater than a threshold.
|
||||
stickyTireActiveFlag = false;
|
||||
if (lowSpeedLngTimerActive && (lowLatSpeedTimer > thresholdTime))
|
||||
{
|
||||
stickyTireActiveFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PxVehicleTireStickyStateUpdate
|
||||
(const PxVehicleAxleDescription& axleDescription, const PxVehicleWheelParams& whlParams,
|
||||
const PxVehicleTireStickyParams& trStickyParams,
|
||||
const PxVehicleArrayData<const PxVehicleWheelActuationState>& actuationStates,
|
||||
const PxVehicleTireGripState& trGripState, const PxVehicleTireSpeedState& trSpeedState, const PxVehicleWheelRigidBody1dState& whlState,
|
||||
const PxReal dt,
|
||||
PxVehicleTireStickyState& trStickyState)
|
||||
{
|
||||
trStickyState.activeStatus[PxVehicleTireDirectionModes::eLONGITUDINAL] = false;
|
||||
trStickyState.activeStatus[PxVehicleTireDirectionModes::eLATERAL] = false;
|
||||
|
||||
//Only process sticky state if tire can generate force.
|
||||
const PxF32 load = trGripState.load;
|
||||
const PxF32 friction = trGripState.friction;
|
||||
if(0 == load*friction)
|
||||
{
|
||||
trStickyState.lowSpeedTime[PxVehicleTireDirectionModes::eLONGITUDINAL] = 0.0f;
|
||||
trStickyState.lowSpeedTime[PxVehicleTireDirectionModes::eLATERAL] = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
//Work out if any wheel is to have a drive applied to it.
|
||||
bool isIntentionToAccelerate = false;
|
||||
bool isIntentionToBrake = false;
|
||||
for(PxU32 i = 0; i < axleDescription.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = axleDescription.wheelIdsInAxleOrder[i];
|
||||
if(actuationStates[wheelId].isDriveApplied)
|
||||
isIntentionToAccelerate = true;
|
||||
if (actuationStates[wheelId].isBrakeApplied)
|
||||
isIntentionToBrake = true;
|
||||
}
|
||||
|
||||
//Long sticky state.
|
||||
bool lngTimerActive = false;
|
||||
{
|
||||
const PxF32 lngSpeed = trSpeedState.speedStates[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
const PxF32 wheelOmega = whlState.rotationSpeed;
|
||||
const PxF32 wheelRadius = whlParams.radius;
|
||||
const PxF32 lngThresholdSpeed = trStickyParams.stickyParams[PxVehicleTireDirectionModes::eLONGITUDINAL].thresholdSpeed;
|
||||
const PxF32 lngLowSpeedTime = trStickyState.lowSpeedTime[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
|
||||
const PxF32 newLowLngSpeedTime = updateLowLngSpeedTimer(
|
||||
lngSpeed, wheelOmega, wheelRadius, lngThresholdSpeed,
|
||||
isIntentionToAccelerate,
|
||||
dt, lngLowSpeedTime);
|
||||
lngTimerActive = (newLowLngSpeedTime > 0);
|
||||
|
||||
bool lngActiveState = false;
|
||||
const PxF32 lngThresholdTime = trStickyParams.stickyParams[PxVehicleTireDirectionModes::eLONGITUDINAL].thresholdTime;
|
||||
activateStickyFrictionLngConstraint(
|
||||
lngSpeed, wheelOmega, newLowLngSpeedTime, isIntentionToBrake,
|
||||
lngThresholdSpeed, lngThresholdTime,
|
||||
lngActiveState);
|
||||
|
||||
trStickyState.lowSpeedTime[PxVehicleTireDirectionModes::eLONGITUDINAL] = newLowLngSpeedTime;
|
||||
trStickyState.activeStatus[PxVehicleTireDirectionModes::eLONGITUDINAL] = lngActiveState;
|
||||
}
|
||||
|
||||
//Lateral sticky state
|
||||
{
|
||||
const PxF32 latSpeed = trSpeedState.speedStates[PxVehicleTireDirectionModes::eLATERAL];
|
||||
const PxF32 latThresholdSpeed = trStickyParams.stickyParams[PxVehicleTireDirectionModes::eLATERAL].thresholdSpeed;
|
||||
const PxF32 latLowSpeedTime = trStickyState.lowSpeedTime[PxVehicleTireDirectionModes::eLATERAL];
|
||||
const PxF32 latNewLowSpeedTime = updateLowLatSpeedTimer(latSpeed, isIntentionToAccelerate, dt, latThresholdSpeed, latLowSpeedTime);
|
||||
|
||||
bool latActiveState = false;
|
||||
const PxF32 latThresholdTime = trStickyParams.stickyParams[PxVehicleTireDirectionModes::eLATERAL].thresholdTime;
|
||||
activateStickyFrictionLatConstraint(lngTimerActive, latNewLowSpeedTime, latThresholdTime,
|
||||
latActiveState);
|
||||
|
||||
trStickyState.lowSpeedTime[PxVehicleTireDirectionModes::eLATERAL] = latNewLowSpeedTime;
|
||||
trStickyState.activeStatus[PxVehicleTireDirectionModes::eLATERAL] = latActiveState;
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxF32 computeTireLoad
|
||||
(const PxVehicleTireForceParams& trForceParams, const PxVehicleSuspensionForce& suspForce)
|
||||
{
|
||||
//Compute the normalised load.
|
||||
const PxF32 rawLoad = suspForce.normalForce;
|
||||
const PxF32 restLoad = trForceParams.restLoad;
|
||||
const PxF32 normalisedLoad = rawLoad / restLoad;
|
||||
|
||||
//Get the load filter params.
|
||||
const PxF32 minNormalisedLoad = trForceParams.loadFilter[0][0];
|
||||
const PxF32 minFilteredNormalisedLoad = trForceParams.loadFilter[0][1];
|
||||
const PxF32 maxNormalisedLoad = trForceParams.loadFilter[1][0];
|
||||
const PxF32 maxFilteredNormalisedLoad = trForceParams.loadFilter[1][1];
|
||||
|
||||
//Compute the filtered load.
|
||||
const PxF32 filteredNormalisedLoad = computeFilteredNormalisedTireLoad(minNormalisedLoad, minFilteredNormalisedLoad, maxNormalisedLoad, maxFilteredNormalisedLoad, normalisedLoad);
|
||||
const PxF32 filteredLoad = restLoad * filteredNormalisedLoad;
|
||||
|
||||
//Set the load after applying the filter.
|
||||
return filteredLoad;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxF32 computeTireFriction
|
||||
(const PxVehicleTireForceParams& trForceParams,
|
||||
const PxReal frictionCoefficient, const PxVehicleTireSlipState& tireSlipState)
|
||||
{
|
||||
//Interpolate the friction using the long slip value.
|
||||
const PxF32 x0 = trForceParams.frictionVsSlip[0][0];
|
||||
const PxF32 y0 = trForceParams.frictionVsSlip[0][1];
|
||||
const PxF32 x1 = trForceParams.frictionVsSlip[1][0];
|
||||
const PxF32 y1 = trForceParams.frictionVsSlip[1][1];
|
||||
const PxF32 x2 = trForceParams.frictionVsSlip[2][0];
|
||||
const PxF32 y2 = trForceParams.frictionVsSlip[2][1];
|
||||
const PxF32 longSlipAbs = PxAbs(tireSlipState.slips[PxVehicleTireDirectionModes::eLONGITUDINAL]);
|
||||
PxF32 mu;
|
||||
if (longSlipAbs < x1)
|
||||
{
|
||||
mu = y0 + (y1 - y0)*(longSlipAbs - x0) / (x1 - x0);
|
||||
}
|
||||
else if (longSlipAbs < x2)
|
||||
{
|
||||
mu = y1 + (y2 - y1)*(longSlipAbs - x1) / (x2 - x1);
|
||||
}
|
||||
else
|
||||
{
|
||||
mu = y2;
|
||||
}
|
||||
PX_ASSERT(mu >= 0);
|
||||
|
||||
const PxF32 tireFriction = frictionCoefficient * mu;
|
||||
return tireFriction;
|
||||
}
|
||||
|
||||
void PxVehicleTireGripUpdate
|
||||
(const PxVehicleTireForceParams& trForceParams,
|
||||
const PxReal frictionCoefficient, bool isWheelOnGround, const PxVehicleSuspensionForce& suspForce,
|
||||
const PxVehicleTireSlipState& trSlipState,
|
||||
PxVehicleTireGripState& trGripState)
|
||||
{
|
||||
trGripState.setToDefault();
|
||||
|
||||
//If the wheel is not touching the ground then carry on with zero grip state.
|
||||
if (!isWheelOnGround)
|
||||
return;
|
||||
|
||||
//Compute load and friction.
|
||||
trGripState.load = computeTireLoad(trForceParams, suspForce);
|
||||
trGripState.friction = computeTireFriction(trForceParams, frictionCoefficient, trSlipState);
|
||||
}
|
||||
|
||||
void PxVehicleTireSlipsAccountingForStickyStatesUpdate
|
||||
(const PxVehicleTireStickyState& trStickyState,
|
||||
PxVehicleTireSlipState& trSlipState)
|
||||
{
|
||||
if(trStickyState.activeStatus[PxVehicleTireDirectionModes::eLATERAL])
|
||||
trSlipState.slips[PxVehicleTireDirectionModes::eLATERAL] = 0.f;
|
||||
if (trStickyState.activeStatus[PxVehicleTireDirectionModes::eLONGITUDINAL])
|
||||
trSlipState.slips[PxVehicleTireDirectionModes::eLONGITUDINAL] = 0.f;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//Default tire force shader function.
|
||||
//Taken from Michigan tire model.
|
||||
//Computes tire long and lat forces plus the aligning moment arising from
|
||||
//the lat force and the torque to apply back to the wheel arising from the
|
||||
//long force (application of Newton's 3rd law).
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#define ONE_TWENTYSEVENTH 0.037037f
|
||||
#define ONE_THIRD 0.33333f
|
||||
PX_FORCE_INLINE PxF32 smoothingFunction1(const PxF32 K)
|
||||
{
|
||||
//Equation 20 in CarSimEd manual Appendix F.
|
||||
//Looks a bit like a curve of sqrt(x) for 0<x<1 but reaching 1.0 on y-axis at K=3.
|
||||
PX_ASSERT(K >= 0.0f);
|
||||
return PxMin(1.0f, K - ONE_THIRD * K*K + ONE_TWENTYSEVENTH * K*K*K);
|
||||
}
|
||||
PX_FORCE_INLINE PxF32 smoothingFunction2(const PxF32 K)
|
||||
{
|
||||
//Equation 21 in CarSimEd manual Appendix F.
|
||||
//Rises to a peak at K=0.75 and falls back to zero by K=3
|
||||
PX_ASSERT(K >= 0.0f);
|
||||
return (K - K * K + ONE_THIRD * K*K*K - ONE_TWENTYSEVENTH * K*K*K*K);
|
||||
}
|
||||
|
||||
void computeTireForceMichiganModel
|
||||
(const PxVehicleTireForceParams& tireData,
|
||||
const PxF32 tireFriction,
|
||||
const PxF32 longSlipUnClamped, const PxF32 latSlipUnClamped, const PxF32 camberUnclamped,
|
||||
const PxF32 wheelRadius,
|
||||
const PxF32 tireLoad,
|
||||
PxF32& wheelTorque, PxF32& tireLongForceMag, PxF32& tireLatForceMag, PxF32& tireAlignMoment)
|
||||
{
|
||||
PX_ASSERT(tireFriction > 0);
|
||||
PX_ASSERT(tireLoad > 0);
|
||||
|
||||
wheelTorque = 0.0f;
|
||||
tireLongForceMag = 0.0f;
|
||||
tireLatForceMag = 0.0f;
|
||||
tireAlignMoment = 0.0f;
|
||||
|
||||
//Clamp the slips to a minimum value.
|
||||
const PxF32 minimumSlipThreshold = 1e-5f;
|
||||
const PxF32 latSlip = PxAbs(latSlipUnClamped) >= minimumSlipThreshold ? latSlipUnClamped : 0.0f;
|
||||
const PxF32 longSlip = PxAbs(longSlipUnClamped) >= minimumSlipThreshold ? longSlipUnClamped : 0.0f;
|
||||
const PxF32 camber = PxAbs(camberUnclamped) >= minimumSlipThreshold ? camberUnclamped : 0.0f;
|
||||
|
||||
//Normalise the tire load.
|
||||
const PxF32 restTireLoad = tireData.restLoad;
|
||||
const PxF32 normalisedTireLoad = tireLoad/ restTireLoad;
|
||||
|
||||
//Compute the lateral stiffness
|
||||
const PxF32 latStiff = (0.0f == tireData.latStiffX) ? tireData.latStiffY : tireData.latStiffY*smoothingFunction1(normalisedTireLoad*3.0f / tireData.latStiffX);
|
||||
|
||||
//Get the longitudinal stiffness
|
||||
const PxF32 longStiff = tireData.longStiff;
|
||||
|
||||
//Get the camber stiffness.
|
||||
const PxF32 camberStiff = tireData.camberStiff;
|
||||
|
||||
//If long slip/lat slip/camber are all zero than there will be zero tire force.
|
||||
if ((0 == latSlip*latStiff) && (0 == longSlip*longStiff) && (0 == camber*camberStiff))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Carry on and compute the forces.
|
||||
const PxF32 TEff = PxTan(latSlip + (camber * camberStiff / latStiff)); // "+" because we define camber stiffness as a positive value
|
||||
const PxF32 K = PxSqrt(latStiff*TEff*latStiff*TEff + longStiff * longSlip*longStiff*longSlip) / (tireFriction*tireLoad);
|
||||
//const PxF32 KAbs=PxAbs(K);
|
||||
PxF32 FBar = smoothingFunction1(K);//K - ONE_THIRD*PxAbs(K)*K + ONE_TWENTYSEVENTH*K*K*K;
|
||||
PxF32 MBar = smoothingFunction2(K); //K - KAbs*K + ONE_THIRD*K*K*K - ONE_TWENTYSEVENTH*KAbs*K*K*K;
|
||||
//Mbar = PxMin(Mbar, 1.0f);
|
||||
PxF32 nu = 1;
|
||||
if (K <= 2.0f*PxPi)
|
||||
{
|
||||
const PxF32 latOverlLong = latStiff/longStiff;
|
||||
nu = 0.5f*(1.0f + latOverlLong - (1.0f - latOverlLong)*PxCos(K*0.5f));
|
||||
}
|
||||
const PxF32 FZero = tireFriction * tireLoad / (PxSqrt(longSlip*longSlip + nu * TEff*nu*TEff));
|
||||
const PxF32 fz = longSlip * FBar*FZero;
|
||||
const PxF32 fx = -nu * TEff*FBar*FZero;
|
||||
//TODO: pneumatic trail.
|
||||
const PxF32 pneumaticTrail = 1.0f;
|
||||
const PxF32 fMy = nu * pneumaticTrail * TEff * MBar * FZero;
|
||||
|
||||
//We can add the torque to the wheel.
|
||||
wheelTorque = -fz * wheelRadius;
|
||||
tireLongForceMag = fz;
|
||||
tireLatForceMag = fx;
|
||||
tireAlignMoment = fMy;
|
||||
}
|
||||
|
||||
void PxVehicleTireForcesUpdate
|
||||
(const PxVehicleWheelParams& whlParams, const PxVehicleSuspensionParams& suspParams,
|
||||
const PxVehicleTireForceParams& trForceParams,
|
||||
const PxVehicleSuspensionComplianceState& compState,
|
||||
const PxVehicleTireGripState& trGripState, const PxVehicleTireDirectionState& trDirectionState,
|
||||
const PxVehicleTireSlipState& trSlipState, const PxVehicleTireCamberAngleState& cmbAngleState,
|
||||
const PxVehicleRigidBodyState& rigidBodyState,
|
||||
PxVehicleTireForce& trForce)
|
||||
{
|
||||
trForce.setToDefault();
|
||||
|
||||
//If the tire can generate no force then carry on with zero force.
|
||||
if(0 == trGripState.friction*trGripState.load)
|
||||
return;
|
||||
|
||||
PxF32 wheelTorque = 0;
|
||||
PxF32 tireLongForceMag = 0;
|
||||
PxF32 tireLatForceMag = 0;
|
||||
PxF32 tireAlignMoment = 0;
|
||||
|
||||
const PxF32 friction = trGripState.friction;
|
||||
const PxF32 tireLoad = trGripState.load;
|
||||
const PxF32 lngSlip = trSlipState.slips[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
const PxF32 latSlip = trSlipState.slips[PxVehicleTireDirectionModes::eLATERAL];
|
||||
const PxF32 camber = cmbAngleState.camberAngle;
|
||||
const PxF32 wheelRadius = whlParams.radius;
|
||||
computeTireForceMichiganModel(trForceParams, friction, lngSlip, latSlip, camber, wheelRadius, tireLoad,
|
||||
wheelTorque, tireLongForceMag, tireLatForceMag, tireAlignMoment);
|
||||
|
||||
//Compute the forces.
|
||||
const PxVec3 tireLongForce = trDirectionState.directions[PxVehicleTireDirectionModes::eLONGITUDINAL]*tireLongForceMag;
|
||||
const PxVec3 tireLatForce = trDirectionState.directions[PxVehicleTireDirectionModes::eLATERAL]*tireLatForceMag;
|
||||
|
||||
//Compute the torques.
|
||||
const PxVec3 r = rigidBodyState.pose.rotate(suspParams.suspensionAttachment.transform(compState.tireForceAppPoint));
|
||||
const PxVec3 tireLongTorque = r.cross(tireLongForce);
|
||||
const PxVec3 tireLatTorque = r.cross(tireLatForce);
|
||||
|
||||
//Set the torques.
|
||||
trForce.forces[PxVehicleTireDirectionModes::eLONGITUDINAL] = tireLongForce;
|
||||
trForce.torques[PxVehicleTireDirectionModes::eLONGITUDINAL] = tireLongTorque;
|
||||
trForce.forces[PxVehicleTireDirectionModes::eLATERAL] = tireLatForce;
|
||||
trForce.torques[PxVehicleTireDirectionModes::eLATERAL] = tireLatTorque;
|
||||
trForce.aligningMoment = tireAlignMoment;
|
||||
trForce.wheelTorque = wheelTorque;
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
|
||||
65
engine/third_party/physx/source/physxvehicle/src/tire/VhTireHelpers.cpp
vendored
Normal file
65
engine/third_party/physx/source/physxvehicle/src/tire/VhTireHelpers.cpp
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/tire/PxVehicleTireHelpers.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
bool PxVehicleAccelerationIntentCompute
|
||||
(const PxVehicleAxleDescription& driveVehicleAxleDesc, const PxVehicleArrayData<const PxVehicleWheelActuationState>& driveVehicleActuationStates)
|
||||
{
|
||||
bool isIntentionToAccelerate = false;
|
||||
for (PxU32 i = 0; i < driveVehicleAxleDesc.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = driveVehicleAxleDesc.wheelIdsInAxleOrder[i];
|
||||
isIntentionToAccelerate = !isIntentionToAccelerate ? driveVehicleActuationStates[wheelId].isDriveApplied : isIntentionToAccelerate;
|
||||
}
|
||||
return isIntentionToAccelerate;
|
||||
}
|
||||
|
||||
void PxVehicleTireStickyStateReset
|
||||
(const bool intentionToAccelerate,
|
||||
const PxVehicleAxleDescription& towedVehicleAxleDesc,
|
||||
PxVehicleArrayData<PxVehicleTireStickyState>& towedVehicleStickyState)
|
||||
{
|
||||
if (!intentionToAccelerate)
|
||||
return;
|
||||
|
||||
for (PxU32 i = 0; i < towedVehicleAxleDesc.nbWheels; i++)
|
||||
{
|
||||
const PxU32 wheelId = towedVehicleAxleDesc.wheelIdsInAxleOrder[i];
|
||||
towedVehicleStickyState[wheelId].setToDefault();
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
|
||||
92
engine/third_party/physx/source/physxvehicle/src/wheel/VhWheelFunctions.cpp
vendored
Normal file
92
engine/third_party/physx/source/physxvehicle/src/wheel/VhWheelFunctions.cpp
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "vehicle2/PxVehicleParams.h"
|
||||
|
||||
#include "vehicle2/suspension/PxVehicleSuspensionStates.h"
|
||||
|
||||
#include "vehicle2/tire/PxVehicleTireStates.h"
|
||||
|
||||
#include "vehicle2/wheel/PxVehicleWheelFunctions.h"
|
||||
#include "vehicle2/wheel/PxVehicleWheelStates.h"
|
||||
#include "vehicle2/wheel/PxVehicleWheelParams.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace vehicle2
|
||||
{
|
||||
|
||||
void PxVehicleWheelRotationAngleUpdate
|
||||
(const PxVehicleWheelParams& whlParams,
|
||||
const PxVehicleWheelActuationState& actState, const PxVehicleSuspensionState& suspState, const PxVehicleTireSpeedState& trSpeedState,
|
||||
const PxReal thresholdForwardSpeedForWheelAngleIntegration, const PxReal dt,
|
||||
PxVehicleWheelRigidBody1dState& whlRigidBody1dState)
|
||||
{
|
||||
//At low vehicle forward speeds we have some numerical difficulties getting the
|
||||
//wheel rotation speeds to be correct due to the tire model's difficulties at low vz.
|
||||
//The solution is to blend between the rolling speed at the wheel and the wheel's actual rotation speed.
|
||||
//If the wheel is
|
||||
//(i) in the air or,
|
||||
//(ii) under braking torque or,
|
||||
//(iii) driven by a drive torque
|
||||
//then always use the wheel's actual rotation speed.
|
||||
//Just to be clear, this means we will blend when the wheel
|
||||
//(i) is on the ground and
|
||||
//(ii) has no brake applied and
|
||||
//(iii) has no drive torque and
|
||||
//(iv) is at low forward speed
|
||||
const PxF32 jounce = suspState.jounce;
|
||||
const bool isBrakeApplied = actState.isBrakeApplied;
|
||||
const bool isDriveApplied = actState.isDriveApplied;
|
||||
const PxF32 lngSpeed = trSpeedState.speedStates[PxVehicleTireDirectionModes::eLONGITUDINAL];
|
||||
const PxF32 absLngSpeed = PxAbs(lngSpeed);
|
||||
PxF32 wheelOmega = whlRigidBody1dState.rotationSpeed;
|
||||
if (jounce > 0 && //(i) wheel touching ground
|
||||
!isBrakeApplied && //(ii) no brake applied
|
||||
!isDriveApplied && //(iii) no drive torque applied
|
||||
(absLngSpeed < thresholdForwardSpeedForWheelAngleIntegration)) //(iv) low speed
|
||||
{
|
||||
const PxF32 wheelRadius = whlParams.radius;
|
||||
const PxF32 alpha = absLngSpeed / thresholdForwardSpeedForWheelAngleIntegration;
|
||||
wheelOmega = (lngSpeed/wheelRadius)*(1.0f - alpha) + wheelOmega * alpha;
|
||||
}
|
||||
|
||||
whlRigidBody1dState.correctedRotationSpeed = wheelOmega;
|
||||
|
||||
//Integrate angle.
|
||||
PxF32 newRotAngle = whlRigidBody1dState.rotationAngle + wheelOmega * dt;
|
||||
|
||||
//Clamp in range (-2*Pi,2*Pi)
|
||||
newRotAngle = newRotAngle - (PxI32(newRotAngle / PxTwoPi) * PxTwoPi);
|
||||
|
||||
//Set the angle.
|
||||
whlRigidBody1dState.rotationAngle = newRotAngle;
|
||||
}
|
||||
|
||||
} //namespace vehicle2
|
||||
} //namespace physx
|
||||
Reference in New Issue
Block a user