PhysX3.4文档(15) -- Vehicles

Vehicles


Introduction


PhysX对车辆的支持在3.x中得到了显着的重新设计。为了取代 NxWheelShape 类 2.8.x,已经开发出核心 PhysX SDK 和车辆仿真代码的更优化集成。更具体地说,车辆组件现在以类似于PhysXExtensions的方式位于核心SDK之外。此更改允许在一次通过中更新车辆,并促进更直观的车辆数据建模方法。车辆支持已从2.8.x的悬架/车轮/轮胎建模扩展到更完整的模型,该模型结合了模块化车辆组件,包括发动机,离合器,齿轮,自动变速箱,差速器,车轮,轮胎,悬架和底盘。快速浏览PxVehicleComponents.h中的数据结构将提供PhysX车辆支持的行为。

Algorithm


PhysX Vehicle SDK将车辆建模为弹簧质量的集合,其中每个弹簧质量代表一条带有相关车轮和轮胎数据的悬架线。这些弹簧质量的集合具有作为刚体演员的互补表示,其质量,质量中心和惯性矩与弹簧质量的质量和坐标完全匹配。如下图所示。

Vehicle_1

图 1a:车辆表示为刚体演员,具有底盘和车轮的形状。请注意,车轮静止偏移是相对于质心指定的。

Vehicle_2

图 1b:车辆表示为质量为 M1 和 M2 的弹簧质量的集合。

弹簧质量和刚体车辆表示之间的关系可以用刚体质量中心方程在数学上形式化:

M = M 1 + M 2 M = M_1 + M_2 M=M1+M2

X c m = ( M 1 x X 1 + M 2 x X 2 ) / ( M 1 + M 2 ) X_{cm} = (M_1 x X_1 + M_2 x X_2)/(M_1 + M_2) Xcm=(M1xX1+M2xX2)/(M1+M2)

其中 M1 和 M2 是弹簧质量;X1和X2是演员空间中的弹簧质量坐标;M是刚体质量;而 Xcm 是刚体质量偏移的中心。

PhysX Vehicle SDK 更新函数的目的是使用弹簧质量模型计算悬架和轮胎力,然后以修改的速度和角速度的形式将这些力的聚合应用于 PhysX SDK 刚体表示。然后,PhysX SDK 管理刚体 actor 与其他场景对象的交互和全局姿势更新。

每辆车的更新从每个悬架线的光线投射开始。光线投射从轮胎顶部的正上方以最大压缩开始,并沿着悬架行进的方向向下投射到最大下垂时轮胎底部正下方的位置。如下图所示。

Vehicle_3

图 2:悬挂限制和悬挂光线投射。

计算来自每个细长或压缩弹簧的悬挂力,并将其添加到要施加到刚体上的聚集力中。此外,悬架力用于计算轮胎承受的载荷。该载荷用于确定将在接触平面中产生的轮胎力,然后添加到要施加到刚体的聚集力中。轮胎力的计算实际上取决于许多因素,包括转向角、外倾角、摩擦力、车轮转速和刚体动量。然后将所有轮胎和悬架力的聚合力应用于与车辆关联的刚体actor,以便在下一次PhysX SDK更新中可以相应地修改变换。

除了作为弹簧质量的集合外,PhysX车辆还支持各种驱动模型。驱动模型的中心是一个扭力离合器,它通过离合器两侧转速差异产生的力将车轮和发动机耦合在一起。离合器的一侧是发动机,它直接由油门踏板提供动力。发动机被建模为一个刚体,其运动是纯粹的旋转,并且仅限于单一的旋转自由度。离合器的另一侧是传动系统,差速器和车轮。离合器另一侧的有效转速可以直接从传动比和通过差速器耦合到离合器的车轮的转速来计算。该模型自然允许发动机扭矩传播到车轮,车轮扭矩传播回发动机,就像在标准汽车中一样。

描述PhysX车辆每个组件的数据可以在部分调整指南中找到。

First Code


Vehicle SDK Initialization


在使用车辆 SDK 之前,必须首先对其进行初始化,以便从各种公差等级中设置一些阈值。这与调用以下函数一样简单:

PX_C_EXPORT bool PX_CALL_CONV PxInitVehicleSDK
    (PxPhysics& physics, PxSerializationRegistry* serializationRegistry = NULL);

