[Chaos Vehicle] Experiences with the new vehicle implementation [+ SkidMark implementation]

If Physics is calculated in Client then replicated to server then its unsafe for a Competitive game right?

Depends. There are multiple ways to keep it in sync, but you need to know what you are doing network wise. Its the major case of “lag” normally.

With the new preview 5 the car physics is kinda bugged. First the engine crashed instantly due to a missing call to the method “OnCreatePhysicsState”. I hardcoded the call by a custom movement component. That somehow worked out well. But then the car just fell flat on the ground (suspension wouldn’t working at all). After debugging i found out, that the command “p.Vehicle.DisableSuspensionConstraint 1” does the trick, more or less. The car is driving again, but feels a lot stiffer than before

Hope the fix a few issues with the next upcoming version…

EDIT: I compared the code of the preview 5 version to the previous one. There aren’t any chances that justify this kind of behaviour

Any you can see… there’s a lot that’s different though. For one thing the Physical Animation thing can now be part of a BP without crashing the engine. Haven’t tried activating a ragdoll - don’t want to get my hopes up :stuck_out_tongue:

My foliage replacement thing mostly works.
I have 2 PHAT rigs. One was fixed coming into preview 1. the object works fine.
One I left alone (so imported from .25) The object jumps around like if collision somewhere is telling it to.

Mostly, the engine just crashes when you run with the usual D3D11RHI error. this has been going on/off since preview1


Assertion failed: GD3D11RHI->GetQueryData(Query->Resource, &Query->Result, sizeof(Query->Result), Query->QueryType, true, false) [File:D:/Build/++UE4/Sync/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11Query.cpp] [Line: 45]


What is curious is that the Gravity-less rig works like it used to when there was gravity applied, and that the one with gravity is the one that spazzes around for no reason.
Locked constraints don’t seem to be working with gravity enabled. AND OR, the mass of the capsule is ignored during physics calculations.
TBH, it’s a total mess still.

And I did just test things. The old code for entering ragdoll just goes into a T-pose so I would say that’s not working at all.
They are making progress though. At least having the physical animation component in doesn’t crash the engine :stuck_out_tongue:

I meant regarding the vehicle implementation. There are just very few changes…

Did you mean changes?

Either way, my horse cart is now even worse off than it was before, so yes… the last release is indeed disappointing…

Yes changes, typo :wink:

If you debug the original vehicles plugin you’ll notice, that the code within a “#if WITH_CHAOS” definition block will never be called…
Manually recompiling the plugin with deleted “#if WITH_CHAOS” definitions results in an error: the physX physic interface does not contain various functions.
It seems that they somehow managed to disable the chaos physics part, at least within the vehicles plugin :eek:

You can easily verfiy this by adding a faulty line, eg:
Error.png

they very likely added a “with chaos” switch in order to allow physx usage.
instead of removing the line you should try to change the value making it default to true across your whole project since it is very likely that they added the same IF to other pieces of code… / i would expect a checkbox or similar in editor or project settings, though didn’t see any.

Tried to “enforce” chaos, result: couple of errors that physx does not know few chaos related stuff (e.g. methods)…

Did a quick test with the UE4.26 Preview 6 - same result

Any update in the latest preview?
at a glance it seems like ragdolling is finally working again (granted by now all my ragdoll files are corrupted and i need to start them from 0 XD)

Event with the final 4.26 version my car setup isn’t working. They must changed some settings, which i haven’t found yet…
I’m currently quite preoccupied due to the PS5 (I’m one of the lucky guys, which got one on time in germany) and work/personal reasons, so that my time for personal developing is limited

I event tried to create a new 4.26 final project from scratch, enable the plugin and import my simple vehicle mesh (5 bones: root bone + 4 wheel bones). This didn’t work at all. Even the advanced vehicle debug pages aren’t working (cannot scroll through them or even display them).

Does anybody know if there is somewhere a flag to enable the vehicle behaviour? :confused:

Hey guys,

