Bullet Physics - Raycast Vehicle bounces while driving for unknown reasons

Started by
3 comments, last by bmarci 2 years ago

As I wrote in Subject, Vehicle was running on a track made using btBvhTriangleMeshShape when it randomly bounces off like something got caught in a wheel.

I have already confirmed that there is no element in the mesh that can be caught in the wheel.

here's video link.

https://youtu.be/lYUlhcdB0iw

and here's how I create vehicle and control it.

void PhysicsPlayer::BuildRigidBody(const std::shared_ptr<BulletWrapper>& physics)
{
    auto dynamicsWorld = physics->GetDynamicsWorld();

    mOOBB.Extents = { 10.0f, 4.0f, 14.0f };

    XMFLOAT3 vehicleExtents = mOOBB.Extents;
    XMFLOAT3 wheelExtents = mWheel[0]->GetBoundingBox().Extents;

    btTransform btCarTransform;
    btCarTransform.setIdentity();
    btCarTransform.setOrigin(btVector3(mPosition.x, mPosition.y, mPosition.z));

    LoadConvexHullShape(L"Models\\Car_Body_Convex_Hull.obj", physics);

    mBtRigidBody = physics->CreateRigidBody(1000.0f, btCarTransform, mBtCollisionShape);
    mVehicleRayCaster = std::make_shared<btDefaultVehicleRaycaster>(dynamicsWorld);
    mVehicle = std::make_shared<btRaycastVehicle>(mTuning, mBtRigidBody, mVehicleRayCaster.get());
    mBtRigidBody = mVehicle->getRigidBody();

    mBtRigidBody->setActivationState(DISABLE_DEACTIVATION);
    //mBtRigidBody->setGravity(btVector3(0, -20, 0));
    dynamicsWorld->addVehicle(mVehicle.get());

    mVehicle->setCoordinateSystem(0, 1, 2);

    btVector3 wheelDirectionCS0(0, -1, 0);
    btVector3 wheelAxleCS(-1, 0, 0);

    float wheelWidth = wheelExtents.x;
    float wheelRadius = wheelExtents.z;
    float wheelFriction = mWheelFriction;
    float suspensionStiffness = 20.f;
    float suspensionDamping = 2.3f;
    float suspensionCompression = 4.4f;
    float rollInfluence = 0.01f;  //1.0f;

    // 앞바퀴
    bool isFrontWheel = true;
    float connectionHeight = -0.9f;

    btVector3 connectionPointCS0(vehicleExtents.x - 2.5f, connectionHeight, vehicleExtents.z - 2.8f);
    mVehicle->addWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, 0.6f, wheelRadius, mTuning, isFrontWheel);

    connectionPointCS0 = btVector3(-vehicleExtents.x + 2.5f, connectionHeight, vehicleExtents.z - 2.8f);
    mVehicle->addWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, 0.6f, wheelRadius, mTuning, isFrontWheel);

    isFrontWheel = false;

    connectionPointCS0 = btVector3(vehicleExtents.x - 2.3f, connectionHeight, -vehicleExtents.z + 2.6f);
    mVehicle->addWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, 0.6f, wheelRadius, mTuning, isFrontWheel);

    connectionPointCS0 = btVector3(-vehicleExtents.x + 2.3f, connectionHeight, -vehicleExtents.z + 2.6f);
    mVehicle->addWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, 0.6f, wheelRadius, mTuning, isFrontWheel);

    for (int i = 0; i < mVehicle->getNumWheels(); i++)
    {
        btWheelInfo& wheel = mVehicle->getWheelInfo(i);
        wheel.m_suspensionStiffness = suspensionStiffness;
        wheel.m_wheelsDampingRelaxation = suspensionDamping;
        wheel.m_wheelsDampingCompression = suspensionCompression;
        wheel.m_frictionSlip = wheelFriction;
        wheel.m_rollInfluence = rollInfluence;
    }
}

class PhysicsPlayer : public Player
{
//Other functions and variables were excluded because they were not related to the bullet.
private:
    const float mWheelFriction = 10.0f;
    const float mWheelDriftFriction = 5.0f;