此函数应在设置所需的 PxPhysics 和 PxFoundation 实例后调用。如果需要车辆序列化,则需要指定 PxSerializationRegistry 实例。可以使用 PxSerialization::createSerializationRegistry() 创建 PxSerializationRegistry() 创建实例,请参阅序列化。

还必须配置车辆仿真的基向量,以便可以明确地计算纵向和横向轮胎打滑:

void PxVehicleSetBasisVectors(const PxVec3& up, const PxVec3& forward);

可以在首次执行PxVehicleUpdates之前的任何时间调用此函数。

与车辆关联的刚体Actor可以通过速度修改立即更新,也可以使用在下一个PhysX SDK模拟调用中应用的加速度进行更新。以下函数可用于选择所需的更新模式:

void PxVehicleSetUpdateMode(PxVehicleUpdateMode::Enum vehicleUpdateMode);

不出所料,车辆 SDK 还有一个需要调用的关机过程:

PX_C_EXPORT void PX_CALL_CONV PxCloseVehicleSDK
    (PxSerializationRegistry* serializationRegistry = NULL);

这需要在PxPhysics实例和PxFoundation实例发布之前调用;也就是说,关闭顺序与初始化顺序相反。此外,如果需要序列化,则需要将 PxSerialization 为 PxInitVehicleSDK 指定的 PxSerializationRegistry 传递给 PxCloseVehicleSDK。如果使用车辆序列化,则必须在关闭 PhysXExtensions 之前调用此序列化。

作为这些函数用法的说明,SnippetVehicle4W 具有以下初始化代码:

PxInitVehicleSDK(*gPhysics);
PxVehicleSetBasisVectors(PxVec3(0,1,0), PxVec3(0,0,1));
PxVehicleSetUpdateMode(PxVehicleUpdateMode::eVELOCITY_CHANGE);

SnippetVehicle4W中的关机代码如下:

PxCloseVehicleSDK();

Introduction To Vehicle Creation


以下伪代码说明了设置 PxVehicleDrive4W 实例的基本过程:

const PxU32 numWheels = 4;

PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(numWheels);
setupWheelsSimulationData(wheelsSimData);

PxVehicleDriveSimData4W driveSimData;
setupDriveSimData(driveSimData);

PxRigidDynamic* vehActor = myPhysics.createRigidDynamic(startPose);
setupVehicleActor(vehActor);
myScene.addActor(*vehActor);

PxVehicleDrive4W* vehDrive4W = PxVehicleDrive4W::allocate(numWheels);
vehDrive4W->setup(physics, veh4WActor, *wheelsSimData, driveSimData, numWheels - 4);
wheelsSimData->free();

上面的代码首先实例化了一个 PxVehicleWheelsSimData 实例,该实例的内部缓冲区足够大,可以存储四个轮子的配置数据。此配置数据包括悬架强度和阻尼速率、车轮质量、轮胎刚度和悬架行驶方向等字段。下一步是创建一个PxVehicleDriveSimData4W实例。此结构存储驱动模型的配置,并包括发动机峰值扭矩、离合器强度、传动比和阿克曼转向校正等数据字段。在此之后,PxRigidDynamicActor被实例化并配置车轮和底盘的几何形状以及动态属性,如质量,转动惯量和质心。最后一步是实例化 PxVehicleDrive4W 实例,并将其与执行组件和车辆配置数据相关联。

功能设置WheelsSimulationData,setupDriveSimData和setatVehicleActor实际上非常复杂,并将在将来的章节设置WheelsSimulationData,setupDriveSimData和setupVehicleActor中讨论。

Introduction To Vehicle Update


PhysX 车辆 SDK 利用批处理场景查询来查询每个轮胎下的几何图形。有关 PhysX 批处理场景查询的更详细讨论,请参阅批处理查询部分。

以下伪代码初始化一个批处理场景查询,其缓冲区对于具有四个车轮的单个车辆来说足够大:

PxRaycastQueryResult sqResults[4];
PxRaycastHit sqHitBuffer[4];
PxBatchQueryDesc sqDesc(4, 0, 0);
sqDesc.queryMemory.userRaycastResultBuffer = sqResults;
sqDesc.queryMemory.userRaycastTouchBuffer = sqHitBuffer;
sqDesc.queryMemory.raycastTouchBufferSize = 4;
sqDesc.preFilterShader = myFilterShader;
PxBatchQuery* batchQuery = scene->createBatchQuery(sqDesc);