LeBoozer First of all, thank you very much for your research and for sharing your code. It helped me a lot!

I can confirm that Chaos Vehicle works fine when compiling from source and enabling chaos.

I attached the code for all files I changed compared to the current 4.26 source on GitHub. The code for **ExtendedChaosVehicle, ExtendedChaosWheeledVehicleMovementComponent, **etc., is LeBoozer’s previous work, but just includes wheel telemetrics. It had to undergo some small changes from 4.26 pr5 to 4.26 pr7 & release.

Thanks again LeBoozer, keep rolling.

Best regards,
Max

D:\ue4-426-release\Engine\Source*UE4Editor.Target.cs*
Just had to make sure that BuildEnvironment = TargetBuildEnvironment.Shared; and **NOT **BuildEnvironment = TargetBuildEnvironment.Unique;


// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;
using System.Collections.Generic;

public class UE4EditorTarget : TargetRules
{
public UE4EditorTarget( TargetInfo Target ) : base(Target)
{
Type = TargetType.Editor;
BuildEnvironment = TargetBuildEnvironment.Shared;
bBuildAllModules = true;
ExtraModuleNames.Add("UE4Game");

bCompileChaos = true;
bUseChaos = true;
}
}


Regarding the code you share I just implemented the WheelTelemetrics and had to do small adjustments from pr5 to pr7/release.

D:\ue4-426-release\Engine\Plugins\Experimental\ChaosVehiclesPlugin\Source\ChaosVehicles\Public*ExtendedChaosVehicle.h*


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Delegates/Delegate.h"
#include "Delegates/DelegateCombinations.h"
#include "PhysicalMaterials/PhysicalMaterial.h"
#include "PhysXIncludes.h"
#include "ExtendedChaosWheeledVehicleMovementComponent.h"
#include "WheeledVehiclePawn.h"
#include "ExtendedChaosVehicle.generated.h"

/**
*
*/
USTRUCT(Blueprintable)
struct FExtendedWheelInfo
{
GENERATED_BODY()

/** Get the wheel RPM [revolutions per minute] */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
float Rpm;

/** Get the magnitude of the force pressing the wheel into the terrain [N.m] */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
float LoadForce;

/** Get the slip angle for this wheel - angle between wheel forward axis and velocity vector [degrees] */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
float SlipAngle;

/** Difference between the ground speed of the wheel and the road speed [km/h] */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
float SlipVelocity;

/** Get the linear ground speed of the wheel based on its current rotational speed [km/h] */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
float GroundSpeed;

/** Get the road speed at the wheel [km/h] */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
float Speed;

/** Get the angular velocity of the wheel [degrees/sec] */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
float AngularVelocity;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
float NormalizedLateralSlip;

/** Get the current longitudinal slip value [0 no slip - using static friction, 1 full slip - using dynamic friction] */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
float NormalizedLongitudinalSlip;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
bool InAir;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
FString ContactSurfaceName;

//UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
//TWeakObjectPtr<UPhysicalMaterial> ContactSurface;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
int ContactSurfaceType;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
FVector ContactPoint;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
FVector ContactNormal;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedWheelInfo")
bool Slipping;

FExtendedWheelInfo() :
Rpm(0.0f),
LoadForce(0.0f),
SlipAngle(0.0f),
SlipVelocity(0.0f),
GroundSpeed(0.0f),
Speed(0.0f),
NormalizedLateralSlip(0.0f),
NormalizedLongitudinalSlip(0.0f),
InAir(false),
//ContactSurface(nullptr),
ContactSurfaceType(-1),
Slipping(false)
{}
};

/**
*
*/
USTRUCT(Blueprintable)
struct FExtendedVehicleInfo
{
GENERATED_BODY()

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedVehicleInfo")
int32 Speed;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedVehicleInfo")
float RPM;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedVehicleInfo")
int32 Gear;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedVehicleInfo")
bool Slipping;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedVehicleInfo")
bool Skidding;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ExtendedVehicleInfo")
TArray<FExtendedWheelInfo> WheelInfo;

FExtendedVehicleInfo() :
Speed(0),
RPM(0.0f),
Gear(0),
Slipping(false),
Skidding(false)
{}
};