    std::shared_ptr<WheelObject> mWheel[4];
    btRaycastVehicle::btVehicleTuning mTuning;
    std::shared_ptr<btVehicleRaycaster> mVehicleRayCaster;
    std::shared_ptr<btRaycastVehicle> mVehicle;

    float mBoosterLeft = 0.0f;
    float mBoosterTime = 5.0f;

    float mEngineForce = 0.f;

    float mMaxEngineForce = 8000.f;
    float mMaxBackwardEngineForce = 10000.f;
    float mBoosterEngineForce = 300000.f;

    float mVehicleSteering = 0.f;
    float mSteeringIncrement = 5.0f;
    float mSteeringClamp = 0.6f;

    float mCurrentSpeed = 0.0f;
    float mMaxSpeed = 1000.0f;

    float mBreakingForce = 0.0f;

    float mFovCoefficient = 1.0f;

    int mItemNum = 0;
    float mDriftGauge = 0.0f;
};


void PhysicsPlayer::OnPreciseKeyInput(float Elapsed)
{
    if (mVehicle)
        mCurrentSpeed = mVehicle->getCurrentSpeedKmHour();

    mEngineForce = 0.0f;
    mBreakingForce = 10.0f;

    if (mBoosterLeft > 0.0f)
    {
        mMaxSpeed = 1500.0f;
        mBoosterLeft -= Elapsed;

        mRimLightOn = true;
    }

    if (mBoosterLeft < 0.0f)
    {
        mMaxSpeed = 1000.0f;
        mBoosterLeft = 0.0f;

        mRimLightOn = false;
    }

    if (mVehicleSteering > 0)
    {
        mVehicleSteering -= mSteeringIncrement * Elapsed;
        if (mVehicleSteering < 0)
        {
            mVehicleSteering = 0;
        }
    }

    else if (mVehicleSteering < 0)
    {
        mVehicleSteering += mSteeringIncrement * Elapsed;
        if (mVehicleSteering > 0)
        {
            mVehicleSteering = 0;
        }
    }

    if (GetAsyncKeyState(VK_LEFT) & 0x8000)
    {
        mVehicleSteering -= mSteeringIncrement * Elapsed;
        if (mVehicleSteering < -mSteeringClamp)
            mVehicleSteering = -mSteeringClamp;
    }
    if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
    {
        mVehicleSteering += mSteeringIncrement * Elapsed;
        if (mVehicleSteering > mSteeringClamp)
            mVehicleSteering = mSteeringClamp;
    }
    if (GetAsyncKeyState(VK_UP) & 0x8000)
    {
        if (mCurrentSpeed < 0.0f)
            mBreakingForce = 150.0f;
        else if (mMaxSpeed > mCurrentSpeed)
            mEngineForce = mMaxEngineForce;
        else
        {
            mBreakingForce = 100.0f;
            mEngineForce = 0.0f;
        }
    }
    if (GetAsyncKeyState(VK_DOWN) & 0x8000)
    {
        if (mCurrentSpeed > 0.0f)
            mBreakingForce = 150.0f;
        else if (-mMaxSpeed < mCurrentSpeed)
            mEngineForce = -mMaxBackwardEngineForce;
        else
        {
            mBreakingForce = 100.0f;
            mEngineForce = 0.0f;
        }
    }
    if (GetAsyncKeyState('Z') & 0x8000/*&&mItemNum>0*/)
    {
        #ifdef STANDALONE
        if (mBoosterLeft == 0.0f)
            mBoosterLeft = mBoosterTime;
        #endif

        //mItemNum-=1;
    }
    // if (GetAsyncKeyState('X') & 0x8000/*&&mItemNum>0*/)
    //{
    //
    //}
    if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
    {       
        for (int i = 2; i < 4; ++i)
        {
            if (mVehicle) mVehicle->getWheelInfo(i).m_frictionSlip = mWheelDriftFriction;
        }

        float Epsilon = 50.0f / 180.0f;

        auto camLook = mCamera->GetLook();
        camLook.y = 0.0f;
        camLook = Vector3::Normalize(camLook);

        auto playerLook = mLook;
        playerLook.y = 0.0f;
        playerLook = Vector3::Normalize(playerLook);

        float angle = acos(Vector3::Dot(camLook, playerLook) / (Vector3::Length(camLook) * Vector3::Length(playerLook)));

        if (Epsilon < angle && mDriftGauge < 1.0f)
        {
            mDriftGauge += Elapsed / 2.0f;
        }
        if (mDriftGauge > 1.0f)
        {
            mDriftGauge = 0.0f;
            if (mItemNum < 2)
                mItemNum++;
        }
    }
    else
    {
        for (int i = 2; i < 4; ++i)
        {
            if(mVehicle) mVehicle->getWheelInfo(i).m_frictionSlip = mWheelFriction;
        }
    }

    if (mBoosterLeft && mMaxSpeed < mCurrentSpeed)
        mEngineForce = mBoosterEngineForce;

    for (int i = 0; i < 2; ++i)
    {
        if (mVehicle)
        {
            mVehicle->applyEngineForce(mEngineForce, i);
            mVehicle->setBrake(mBreakingForce, i);
        }
    }

    if (mVehicle)
    {
        int wheelIndex = 0;
        mVehicle->setSteeringValue(mVehicleSteering, wheelIndex);
        wheelIndex = 1;
        mVehicle->setSteeringValue(mVehicleSteering, wheelIndex);
    }
}