PxBatchQuery 实例通常作为初始化阶段的一部分进行实例化,然后重用每个帧。可以为每个车辆实例化一个 PxBatchQuery 实例,或者使用足够大的缓冲区来实例化单个 PxBatchQuery 实例,以容纳批量车辆数组的所有车轮。唯一的限制是在车辆仿真帧开始时配置的所有批处理车辆数组和关联缓冲区必须一直持续到车辆模拟框架结束。

PhysX 车辆利用场景查询过滤器着色器来消除与发出光线投射的车辆以及任何不被视为可驾驶表面的几何体的交叉点。有关如何设置"myFilterShader"的更多详细信息,请参阅上面的"过滤"部分。

对于仅包含单个四轮车辆的批次,可以使用以下伪代码执行悬架射线照射:对于仅包含单个四轮车辆的批次,可以使用以下伪代码执行悬架射线照射:

PxVehicleWheels* vehicles[1] = {myVehicle};
PxVehicleSuspensionRaycasts(batchQuery, 1, vehicles, 4, sqResults);

PxVehicleSuspensionRaycasts功能为批量车辆阵列中的所有车辆执行悬架射线投射。sqResults 数组中的每个元素都对应于单个悬架的光线投射报告。指向 sqResults 中连续块的指针由每辆车依次存储,因为该函数在车辆数组中进行迭代。这些存储块由每辆车存储,以便它们可以轻松查询PxVehicleUpdates中的悬架光线投射结果。因此,sqResults 数组必须至少持续到 PxVehicleUpdates 结束,并且长度必须至少与车辆数组中的车轮总数一样大。

车辆将使用以下函数调用进行更新:

PxVehicleUpdates(timestep, gravity, frictionPairs, 1, vehicles, NULL);

PxVehicleUpdates 功能可更新每辆车的内部动态,呈现车辆执行组件的车轮形状,并将速度或加速度更改应用于执行组件,具体取决于使用 PxVehicleSetUpdateMode 选择的更新模式。更多详细信息可以在部分车轮姿势和部分车辆更新中找到。参数摩擦对基本上是一个查找表,它将独特的摩擦值与轮胎类型和Px材料的组合相关联。这里的想法是允许针对每种表面类型调整轮胎响应。这将在可驾驶表面上的轮胎摩擦部分进行更深入的讨论。

Snippets


当前实现了四个代码段来说明 PhysX 车辆 SDK 的操作。这些是:

1. SnippetVehicle4W
2. SnippetVehicleTank
    3. SnippetNoDrive
3. SnippetVehicleScale
4. SnippetVehicleMultiThreading
    5. SnippetVehicleWheelContactMod

每个代码片段都在整个指南中使用。

SnippetVehicle4W


SnippetVehicle4W演示了如何实例化和更新PxVehicleDrive4W类型的车辆。它在飞机上创建车辆,然后控制车辆,以便执行许多精心设计的动作,例如加速,倒车,制动,手刹和转弯。

SnippetVehicleTank


SnippetVehicleTank 演示了如何实例化和更新 PxVehicleDriveTank 类型的车辆。它在飞机上创建一个坦克,然后控制坦克,以便它执行许多精心设计的机动,如加速,倒车,软转弯和硬转弯。

SnippetVehicleNoDrive


SnippetVehicleNoDrive演示了如何实例化和更新PxVehicleNoDrive类型的车辆。它在飞机上创建车辆,然后控制车辆,以便它执行许多精心设计的操作,例如加速,倒车,软转弯和硬转弯。

SnippetVehicleScale


SnippetVehicleScale 演示了当仪表不是所选的长度刻度时如何配置 PhysX 车辆。该代码段设置一个车辆,其中米作为采用的长度刻度,然后修改车辆参数,以便它们表示同一车辆,但以厘米作为所选的长度刻度。

SnippetVehicleMultiThreading


SnippetVehicleMultiThreading演示了如何实现多线程车辆。它在平面上创建多个车辆,然后跨多个线程并行模拟它们。

Advanced Concepts


Vehicle Creation


本节讨论车辆仿真数据的配置,并介绍如何在 PhysX SDK 中设置表示车辆的执行组件。车辆创建简介部分确定了车辆配置的三个不同阶段:车轮仿真数据的配置、驱动仿真数据的配置和执行组件配置。这些阶段中的每一个都依次讨论。

setupWheelsSimulationData