/**
*
*/
USTRUCT(Blueprintable)
struct FTyreSqueal
{
GENERATED_BODY()

/** Threshold for the slip velocity [km/h] */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "TyreSqueal")
float SlipVelocityThreshold;

/** */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "TyreSqueal")
float SlipAngleThreshold;

FTyreSqueal() :
SlipVelocityThreshold(5.0f),
SlipAngleThreshold(40.0f)
{}
};

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FStartSlipping);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FStopSlipping);

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWheelEventWithIndex, uint8, WheelIndex);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FWheelEventWithIndexAndWheelInfo, uint8, WheelIndex, FExtendedWheelInfo, WheelInfo);

/**
*
*/
UCLASS(Blueprintable)
class AExtendedChaosVehicle : public AWheeledVehiclePawn
{
GENERATED_BODY()

UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "ExtendedChaosVehicle")
FStartSlipping OnStartSlipping;

UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "ExtendedChaosVehicle")
FStopSlipping OnStopSlipping;

UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "ExtendedChaosVehicle")
FWheelEventWithIndexAndWheelInfo OnWheelUpdate;

UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "ExtendedChaosVehicle")
FWheelEventWithIndexAndWheelInfo OnWheelStartSlipping;

UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "ExtendedChaosVehicle")
FWheelEventWithIndexAndWheelInfo OnWheelSlipping;

UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "ExtendedChaosVehicle")
FWheelEventWithIndexAndWheelInfo OnWheelStopSlipping;

private:
FExtendedVehicleInfo LatestVehicleInfo;
bool IsSlipping;

public:

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ExtendedChaosVehicle")
UMaterialInterface* Material;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ExtendedChaosVehicle")
FTyreSqueal TyreSqueal;

AExtendedChaosVehicle(const FObjectInitializer& ObjectInitializer) :
IsSlipping(false),
Super(ObjectInitializer.SetDefaultSubobjectClass<UExtendedChaosWheeledVehicleMovementComponent>(VehicleMovementComponentName))
{
}

void Tick(float deltaSeconds);

UFUNCTION(BlueprintCallable, BlueprintPure, Category = "ExtendedChaosVehicle")
inline FExtendedVehicleInfo GetVehicleInfo() { return LatestVehicleInfo; }

private:
FExtendedVehicleInfo DetermineVehicleInfo();
};

D:\ue4-426-release\Engine\Plugins\Experimental\ChaosVehiclesPlugin\Source\ChaosVehicles\Public*ExtendedChaosWheeledVehicleMovementComponent.h*


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Delegates/Delegate.h"
#include "Delegates/DelegateCombinations.h"
#include "PhysicalMaterials/PhysicalMaterial.h"
#include "PhysXIncludes.h"
#include "ChaosWheeledVehicleMovementComponent.h"
#include "ExtendedChaosWheeledVehicleMovementComponent.generated.h"

/**
*
*/
UCLASS(Blueprintable)
class UExtendedChaosWheeledVehicleMovementComponent : public UChaosWheeledVehicleMovementComponent
{
GENERATED_BODY()



public:


virtual void BeginPlay() override;
//void CreateVehicle(TArray<FWheelSetup> previousTires);


UChaosVehicleWheel* GetWheel(int wheelIdx);

};

D:\ue4-426-release\Engine\Plugins\Experimental\ChaosVehiclesPlugin\Source\ChaosVehicles\Private*ExtendedChaosVehicle.cpp*


// Fill out your copyright notice in the Description page of Project Settings.


#include "ExtendedChaosVehicle.h"

#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)

