include/vehicle2/drivetrain/PxVehicleDrivetrainParams.h
File members: include/vehicle2/drivetrain/PxVehicleDrivetrainParams.h
// 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-2023 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 "foundation/PxFoundation.h"
#include "common/PxCoreUtilityTypes.h"
#include "vehicle2/PxVehicleParams.h"
#include "vehicle2/commands/PxVehicleCommandParams.h"
#if !PX_DOXYGEN
namespace physx
{
namespace vehicle2
{
#endif
struct PxVehicleDirectDriveThrottleCommandResponseParams : public PxVehicleCommandResponseParams
{
PX_FORCE_INLINE PxVehicleDirectDriveThrottleCommandResponseParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
PxVehicleDirectDriveThrottleCommandResponseParams r = *this;
const PxReal scale = trgScale.scale/srcScale.scale;
r.maxResponse *= (scale*scale); //Max response is a torque!
return r;
}
PX_FORCE_INLINE bool isValid(const PxVehicleAxleDescription& axleDesc) const
{
PX_CHECK_AND_RETURN_VAL(PxIsFinite(maxResponse), "PxVehicleDirectDriveThrottleCommandResponseParams.maxResponse must be a finite value", false);
for (PxU32 i = 0; i < axleDesc.nbWheels; i++)
{
PX_CHECK_AND_RETURN_VAL(PxIsFinite(wheelResponseMultipliers[axleDesc.wheelIdsInAxleOrder[i]]), "PxVehicleDirectDriveThrottleCommandResponseParams.wheelResponseMultipliers[i] must be a finite value", false);
}
return true;
}
};
struct PxVehicleClutchCommandResponseParams
{
PxReal maxResponse;
PX_FORCE_INLINE PxVehicleClutchCommandResponseParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
const PxReal scale = trgScale.scale/srcScale.scale;
PxVehicleClutchCommandResponseParams r = *this;
r.maxResponse *= (scale*scale);
return r;
}
PX_FORCE_INLINE bool isValid() const
{
PX_CHECK_AND_RETURN_VAL(maxResponse >= 0.0f, "PxVehicleClutchCommandResponseParams.maxResponse must be greater than or equal to zero", false);
return true;
}
};
struct PxVehicleClutchAccuracyMode
{
enum Enum
{
eESTIMATE = 0,
eBEST_POSSIBLE
};
};
struct PxVehicleClutchParams
{
public:
PxVehicleClutchAccuracyMode::Enum accuracyMode;
PxU32 estimateIterations;
PX_FORCE_INLINE PxVehicleClutchParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
PX_UNUSED(srcScale);
PX_UNUSED(trgScale);
return *this;
}
PX_FORCE_INLINE bool isValid() const
{
PX_CHECK_AND_RETURN_VAL((PxVehicleClutchAccuracyMode::eBEST_POSSIBLE == accuracyMode) || ((PxVehicleClutchAccuracyMode::eESTIMATE == accuracyMode) && (estimateIterations > 0)), "PxVehicleClutchParams.estimateIterations must be greater than zero if PxVehicleClutchAccuracyMode::eESTIMATE is selected", false);
return true;
}
};
struct PxVehicleEngineParams
{
enum
{
eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES = 8
};
PxVehicleFixedSizeLookupTable<PxReal, eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES> torqueCurve;
PxReal moi;
PxReal peakTorque;
PxReal idleOmega;
PxReal maxOmega;
PxReal dampingRateFullThrottle;
PxReal dampingRateZeroThrottleClutchEngaged;
PxReal dampingRateZeroThrottleClutchDisengaged;
PX_FORCE_INLINE PxVehicleEngineParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
PxVehicleEngineParams r = *this;
const PxReal scale = trgScale.scale/srcScale.scale;
r.moi *= (scale*scale);
r.peakTorque *= (scale*scale);
r.dampingRateFullThrottle *= (scale*scale);
r.dampingRateZeroThrottleClutchDisengaged *= (scale*scale);
r.dampingRateZeroThrottleClutchEngaged *= (scale*scale);
return r;
}
PX_FORCE_INLINE bool isValid() const
{
PX_CHECK_AND_RETURN_VAL(moi > 0.0f, "PxVehicleEngineParams.moi must be greater than zero", false);
PX_CHECK_AND_RETURN_VAL(peakTorque >= 0.0f, "PxVehicleEngineParams.peakTorque must be greater than or equal to zero", false);
PX_CHECK_AND_RETURN_VAL(torqueCurve.isValid(), "PxVehicleEngineParams.torqueCurve is invalid", false);
PX_CHECK_AND_RETURN_VAL(maxOmega >= 0.0f, "PxVehicleEngineParams.maxOmega must be greater than or equal to zero", false);
PX_CHECK_AND_RETURN_VAL(idleOmega >= 0.0f, "PxVehicleEngineParams.idleOmega must be greater or equal to zero", false);
PX_CHECK_AND_RETURN_VAL(dampingRateFullThrottle >= 0.0f, "PxVehicleEngineParams.dampingRateFullThrottle must be greater than or equal to zero", false);
PX_CHECK_AND_RETURN_VAL(dampingRateZeroThrottleClutchEngaged >= 0.0f, "PxVehicleEngineParams.dampingRateZeroThrottleClutchEngaged must be greater than or equal to zero", false);
PX_CHECK_AND_RETURN_VAL(dampingRateZeroThrottleClutchDisengaged >= 0.0f, "PxVehicleEngineParams.dampingRateZeroThrottleClutchDisengaged must be greater than or equal to zero", false)
return true;
}
};
struct PxVehicleGearboxParams
{
public:
PxU32 neutralGear;
enum Enum
{
eMAX_NB_GEARS = 32
};
PxReal ratios[eMAX_NB_GEARS];
PxReal finalRatio;
PxU32 nbRatios;
PxReal switchTime;
PX_FORCE_INLINE PxVehicleGearboxParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
PX_UNUSED(srcScale);
PX_UNUSED(trgScale);
return *this;
}
PX_FORCE_INLINE bool isValid() const
{
PX_CHECK_AND_RETURN_VAL(finalRatio > 0, "PxVehicleGearboxParams.finalRatio must be greater than zero", false);
PX_CHECK_AND_RETURN_VAL(nbRatios >= 1, "PxVehicleGearboxParams.nbRatios must be greater than zero", false);
PX_CHECK_AND_RETURN_VAL(nbRatios <= eMAX_NB_GEARS, "PxVehicleGearboxParams.nbRatios must be less than or equal to eMAX_NB_GEARS", false);
PX_CHECK_AND_RETURN_VAL(neutralGear < nbRatios, "PxVehicleGearboxParams.neutralGear must be less than PxVehicleGearboxParams.nbRatios", false);
PX_CHECK_AND_RETURN_VAL(switchTime >= 0.0f, "PxVehicleGearboxParams.switchTime must be greater than or equal to zero", false);
for(PxU32 i = 0; i < neutralGear; i++)
{
PX_CHECK_AND_RETURN_VAL(ratios[i] < 0.0f, "Reverse gear ratios must be less than zero", false);
}
{
PX_CHECK_AND_RETURN_VAL(ratios[neutralGear] == 0.0f, "Neutral gear ratio must be equal to zero", false);
}
for (PxU32 i = neutralGear + 1; i < nbRatios; i++)
{
PX_CHECK_AND_RETURN_VAL(ratios[i] > 0.0f, "Forward gear ratios must be greater than zero", false);
}
for (PxU32 i = neutralGear + 2; i < nbRatios; i++)
{
PX_CHECK_AND_RETURN_VAL(ratios[i] < ratios[i - 1], "Forward gear ratios must be a descending sequence of gear ratios", false);
}
return true;
}
};
struct PxVehicleAutoboxParams
{
public:
PxReal upRatios[PxVehicleGearboxParams::eMAX_NB_GEARS];
PxReal downRatios[PxVehicleGearboxParams::eMAX_NB_GEARS];
PxReal latency;
PX_FORCE_INLINE PxVehicleAutoboxParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
PX_UNUSED(srcScale);
PX_UNUSED(trgScale);
return *this;
}
PX_FORCE_INLINE bool isValid(const PxVehicleGearboxParams& gearboxParams) const
{
if (!gearboxParams.isValid())
return false;
for (PxU32 i = gearboxParams.neutralGear + 1; i < gearboxParams.nbRatios-1; i++)
{
PX_CHECK_AND_RETURN_VAL(upRatios[i] >= 0.0f, "PxVehicleAutoboxParams.upRatios must be greater than or equal to zero", false);
}
for (PxU32 i = gearboxParams.neutralGear + 2; i < gearboxParams.nbRatios; i++)
{
PX_CHECK_AND_RETURN_VAL(downRatios[i] >= 0.0f, "PxVehicleAutoboxParams.downRatios must be greater than or equal to zero", false);
}
PX_CHECK_AND_RETURN_VAL(latency >= 0.0f, "PxVehicleAutoboxParams.latency must be greater than or equal to zero", false);
return true;
}
};
struct PX_DEPRECATED PxVehicleFourWheelDriveDifferentialLegacyParams
{
public:
enum Enum
{
eDIFF_TYPE_LS_4WD, //limited slip differential for car with 4 driven wheels
eDIFF_TYPE_LS_FRONTWD, //limited slip differential for car with front-wheel drive
eDIFF_TYPE_LS_REARWD, //limited slip differential for car with rear-wheel drive
eMAX_NB_DIFF_TYPES
};
PxU32 frontWheelIds[2];
PxU32 rearWheelIds[2];
PxReal frontRearSplit;
PxReal frontNegPosSplit;
PxReal rearNegPosSplit;
PxReal centerBias;
PxReal frontBias;
PxReal rearBias;
Enum type;
PX_FORCE_INLINE PxVehicleFourWheelDriveDifferentialLegacyParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
PX_UNUSED(srcScale);
PX_UNUSED(trgScale);
return *this;
}
PX_FORCE_INLINE bool isValid(const PxVehicleAxleDescription& axleDesc) const
{
PX_UNUSED(axleDesc);
PX_CHECK_AND_RETURN_VAL((axleDesc.getAxle(frontWheelIds[0]) != 0xffffffff) && (axleDesc.getAxle(frontWheelIds[0])== axleDesc.getAxle(frontWheelIds[1])), "frontWheelIds[0] and frontWheelIds[1] must reference wheels on the same axle", false);
PX_CHECK_AND_RETURN_VAL((axleDesc.getAxle(rearWheelIds[0]) != 0xffffffff) && (axleDesc.getAxle(rearWheelIds[0]) == axleDesc.getAxle(rearWheelIds[1])), "rearWheelIds[0] and rearWheelIds[1] must reference wheels on the same axle", false);
PX_CHECK_AND_RETURN_VAL(frontRearSplit <= 1.0f && frontRearSplit >= 0.0f, "PxVehicleLegacyFourWheelDriveDifferentialParams.frontRearSplit must be in range [0,1]", false);
PX_CHECK_AND_RETURN_VAL(frontNegPosSplit <= 1.0f && frontNegPosSplit >= 0.0f, "PxVehicleLegacyFourWheelDriveDifferentialParams.frontNegPosSplit must be in range [0,1]", false);
PX_CHECK_AND_RETURN_VAL(rearNegPosSplit <= 1.0f && rearNegPosSplit >= 0.0f, "PxVehicleLegacyFourWheelDriveDifferentialParams.rearNegPosSplit must be in range [0,1]", false);
PX_CHECK_AND_RETURN_VAL(centerBias >= 1.0f, "PxVehicleLegacyFourWheelDriveDifferentialParams.centerBias must be greater than or equal to 1.0f", false);
PX_CHECK_AND_RETURN_VAL(frontBias >= 1.0f, "PxVehicleLegacyFourWheelDriveDifferentialParams.frontBias must be greater than or equal to 1.0f", false);
PX_CHECK_AND_RETURN_VAL(rearBias >= 1.0f, "PxVehicleLegacyFourWheelDriveDifferentialParams.rearBias must be greater than or equal to 1.0f", false);
PX_CHECK_AND_RETURN_VAL(type < PxVehicleFourWheelDriveDifferentialLegacyParams::eMAX_NB_DIFF_TYPES, "PxVehicleLegacyFourWheelDriveDifferentialParams.type has illegal value", false);
return true;
}
};
struct PxVehicleMultiWheelDriveDifferentialParams
{
PxReal torqueRatios[PxVehicleLimits::eMAX_NB_WHEELS];
PxReal aveWheelSpeedRatios[PxVehicleLimits::eMAX_NB_WHEELS];
PX_FORCE_INLINE void setToDefault()
{
PxMemZero(this, sizeof(PxVehicleMultiWheelDriveDifferentialParams));
}
PX_FORCE_INLINE PxVehicleMultiWheelDriveDifferentialParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
PX_UNUSED(srcScale);
PX_UNUSED(trgScale);
return *this;
}
PX_FORCE_INLINE bool isValid(const PxVehicleAxleDescription& axleDesc) const
{
if (!axleDesc.isValid())
return false;
PxReal aveWheelSpeedSum = 0.0f;
PxReal torqueRatioSum = 0.0f;
for (PxU32 i = 0; i < axleDesc.nbWheels; i++)
{
const PxU32 wheelId = axleDesc.wheelIdsInAxleOrder[i];
PX_CHECK_AND_RETURN_VAL(PxAbs(torqueRatios[wheelId]) <= 1.0f, "PxVehicleMultiWheelDriveDifferentialParams.torqueRatios[i] must be in range [-1, 1] for all wheels connected to the differential", false);
PX_CHECK_AND_RETURN_VAL(aveWheelSpeedRatios[wheelId] >= 0.0f && aveWheelSpeedRatios[wheelId] <= 1.0f, "PxVehicleMultiWheelDriveDifferentialParams.aveWheelSpeedRatios[i] must be in range [0, 1] for all wheels connected to the differential", false);
aveWheelSpeedSum += aveWheelSpeedRatios[wheelId];
torqueRatioSum += PxAbs(torqueRatios[wheelId]);
}
PX_CHECK_AND_RETURN_VAL(aveWheelSpeedSum >= 0.99f && aveWheelSpeedSum <= 1.01f, "Sum of PxVehicleMultiWheelDriveDifferentialParams.aveWheelSpeedRatios[i] must be 1.0.", false);
PX_CHECK_AND_RETURN_VAL(torqueRatioSum >= 0.99f && torqueRatioSum <= 1.01f, "Sum of PxVehicleMultiWheelDriveDifferentialParams.torqueRatios[i] must be 1.0.", false);
PX_UNUSED(aveWheelSpeedSum);
PX_UNUSED(torqueRatioSum);
return true;
}
};
#define PX_VEHICLE_FOUR_WHEEL_DIFFERENTIAL_MAXIMUM_STRENGTH PX_MAX_F32
struct PxVehicleFourWheelDriveDifferentialParams : public PxVehicleMultiWheelDriveDifferentialParams
{
PxU32 frontWheelIds[2];
PxU32 rearWheelIds[2];
PxReal frontBias;
PxReal frontTarget;
PxReal rearBias;
PxReal rearTarget;
PxReal centerBias;
PxReal centerTarget;
PxReal rate;
PX_FORCE_INLINE void setToDefault()
{
PxVehicleMultiWheelDriveDifferentialParams::setToDefault();
frontBias = 0.0f;
rearBias = 0.0f;
centerBias = 0.0f;
}
PX_FORCE_INLINE bool isValid(const PxVehicleAxleDescription& axleDesc) const
{
if (!PxVehicleMultiWheelDriveDifferentialParams::isValid(axleDesc))
return false;
PX_CHECK_AND_RETURN_VAL((0.0f == centerBias) ||
(centerBias > 1.0f &&
frontWheelIds[0] < axleDesc.nbWheels && frontWheelIds[1] < axleDesc.nbWheels &&
rearWheelIds[0] < axleDesc.nbWheels && rearWheelIds[1] < axleDesc.nbWheels),
"PxVehicleFourWheelDriveDifferentialParams:: centreBias is enabled but the frontWheelIds and rearWheelIds are not configured correctly.", false);
PX_CHECK_AND_RETURN_VAL((0.0f == centerBias) ||
(centerBias > 1.0f &&
frontWheelIds[0] != frontWheelIds[1] && frontWheelIds[0] != rearWheelIds[0] && frontWheelIds[0] != rearWheelIds[1] &&
frontWheelIds[1] != rearWheelIds[0] && frontWheelIds[1] != rearWheelIds[1] &&
rearWheelIds[0] != rearWheelIds[1]),
"PxVehicleFourWheelDriveDifferentialParams:: centreBias is enabled but the frontWheelIds and rearWheelIds are not configured correctly.", false);
PX_CHECK_AND_RETURN_VAL((0.0f == centerBias) ||
(centerBias > 1.0f &&
torqueRatios[frontWheelIds[0]] != 0.0f && torqueRatios[frontWheelIds[1]] != 0.0f && torqueRatios[rearWheelIds[0]] != 0.0f && torqueRatios[rearWheelIds[1]] != 0.0f),
"PxVehicleFourWheelDriveDifferentialParams:: centreBias is enabled but the front and rear wheels are not connected.", false);
PX_CHECK_AND_RETURN_VAL((0.0f == rearBias) ||
(rearBias > 1.0f && rearWheelIds[0] < axleDesc.nbWheels && rearWheelIds[1] < axleDesc.nbWheels),
"PxVehicleFourWheelDriveDifferentialParams:: rearBias is enabled but the rearWheelIds are not configured correctly.", false);
PX_CHECK_AND_RETURN_VAL((0.0f == rearBias) ||
(rearBias > 1.0f && rearWheelIds[0] != rearWheelIds[1]),
"PxVehicleFourWheelDriveDifferentialParams:: rearBias is enabled but the rearWheelIds are not configured correctly.", false);
PX_CHECK_AND_RETURN_VAL((0.0f == centerBias) ||
(rearBias > 1.0f && torqueRatios[rearWheelIds[0]] != 0.0f && torqueRatios[rearWheelIds[1]] != 0.0f),
"PxVehicleFourWheelDriveDifferentialParams:: rearBias is enabled but the rear wheels are not connected.", false);
PX_CHECK_AND_RETURN_VAL((0.0f == frontBias) ||
(frontBias > 1.0f && frontWheelIds[0] < axleDesc.nbWheels && frontWheelIds[1] < axleDesc.nbWheels),
"PxVehicleFourWheelDriveDifferentialParams:: frontBias is enabled but the frontWheelIds are not configured correctly.", false);
PX_CHECK_AND_RETURN_VAL((0.0f == frontBias) ||
(frontBias > 1.0f && frontWheelIds[0] != frontWheelIds[1]),
"PxVehicleFourWheelDriveDifferentialParams:: frontBias is enabled but the frontWheelIds are not configured correctly.", false);
PX_CHECK_AND_RETURN_VAL((0.0f == frontBias) ||
(frontBias > 1.0f && torqueRatios[frontWheelIds[0]] != 0.0f && frontWheelIds[frontWheelIds[1]]),
"PxVehicleFourWheelDriveDifferentialParams:: frontBias is enabled but the front wheels are not connected.", false);
PX_CHECK_AND_RETURN_VAL(((0.0f == frontBias) && (0.0f == rearBias) && (0.0f == centerBias)) || (rate >= 0.0f),
"PxVehicleFourWheelDriveDifferentialParams:: strength must be greater than or equal to zero", false);
PX_CHECK_AND_RETURN_VAL((0.0f == frontBias) || ((1.0f == frontTarget && 1.0f == rearTarget) || (frontTarget > 1.0f && frontTarget < frontBias)),
"PxVehicleFourWheelDriveDifferentialParams: frontBias is enabled but frontTarget not in range (1.0f, frontBias)", false);
PX_CHECK_AND_RETURN_VAL((0.0f == rearBias) || ((1.0f == rearTarget && 1.0f == rearBias) || (rearTarget > 1.0f && rearTarget < rearBias)),
"PxVehicleFourWheelDriveDifferentialParams: rearBias is enabled but rearTarget not in range (1.0f, rearBias)", false);
PX_CHECK_AND_RETURN_VAL((0.0f == centerBias) || ((1.0f == centerTarget && 1.0f == centerBias) || (centerTarget > 1.0f && centerTarget < centerBias)),
"PxVehicleFourWheelDriveDifferentialParams: centerBias is enabled but centerTarget not in range (1.0f, centerBias)", false);
return true;
}
PX_FORCE_INLINE PxVehicleFourWheelDriveDifferentialParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
PX_UNUSED(srcScale);
PX_UNUSED(trgScale);
PxVehicleFourWheelDriveDifferentialParams r = *this;
static_cast<PxVehicleMultiWheelDriveDifferentialParams&>(r) = PxVehicleMultiWheelDriveDifferentialParams::transformAndScale(srcFrame, trgFrame, srcScale, trgScale);
return r;
}
};
struct PxVehicleTankDriveDifferentialParams : public PxVehicleMultiWheelDriveDifferentialParams
{
PX_FORCE_INLINE void setToDefault()
{
PxVehicleMultiWheelDriveDifferentialParams::setToDefault();
nbTracks = 0;
}
void addTankTrack(const PxU32 nbWheelsInTrackToAdd, const PxU32* const wheelIdsInTrackToAdd, const PxU32 thrustControllerIndex)
{
PxU32 trackToWheelIdsOffset = nbTracks ? trackToWheelIds[nbTracks - 1] + nbWheelsPerTrack[nbTracks - 1] : 0;
PX_ASSERT((trackToWheelIdsOffset + nbWheelsInTrackToAdd) <= PxVehicleLimits::eMAX_NB_WHEELS);
PX_ASSERT(nbTracks < PxVehicleLimits::eMAX_NB_WHEELS);
PX_ASSERT(thrustControllerIndex < 2);
nbWheelsPerTrack[nbTracks] = nbWheelsInTrackToAdd;
thrustIdPerTrack[nbTracks] = thrustControllerIndex;
trackToWheelIds[nbTracks] = trackToWheelIdsOffset;
for (PxU32 i = 0; i < nbWheelsInTrackToAdd; i++)
{
wheelIdsInTrackOrder[trackToWheelIdsOffset + i] = wheelIdsInTrackToAdd[i];
}
nbTracks++;
}
PX_FORCE_INLINE PxU32 getNbTracks() const
{
return nbTracks;
}
PX_FORCE_INLINE PxU32 getNbWheelsInTrack(const PxU32 i) const
{
return nbWheelsPerTrack[i];
}
PX_FORCE_INLINE const PxU32* getWheelsInTrack(const PxU32 i) const
{
return (wheelIdsInTrackOrder + trackToWheelIds[i]);
}
PX_FORCE_INLINE PxU32 getWheelInTrack(const PxU32 j, const PxU32 i) const
{
return wheelIdsInTrackOrder[trackToWheelIds[i] + j];
}
PX_FORCE_INLINE PxU32 getThrustControllerIndex(const PxU32 i) const
{
return thrustIdPerTrack[i];
}
PX_FORCE_INLINE PxVehicleTankDriveDifferentialParams transformAndScale(
const PxVehicleFrame& srcFrame, const PxVehicleFrame& trgFrame, const PxVehicleScale& srcScale, const PxVehicleScale& trgScale) const
{
PX_UNUSED(srcFrame);
PX_UNUSED(trgFrame);
PX_UNUSED(srcScale);
PX_UNUSED(trgScale);
PxVehicleTankDriveDifferentialParams r = *this;
static_cast<PxVehicleMultiWheelDriveDifferentialParams&>(r) = PxVehicleMultiWheelDriveDifferentialParams::transformAndScale(srcFrame, trgFrame, srcScale, trgScale);
return r;
}
PX_FORCE_INLINE bool isValid(const PxVehicleAxleDescription& axleDesc) const
{
if (!PxVehicleMultiWheelDriveDifferentialParams::isValid(axleDesc))
return false;
PX_CHECK_AND_RETURN_VAL(nbTracks <= PxVehicleLimits::eMAX_NB_WHEELS, "PxVehicleTankDriveDifferentialParams.nbTracks must not exceed PxVehicleLimits::eMAX_NB_WHEELS", false);
const PxU32 nbWheelsInTracksSize = nbTracks ? trackToWheelIds[nbTracks - 1] + nbWheelsPerTrack[nbTracks - 1] : 0;
PX_UNUSED(nbWheelsInTracksSize);
PX_CHECK_AND_RETURN_VAL(nbWheelsInTracksSize <= PxVehicleLimits::eMAX_NB_WHEELS, "PxVehicleTankDriveDifferentialParams.nbWheelsInTracks must not exceed PxVehicleLimits::eMAX_NB_WHEELS", false);
for (PxU32 i = 0; i < nbTracks; i++)
{
PX_CHECK_AND_RETURN_VAL(thrustIdPerTrack[i] < 2, "PxVehicleTankDriveDifferentialParams.thrustId must be less than 2", false);
}
for (PxU32 i = 0; i < axleDesc.nbWheels; i++)
{
const PxU32 wheelId = axleDesc.wheelIdsInAxleOrder[i];
PxU32 count = 0;
for (PxU32 j = 0; j < nbTracks; j++)
{
const PxU32 nbWheels = getNbWheelsInTrack(j);
const PxU32* wheelIds = getWheelsInTrack(j);
for (PxU32 k = 0; k < nbWheels; k++)
{
if (wheelIds[k] == wheelId)
count++;
}
}
PX_CHECK_AND_RETURN_VAL(count <= 1, "PxVehicleTankDriveDifferentialParams - a wheel cannot be in more than one tank track", false);
}
return true;
}
PxU32 nbTracks;
PxU32 thrustIdPerTrack[PxVehicleLimits::eMAX_NB_WHEELS];
PxU32 nbWheelsPerTrack[PxVehicleLimits::eMAX_NB_WHEELS];
PxU32 trackToWheelIds[PxVehicleLimits::eMAX_NB_WHEELS];
PxU32 wheelIdsInTrackOrder[PxVehicleLimits::eMAX_NB_WHEELS];
};
#if !PX_DOXYGEN
} // namespace vehicle2
} // namespace physx
#endif