以下代码取自 SnippetVehicle4W,实例化了 PxVehicleWheelsSimData:

void setupWheelsSimulationData(const PxF32 wheelMass, const PxF32 wheelMOI,
    const PxF32 wheelRadius, const PxF32 wheelWidth, const PxU32 numWheels,
    const PxVec3* wheelCenterActorOffsets, const PxVec3& chassisCMOffset,
    const PxF32 chassisMass, PxVehicleWheelsSimData* wheelsSimData)
{
    //Set up the wheels.
    PxVehicleWheelData wheels[PX_MAX_NB_WHEELS];
    {
        //Set up the wheel data structures with mass, moi, radius, width.
        for(PxU32 i = 0; i < numWheels; i++)
        {
            wheels[i].mMass = wheelMass;
            wheels[i].mMOI = wheelMOI;
            wheels[i].mRadius = wheelRadius;
            wheels[i].mWidth = wheelWidth;
        }

        //Enable the handbrake for the rear wheels only.
        wheels[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mMaxHandBrakeTorque=4000.0f;
        wheels[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mMaxHandBrakeTorque=4000.0f;
        //Enable steering for the front wheels only.
        wheels[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mMaxSteer=PxPi*0.3333f;
        wheels[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mMaxSteer=PxPi*0.3333f;
    }

    //Set up the tires.
    PxVehicleTireData tires[PX_MAX_NB_WHEELS];
    {
        //Set up the tires.
        for(PxU32 i = 0; i < numWheels; i++)
        {
            tires[i].mType = TIRE_TYPE_NORMAL;
        }
    }

    //Set up the suspensions
    PxVehicleSuspensionData suspensions[PX_MAX_NB_WHEELS];
    {
        //Compute the mass supported by each suspension spring.
        PxF32 suspSprungMasses[PX_MAX_NB_WHEELS];
        PxVehicleComputeSprungMasses
            (numWheels, wheelCenterActorOffsets,
             chassisCMOffset, chassisMass, 1, suspSprungMasses);

        //Set the suspension data.
        for(PxU32 i = 0; i < numWheels; i++)
        {
            suspensions[i].mMaxCompression = 0.3f;
            suspensions[i].mMaxDroop = 0.1f;
            suspensions[i].mSpringStrength = 35000.0f;
            suspensions[i].mSpringDamperRate = 4500.0f;
            suspensions[i].mSprungMass = suspSprungMasses[i];
        }

        //Set the camber angles.
        const PxF32 camberAngleAtRest=0.0;
        const PxF32 camberAngleAtMaxDroop=0.01f;
        const PxF32 camberAngleAtMaxCompression=-0.01f;
        for(PxU32 i = 0; i < numWheels; i+=2)
        {
            suspensions[i + 0].mCamberAtRest =  camberAngleAtRest;
            suspensions[i + 1].mCamberAtRest =  -camberAngleAtRest;
            suspensions[i + 0].mCamberAtMaxDroop = camberAngleAtMaxDroop;
            suspensions[i + 1].mCamberAtMaxDroop = -camberAngleAtMaxDroop;
            suspensions[i + 0].mCamberAtMaxCompression = camberAngleAtMaxCompression;
            suspensions[i + 1].mCamberAtMaxCompression = -camberAngleAtMaxCompression;
        }
    }

    //Set up the wheel geometry.
    PxVec3 suspTravelDirections[PX_MAX_NB_WHEELS];
    PxVec3 wheelCentreCMOffsets[PX_MAX_NB_WHEELS];
    PxVec3 suspForceAppCMOffsets[PX_MAX_NB_WHEELS];
    PxVec3 tireForceAppCMOffsets[PX_MAX_NB_WHEELS];
    {
        //Set the geometry data.
        for(PxU32 i = 0; i < numWheels; i++)
        {
            //Vertical suspension travel.
            suspTravelDirections[i] = PxVec3(0,-1,0);

            //Wheel center offset is offset from rigid body center of mass.
            wheelCentreCMOffsets[i] =
                wheelCenterActorOffsets[i] - chassisCMOffset;

            //Suspension force application point 0.3 metres below
            //rigid body center of mass.
            suspForceAppCMOffsets[i] =
                PxVec3(wheelCentreCMOffsets[i].x,-0.3f,wheelCentreCMOffsets[i].z);

            //Tire force application point 0.3 metres below
            //rigid body center of mass.
            tireForceAppCMOffsets[i] =
                PxVec3(wheelCentreCMOffsets[i].x,-0.3f,wheelCentreCMOffsets[i].z);
        }
    }

    //Set up the filter data of the raycast that will be issued by each suspension.
    PxFilterData qryFilterData;
    setupNonDrivableSurface(qryFilterData);

    //Set the wheel, tire and suspension data.
    //Set the geometry data.
    //Set the query filter data
    for(PxU32 i = 0; i < numWheels; i++)
    {
        wheelsSimData->setWheelData(i, wheels[i]);
        wheelsSimData->setTireData(i, tires[i]);
        wheelsSimData->setSuspensionData(i, suspensions[i]);
        wheelsSimData->setSuspTravelDirection(i, suspTravelDirections[i]);
        wheelsSimData->setWheelCentreOffset(i, wheelCentreCMOffsets[i]);
        wheelsSimData->setSuspForceAppPointOffset(i, suspForceAppCMOffsets[i]);
        wheelsSimData->setTireForceAppPointOffset(i, tireForceAppCMOffsets[i]);
        wheelsSimData->setSceneQueryFilterData(i, qryFilterData);
        wheelsSimData->setWheelShapeMapping(i, i);
    }
}

PxVehicleComputeSprungMasses函数计算每个悬架的弹簧质量,以便它们共同匹配刚体质量中心。这是在演员的框架中执行的。在演员的框架中执行PxVehicleComputeSprungMass是有意义的,因为刚体质量中心总是在演员的框架中指定。另一方面,车辆悬架系统在质心框架中指定。因此,函数 setWheelCentreOffset、setSuspForceAppPointOffset 和 setTireForceAppPointOffset 都描述了刚体质心的偏移量。这种方法的直接性可以使刚体质心的变化比预期的要复杂一些。为了解决这个问题,引入了PxVehicleUpdateCMassLocalPose函数,尽管在上面的代码中没有使用。此功能重新计算和设置所有悬架偏移,重新计算弹簧质量,并以保留每个弹簧的固有频率和阻尼比的方式设置它们。

上述许多参数和功能的详细信息可以在部分调优指南中找到。功能设置NonDrivableSurface为每个悬架光线投射设置场景查询过滤器数据,将在部分过滤中更详细地讨论。此外,TIRE_TYPE_NORMAL与轮胎摩擦之间的联系应在可驾驶表面上的轮胎摩擦部分中明确。最后,在截面轮姿势中应阐明功能集WheelShapeMappping的使用。

setupDriveSimData

以下代码取自 SnippetVehicle4W,实例化了 PxVehicleDriveSimData4W:

PxVehicleDriveSimData4W driveSimData;
{
    //Diff
    PxVehicleDifferential4WData diff;
    diff.mType=PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD;
    driveSimData.setDiffData(diff);

    //Engine
    PxVehicleEngineData engine;
    engine.mPeakTorque=500.0f;
    engine.mMaxOmega=600.0f;//approx 6000 rpm
    driveSimData.setEngineData(engine);

    //Gears
    PxVehicleGearsData gears;
    gears.mSwitchTime=0.5f;
    driveSimData.setGearsData(gears);

    //Clutch
    PxVehicleClutchData clutch;
    clutch.mStrength=10.0f;
    driveSimData.setClutchData(clutch);

    //Ackermann steer accuracy
    PxVehicleAckermannGeometryData ackermann;
    ackermann.mAccuracy=1.0f;
    ackermann.mAxleSeparation=
        wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).z-
        wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).z;
    ackermann.mFrontWidth=
        wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT).x-
        wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).x;
    ackermann.mRearWidth=
        wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_RIGHT).x-
        wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).x;
    driveSimData.setAckermannGeometryData(ackermann);
}