void AExtendedChaosVehicle::Tick(float deltaSeconds)
{
// Local variables
const auto movementComp = this->GetVehicleMovementComponent();

Super::Tick(deltaSeconds);

// Get next info
auto info = DetermineVehicleInfo();

// Check all wheels
bool skidding = false;
bool slipping = false;
for (auto idx = 0; idx < info.WheelInfo.Num(); ++idx)
{
// Get last wheel info
if (idx >= LatestVehicleInfo.WheelInfo.Num()) continue;
auto& lastWheel = LatestVehicleInfo.WheelInfo[idx];

// Get next wheel info
auto& wheel = info.WheelInfo[idx];

// Fire wheel event: start/stop slipping
if (!lastWheel.Slipping && wheel.Slipping)
{
// Reset slipping duration
//wheel.SlippingDuration = 0.0f;

// Fire callback
OnWheelStartSlipping.Broadcast(idx, wheel);
}
else if (lastWheel.Slipping && !wheel.Slipping) OnWheelStopSlipping.Broadcast(idx, wheel);
else if (wheel.Slipping)
{
// Update slipping duration
//wheel.SlippingDuration = lastWheel.SlippingDuration + deltaSeconds;

// Fire callback
OnWheelSlipping.Broadcast(idx, wheel);
}
OnWheelUpdate.Broadcast(idx, wheel);

// Accumulate skidding & slipping
slipping = slipping || wheel.Slipping;
}
info.Slipping = slipping;

// Fire events
if (!IsSlipping && slipping)
{
IsSlipping = true;
OnStartSlipping.Broadcast();
}
else if (IsSlipping && !slipping)
{
IsSlipping = false;
OnStopSlipping.Broadcast();
}

// Update latest info
LatestVehicleInfo = info;
}

FExtendedVehicleInfo AExtendedChaosVehicle::D
https:\/\/forums.unrealengine.com\/core\/image\/gif;base64
​​etermineVehicleInfo()
{
// Local variables
FExtendedVehicleInfo info;
const auto movementComp = (UExtendedChaosWheeledVehicleMovementComponent*)this->GetVehicleMovementComponent();

// Process wheel data
for (int32_t wIdx = 0; wIdx < movementComp->PhysicsVehicle()->Wheels.Num(); ++wIdx)
{
// Get reference
auto& wheel = movementComp->PhysicsVehicle()->Wheels[wIdx];
const auto& chaosWheel = movementComp->GetWheel(wIdx);

// Extract material's name
TWeakObjectPtr<UPhysicalMaterial> contactSurfaceMaterial = nullptr;
FString contactSurfaceString = "";
int contactSurfaceType = -1;

if (chaosWheel->GetContactSurfaceMaterial() && chaosWheel->GetContactSurfaceMaterial()->IsValidLowLevel())
{
contactSurfaceMaterial = chaosWheel->GetContactSurfaceMaterial();
contactSurfaceString = contactSurfaceMaterial != nullptr ? contactSurfaceMaterial->GetName() : FString(TEXT("NONE"));
contactSurfaceType = (int)contactSurfaceMaterial->SurfaceType;
}

// Add new wheel info
FExtendedWheelInfo wheelInfo;
wheelInfo.InAir = !wheel.bInContact;
wheelInfo.Rpm = wheel.GetWheelRPM();
wheelInfo.LoadForce = wheel.GetWheelLoadForce() * 0.01f;
wheelInfo.SlipAngle = FMath::RadiansToDegrees(wheel.GetSlipAngle());
wheelInfo.SlipVelocity = (wheel.GetWheelGroundSpeed() - wheel.GetRoadSpeed()) * 0.036f;
wheelInfo.AngularVelocity = wheel.GetAngularVelocity() * 57.3;
wheelInfo.GroundSpeed = wheel.GetWheelGroundSpeed() * 0.036f;
wheelInfo.Speed = wheel.GetRoadSpeed() * 0.036f;
wheelInfo.NormalizedLongitudinalSlip = wheel.GetNormalizedLongitudinalSlip();
wheelInfo.NormalizedLateralSlip = FMath::Clamp(FMath::RadiansToDegrees(wheel.GetSlipAngle()) / 30.0f, -1.f, 1.f);//wheel.GetNormalizedLateralSlip();
wheelInfo.ContactSurfaceName = contactSurfaceString;
wheelInfo.ContactSurfaceType = contactSurfaceType;
wheelInfo.ContactPoint = chaosWheel->HitResult.ImpactPoint;
wheelInfo.ContactNormal = chaosWheel->HitResult.ImpactNormal;

// Determine slipping & skidding
float slipAngle = abs(wheelInfo.SlipAngle);
wheelInfo.Slipping =
slipAngle > TyreSqueal.SlipAngleThreshold && slipAngle < (180.0f - TyreSqueal.SlipAngleThreshold) ||
abs(wheelInfo.SlipVelocity) > TyreSqueal.SlipVelocityThreshold;
wheelInfo.Slipping &= !wheelInfo.InAir;

// Add to list
info.WheelInfo.Add(wheelInfo);
}

return info;
}

