updateFriction method

void updateFriction(
  1. double timeStep
)

Implementation

void updateFriction(double timeStep){
  final surfNormalWSScaledProj = _updateFrictionSurfNormalWSScaledProj;

  //calculate the impulse, so that the wheels don't move sidewards
  final wheelInfos = this.wheelInfos;
  final numWheels = wheelInfos.length;
  final chassisBody = this.chassisBody;
  List<Vec3> forwardWS = updateFrictionForwardWS;
  List<Vec3> axle = updateFrictionAxle;

  numWheelsOnGround = 0;

  for (int i = 0; i < numWheels; i++) {
    final wheel = wheelInfos[i];

    final groundObject = wheel.raycastResult.body;
    if (groundObject != null) {
      numWheelsOnGround++;
    }

    wheel.sideImpulse = 0;
    wheel.forwardImpulse = 0;
    if (forwardWS.length-1 < i){//!forwardWS[i]) {
      forwardWS.add(Vec3());
    }
    if (axle.length-1 < i){//!axle[i]) {
      axle.add(Vec3());
    }
  }

  for (int i = 0; i < numWheels; i++) {
    final wheel = wheelInfos[i];

    final groundObject = wheel.raycastResult.body;

    if (groundObject != null) {
      final axlei = axle[i];
      final wheelTrans = getWheelTransformWorld(i);

      // Get world axle
      wheelTrans.vectorToWorld(directions[indexRightAxis.index], axlei);

      final surfNormalWS = wheel.raycastResult.hitNormalWorld;
      final proj = axlei.dot(surfNormalWS);
      surfNormalWS.scale(proj, surfNormalWSScaledProj);
      axlei.vsub(surfNormalWSScaledProj, axlei);
      axlei.normalize();

      surfNormalWS.cross(axlei, forwardWS[i]);
      forwardWS[i].normalize();

      wheel.sideImpulse = resolveSingleBilateral(
        chassisBody,
        wheel.raycastResult.hitPointWorld,
        groundObject,
        wheel.raycastResult.hitPointWorld,
        axlei
      );

      wheel.sideImpulse *= _sideFrictionStiffness2;
    }
  }

  const sideFactor = 1;
  const fwdFactor = 0.5;
  sliding = false;

  for (int i = 0; i < numWheels; i++) {
    final wheel = wheelInfos[i];
    final groundObject = wheel.raycastResult.body;

    double rollingFriction = 0;

    wheel.slipInfo = 1;
    if (groundObject != null) {
      const double defaultRollingFrictionImpulse = 0;
      final double maxImpulse = wheel.brake != 0 ? wheel.brake : defaultRollingFrictionImpulse;

      // btWheelContactPoint contactPt(chassisBody,groundObject,wheelInfraycastInfo.hitPointWorld,forwardWS[wheel],maxImpulse);
      // rollingFriction = calcRollingFriction(contactPt);
      rollingFriction = calcRollingFriction(
        chassisBody,
        groundObject,
        wheel.raycastResult.hitPointWorld,
        forwardWS[i],
        maxImpulse
      );

      rollingFriction += wheel.engineForce * timeStep;

      // rollingFriction = 0;
      final factor = maxImpulse / rollingFriction;
      wheel.slipInfo *= factor;
    }

    //switch between active rolling (throttle), braking and non-active rolling friction (nthrottle/break)

    wheel.forwardImpulse = 0;
    wheel.skidInfo = 1;

    if (groundObject != null) {
      wheel.skidInfo = 1;

      final maximp = wheel.suspensionForce * timeStep * wheel.frictionSlip;
      final maximpSide = maximp;

      final maximpSquared = maximp * maximpSide;

      wheel.forwardImpulse = rollingFriction; //wheelInfo.engineForce* timeStep;

      final x = (wheel.forwardImpulse * fwdFactor) / wheel.forwardAcceleration;
      final y = (wheel.sideImpulse * sideFactor) / wheel.sideAcceleration;

      final impulseSquared = x * x + y * y;

      wheel.sliding = false;
      if (impulseSquared > maximpSquared) {
        sliding = true;
        wheel.sliding = true;

        final factor = maximp / math.sqrt(impulseSquared);

        wheel.skidInfo *= factor;
      }
    }
  }

  if (sliding) {
    for (int i = 0; i < numWheels; i++) {
      final wheel = wheelInfos[i];
      if (wheel.sideImpulse != 0) {
        if (wheel.skidInfo < 1) {
          wheel.forwardImpulse *= wheel.skidInfo;
          wheel.sideImpulse *= wheel.skidInfo;
        }
      }
    }
  }

  // apply the impulses
  for (int i = 0; i < numWheels; i++) {
    final wheel = wheelInfos[i];

    final relPos = Vec3();
    wheel.raycastResult.hitPointWorld.vsub(chassisBody.position, relPos);
    // cannons applyimpulse is using world coord for the position
    //rel_pos.copy(wheel.raycastResult.hitPointWorld);

    if (wheel.forwardImpulse != 0) {
      final impulse = Vec3();
      forwardWS[i].scale(wheel.forwardImpulse, impulse);
      chassisBody.applyImpulse(impulse, relPos);
    }

    if (wheel.sideImpulse != 0) {
      final groundObject = wheel.raycastResult.body!;

      final relPos2 = Vec3();
      wheel.raycastResult.hitPointWorld.vsub(groundObject.position, relPos2);
      //rel_pos2.copy(wheel.raycastResult.hitPointWorld);
      final sideImp = Vec3();
      axle[i].scale(wheel.sideImpulse, sideImp);

      // Scale the relative position in the up direction with rollInfluence.
      // If rollInfluence is 1, the impulse will be applied on the hitPoint (easy to roll over), if it is zero it will be applied in the same plane as the center of mass (not easy to roll over).
      chassisBody.vectorToLocalFrame(relPos, relPos);
      relPos[indexUpAxis.index] *= wheel.rollInfluence;//'xyz'[this.indexUpAxis] as 'x' | 'y' | 'z'
      chassisBody.vectorToWorldFrame(relPos, relPos);
      chassisBody.applyImpulse(sideImp, relPos);

      //apply friction impulse on the ground
      sideImp.scale(-1, sideImp);
      groundObject.applyImpulse(sideImp, relPos2);
    }
  }
}