上述许多参数和功能的详细信息可以在部分调优指南中找到。

配置 PxVehicleDriveSimDataNW 和 PxVehicleDriveSimDataTank 实例遵循非常相似的过程,尽管组件略有不同。例如,可以在SnippetVehicleTank中找到更多详细信息。

setupVehicleActor

以下代码(所有车辆代码段通用)设置了一个具有几何图形、滤镜和动态数据的刚性动态执行组件:

PxRigidDynamic* createVehicleActor
(const PxVehicleChassisData& chassisData,
 PxMaterial** wheelMaterials, PxConvexMesh** wheelConvexMeshes, const PxU32 numWheels, const PxFilterData& wheelSimFilterData,
 PxMaterial** chassisMaterials, PxConvexMesh** chassisConvexMeshes, const PxU32 numChassisMeshes, const PxFilterData& chassisSimFilterData,
 PxPhysics& physics)
{
        //We need a rigid body actor for the vehicle.
        //Don't forget to add the actor to the scene after setting up the associated vehicle.
        PxRigidDynamic* vehActor = physics.createRigidDynamic(PxTransform(PxIdentity));

        //Wheel and chassis query filter data.
        //Optional: cars don't drive on other cars.
        PxFilterData wheelQryFilterData;
        setupNonDrivableSurface(wheelQryFilterData);
        PxFilterData chassisQryFilterData;
        setupNonDrivableSurface(chassisQryFilterData);

        //Add all the wheel shapes to the actor.
        for(PxU32 i = 0; i < numWheels; i++)
        {
                PxConvexMeshGeometry geom(wheelConvexMeshes[i]);
                PxShape* wheelShape=PxRigidActorExt::createExclusiveShape(*vehActor, geom, *wheelMaterials[i]);
                wheelShape->setQueryFilterData(wheelQryFilterData);
                wheelShape->setSimulationFilterData(wheelSimFilterData);
                wheelShape->setLocalPose(PxTransform(PxIdentity));
        }

        //Add the chassis shapes to the actor.
        for(PxU32 i = 0; i < numChassisMeshes; i++)
        {
                PxShape* chassisShape=PxRigidActorExt::createExclusiveShape(*vehActor, PxConvexMeshGeometry(chassisConvexMeshes[i]), *chassisMaterials[i]);
                chassisShape->setQueryFilterData(chassisQryFilterData);
                chassisShape->setSimulationFilterData(chassisSimFilterData);
                chassisShape->setLocalPose(PxTransform(PxIdentity));
        }

        vehActor->setMass(chassisData.mMass);
        vehActor->setMassSpaceInertiaTensor(chassisData.mMOI);
        vehActor->setCMassLocalPose(PxTransform(chassisData.mCMOffset,PxQuat(PxIdentity)));

        return vehActor;
}