void PhysicsPlayer::Update(float elapsedTime, float updateRate)
{
    GameObject::Update(elapsedTime, updateRate);
    
    for (int i = 0; i < 4; ++i)
    {
        if (mVehicle)
        {
            btTransform wheelTransform = mVehicle->getWheelTransformWS(i);
            mWheel[i]->UpdatePosition(elapsedTime, wheelTransform);
        }
    }

    //btVector3 linearVel = mBtRigidBody->getLinearVelocity();
    //mBtRigidBody->applyCentralImpulse(btVector3(0, -linearVel.length() / 10, 0));

    if (mBoosterLeft > 0.0f)
    {
        if (mFovCoefficient < 1.1f)
            mFovCoefficient += elapsedTime * 5.0f * (1.1f - mFovCoefficient);
        else
            mFovCoefficient = 1.1f;
    }
    else
    {
        if (mFovCoefficient > 1.0f)
            mFovCoefficient -= elapsedTime * 5.0f * (mFovCoefficient - 1.0f);
        else
            mFovCoefficient = 1.0f;
    }
}

Update runs after OnPreciseKeyInput runs.

The vehicle chassis was created using a Hull Shape created by the V-HACD.

And I don't know if this is going to be an impact, but because the vehicle modeling is pretty big, all the objects have been scaled six times accordingly.

That is, 1 meter is 6 in the code internal value.

I'm not sure what part of the code is causing this sudden bounce. Is there any guideline for tuning the Raycast Vehicle?

Advertisement

From the video it looks like the suspension is unstable from the start, and instability gets worse at high speeds. Try a few things to see if anything improves:
* Increase damping or decrease stiffness to make the springs more stable. Your stiffness is high compared to damping, which leads to instability.
* Decrease simulation time step.
* Try it with a very large plane or box shape as the road surface rather than mesh, to eliminate possibility it is due to the mesh.

I only have a tiny bit of experience with bullet and nothing related to cars, but definitely get your debug draw render code up and running. That was one of the first things I did. This way you can see better what collision/joints actually look like. I just last night had a bug where my physics on a mesh was scaled 10x the size of what I rendered the object and as you can imagine you don't find that unless you have debug drawing on.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

SharkBladder said:
And I don't know if this is going to be an impact, but because the vehicle modeling is pretty big, all the objects have been scaled six times accordingly. That is, 1 meter is 6 in the code internal value.

The first fishy thing that I noticed was your car going at 630km/h
Try to stick with the actual measurements, so scale everything to match real-world sizes. Force/torque calculations heavily depend on distances.
If you scale up the car, weight/inertia tensors/spring stiffness/damping…etc everything have to be modified accordingly.
Also, first I would try what @aressera suggested.

This topic is closed to new replies.

Advertisement