D:\ue4-426-release\Engine\Plugins\Experimental\ChaosVehiclesPlugin\Source\ChaosVehicles\Private*ExtendedChaosWheeledVehicleMovementComponent.cpp*


#include "ExtendedChaosWheeledVehicleMovementComponent.h"

void UExtendedChaosWheeledVehicleMovementComponent::BeginPlay()
{
// Call parent
UChaosWheeledVehicleMovementComponent::BeginPlay();

}

/*void UExtendedChaosWheeledVehicleMovementComponent::CreateVehicle(TArray<ChaosWheelS> previousTires)
{
// Call parent
UChaosWheeledVehicleMovementComponent::CreateVehicle();

// Re-create skid mark meshes
if (previousTires.Num() != WheelSetups.Num())
{
DropSkidMarkMeshes();
CreateSkidMarkMeshes();
}
}*/


UChaosVehicleWheel* UExtendedChaosWheeledVehicleMovementComponent::GetWheel(int wheelIdx)
{
// Check parameter
check(wheelIdx <= this->Wheels.Num());
return this->Wheels[wheelIdx];
}



We wrapped a little demo using Chaos Vehicles. Thanks again @LeBoozer for sharing his work.

looks nice! :slight_smile:

@mniemann thx for pointing out, that the chaos vehicle is properly working in a source code build. Until now i haven’t used source code builds, but after a long session with the compiler deadlocking my whole computer while building the engine (:rolleyes::eek:) the vehicle is working now! :wink:

Today I tried a few things with the chaos vehicle (4.26 code build of the engine) and noticed a few things:

  1. The physical ground material is now included in the calculation of the overall wheel friction. This is quite nice, since different grounds (regarding the friction) can be achieved easily now → snow, mud …
  2. The physical and visual behaviour of accelerated wheels are incorrect as soon as the wheels are in air. Here is a short demonstation video to show you the behaviour:
    https://youtube.com/watch?v=HJBif4cTNAs
The game starts with a vehicle with no grounded wheel. Trying to accelerate result in nothing. The wheel won't spin. If you start the game with grouded accelerated wheels, the wheels will spin midair, but in just one direction (ignoring *reverse *completely).
Quick scan through the code: Within the simulation method of the *WheelSystem *one can see, that the omega value is only calculated for wheels, which are touching the ground. Otherwise the previously stored value will be used. This seems wrong...
  1. Somehow the differential type is inverted in relation to the expected physical result regarding the laterial friction (simplified: drifting). Front wheel drives drift like crazy and rear wheel drives nearly cannot drift at all. See this video for a short demonstration:
    https://youtube.com/watch?v=ZbA99cUDqLg
The values of the wheels / vehicle movement component are the same for both drive types. As you can see, one cannot manage to drift with the real wheel drive, but the front wheel drive ist drifting like a charm (in the video it's acutally drifting a way too much though...)

Hey every one got to try the new Chaos Vehicle Physics but have a problem my engine crush when I press Play!
Had to rebuild the engine from source after enabling the Physics but for some reason it crashes only when press play with a vehicle inside!

Chaos Error.PNG

If any one know what I did wrong please help me thx for reading!