wheelSimFilterData、chassisSimFilterData、wheelQryFilterData 和 chassisQryFilterData 的重要性将在过滤部分讨论。此外,上述代码中车轮形状的排序与 PxVehicleWheelsSimData::setWheelShapeMapping 函数之间的联系在 Section Wheel Pose 中得到了阐述。

Filtering


本节将描述车辆查询和车辆仿真过滤背后的概念。

车辆场景查询和仿真过滤的主要目标是确保车辆受到悬架弹簧力的支撑,而不会受到车轮形状交叉的干扰。过滤的要求如下:

1. wheel shapes must not hit drivable surfaces
2. suspension raycasts can hit drivable surfaces
3. suspension raycasts must not hit the shapes of the vehicle issuing the raycasts

通过仿真过滤,可以确保车轮形状不会撞到可驾驶表面。这在碰撞过滤部分有更详细的讨论。车辆代码段使用以下模拟过滤器着色器:

PxFilterFlags VehicleFilterShader
(PxFilterObjectAttributes attributes0, PxFilterData filterData0,
 PxFilterObjectAttributes attributes1, PxFilterData filterData1,
 PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
{
        PX_UNUSED(attributes0);
        PX_UNUSED(attributes1);
        PX_UNUSED(constantBlock);
        PX_UNUSED(constantBlockSize);

        if( (0 == (filterData0.word0 & filterData1.word1)) && (0 == (filterData1.word0 & filterData0.word1)) )
                return PxFilterFlag::eSUPPRESS;

        pairFlags = PxPairFlag::eCONTACT_DEFAULT;
        pairFlags |= PxPairFlags(PxU16(filterData0.word2 | filterData1.word2));

        return PxFilterFlags();
}

这些代码段还将仿真筛选器数据应用于车轮形状,如下所示:

PxFilterData wheelSimFilterData;
wheelSimFilterData.word0 = COLLISION_FLAG_WHEEL;
wheelSimFilterData.word1 = COLLISION_FLAG_WHEEL_AGAINST;

...

wheelShape->setSimulationFilterData(wheelSimFilterData);

最后,将以下仿真滤波器数据应用于可驾驶表面:

PxFilterData simFilterData;
simFilterData.word0 = COLLISION_FLAG_GROUND;
simFilterDat
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值