fix(vehicle): one chassis body, so the car sits on the road
The vehicle floated 3.7 m above the street because the physics asset had a body per bone and the four wheel bodies intersected the chassis body, pushing the whole thing up. It is now a single chassis body on the root bone (452 x 205 x 40 cm) - the same shape Unreal's vehicle template uses, because Chaos simulates the wheels itself and they must not be separate rigid bodies. Settle check, same spawn point: before: settled at Z 494 cm after: settled at Z 119 cm Added -drivetest, which holds full throttle for 3 s and reports speed and distance. It fails, and the failure names its own cause: BeginPlay logs '0 wheel objects after register' while the component reports 4 wheel setups, so no wheels exist to receive torque. Recorded in TODO.md with the next step - check the skeleton bone names against the setups, then give the front and rear pairs their own wheel subclasses instead of the base class.
This commit is contained in:
1 parent
4f3ed20e49
commit
5dd53ac30b
5 files changed
+86
-34
No files matched your search
@@ -91,7 +91,25 @@ void AGigLineVehicle::ConfigureWheels()
|
||||
void AGigLineVehicle::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
ConfigureWheels();
|
||||
|
||||
// Wheel objects do not exist until the component is registered, so the per-wheel
|
||||
// flags set in the constructor went nowhere - which is why the drive test measured
|
||||
// zero speed with throttle held. Apply them again now that they exist, and give the
|
||||
// engine a torque curve to actually make force.
|
||||
if (UChaosWheeledVehicleMovementComponent* Movement =
|
||||
Cast<UChaosWheeledVehicleMovementComponent>(GetVehicleMovementComponent()))
|
||||
{
|
||||
ConfigureWheels();
|
||||
Movement->EngineSetup.MaxTorque = 500.0f;
|
||||
Movement->EngineSetup.MaxRPM = 6000.0f;
|
||||
Movement->EngineSetup.EngineIdleRPM = 900.0f;
|
||||
Movement->TransmissionSetup.bUseAutomaticGears = true;
|
||||
Movement->TransmissionSetup.FinalRatio = 3.5f;
|
||||
Movement->SetThrottleInput(0.0f);
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine vehicle: %d wheel objects after register, torque %.0f"),
|
||||
Movement->Wheels.Num(), Movement->EngineSetup.MaxTorque);
|
||||
}
|
||||
UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: spawned at (%.0f, %.0f, %.0f), %d wheel setups"),
|
||||
GetActorLocation().X, GetActorLocation().Y, GetActorLocation().Z,
|
||||
GetVehicleMovementComponent()
|
||||
@@ -107,6 +125,35 @@ void AGigLineVehicle::Tick(float DeltaSeconds)
|
||||
// One settled-state report: proves the physics body exists, is simulating, and has
|
||||
// come to rest on the road rather than falling through it. Everything else about the
|
||||
// driving behaviour is measured later; this is the "is it real" check.
|
||||
// `-drivetest`: hold full throttle from 1 s to 4 s and report the result. A vehicle
|
||||
// that spawns is not a vehicle that drives.
|
||||
if (FParse::Param(FCommandLine::Get(), TEXT("drivetest")))
|
||||
{
|
||||
DriveElapsed += DeltaSeconds;
|
||||
if (UChaosVehicleMovementComponent* Movement = GetVehicleMovementComponent())
|
||||
{
|
||||
if (DriveElapsed > 1.0f && DriveElapsed < 4.0f)
|
||||
{
|
||||
Movement->SetThrottleInput(1.0f);
|
||||
}
|
||||
else if (DriveElapsed >= 4.0f && !bDriveReported)
|
||||
{
|
||||
Movement->SetThrottleInput(0.0f);
|
||||
bDriveReported = true;
|
||||
const float SpeedCm = Movement->GetForwardSpeed();
|
||||
const float TravelledM = FVector::Dist2D(GetActorLocation(), DriveStart) / 100.f;
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine vehicle DRIVETEST speed=%.0f cm/s (%.1f km/h), travelled %.1f m -> %s"),
|
||||
SpeedCm, SpeedCm * 0.036f, TravelledM,
|
||||
(SpeedCm > 200.f && TravelledM > 1.0f) ? TEXT("PASS") : TEXT("FAIL"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DriveStart.IsZero() && DriveElapsed > 1.0f)
|
||||
{
|
||||
DriveStart = GetActorLocation();
|
||||
}
|
||||
|
||||
SettleElapsed += DeltaSeconds;
|
||||
if (!bSettleReported && SettleElapsed > 3.0f)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,10 @@ private:
|
||||
/** Configure the Chaos wheels from the modelled dimensions. */
|
||||
void ConfigureWheels();
|
||||
|
||||
float DriveElapsed = 0.f;
|
||||
bool bDriveReported = false;
|
||||
FVector DriveStart = FVector::ZeroVector;
|
||||
|
||||
float SettleElapsed = 0.f;
|
||||
bool bSettleReported = false;
|
||||
};
|
||||
@@ -5,6 +5,10 @@
|
||||
#include "Engine/SkeletalMesh.h"
|
||||
#include "PhysicsAssetUtils.h"
|
||||
#include "PhysicsEngine/PhysicsAsset.h"
|
||||
#include "PhysicsEngine/BodySetup.h"
|
||||
#include "PhysicsEngine/SkeletalBodySetup.h"
|
||||
#include "Engine/SkeletalMesh.h"
|
||||
|
||||
#include "UObject/Package.h"
|
||||
#endif
|
||||
|
||||
@@ -28,34 +32,32 @@ UPhysicsAsset* UGigLineVehicleBuilder::BuildPhysicsAsset(USkeletalMesh* Mesh,
|
||||
}
|
||||
UPhysicsAsset* PhysicsAsset = NewObject<UPhysicsAsset>(Package, *AssetName,
|
||||
RF_Public | RF_Standalone | RF_Transactional);
|
||||
if (!PhysicsAsset)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: could not create %s"), *FullName);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Boxes on the five bones: a root box and four wheel capsules is what a car needs;
|
||||
// per-bone hulls from a 500-triangle mesh would add cost for nothing.
|
||||
FPhysAssetCreateParams Params;
|
||||
Params.MinBoneSize = 1.0f;
|
||||
Params.GeomType = EFG_Box;
|
||||
Params.bCreateConstraints = true;
|
||||
// Every bone gets a body: the vehicle has exactly five bones (root plus four
|
||||
// wheels) and each one needs collision, so filtering by bone size only produced a
|
||||
// single root body.
|
||||
Params.bBodyForAll = true;
|
||||
Params.bWalkPastSmall = false;
|
||||
Params.bDisableCollisionsByDefault = true;
|
||||
// ONE body on the chassis bone, which is what Unreal's own vehicle template uses.
|
||||
// The first attempt let FPhysicsAssetUtils build a body per bone and the car settled
|
||||
// 3.7 m above the road: the four wheel bodies were intersecting the chassis body and
|
||||
// pushing the whole vehicle up. Chaos drives the wheels itself, so they must not be
|
||||
// separate rigid bodies here.
|
||||
const FBoxSphereBounds Bounds = Mesh->GetBounds();
|
||||
const FVector Extent = Bounds.BoxExtent;
|
||||
const FName ChassisBone(TEXT("root"));
|
||||
|
||||
FText Error;
|
||||
const bool bOk = FPhysicsAssetUtils::CreateFromSkeletalMesh(
|
||||
PhysicsAsset, Mesh, Params, Error, /*bSetToMesh=*/true, /*bShowProgress=*/false);
|
||||
if (!bOk)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: physics asset build failed: %s"),
|
||||
*Error.ToString());
|
||||
return nullptr;
|
||||
}
|
||||
USkeletalBodySetup* Body = NewObject<USkeletalBodySetup>(PhysicsAsset, ChassisBone,
|
||||
RF_Public | RF_Transactional);
|
||||
Body->BoneName = ChassisBone;
|
||||
// A box slightly under the mesh bounds: a body that is exactly the bounds sits on the
|
||||
// ground plane and reads as floating because the mesh has wheels below the sills.
|
||||
FKBoxElem Box;
|
||||
Box.X = Extent.X * 1.9f;
|
||||
Box.Y = Extent.Y * 1.8f;
|
||||
Box.Z = Extent.Z * 0.55f;
|
||||
Box.Center = FVector(0.f, 0.f, -Extent.Z * 0.25f);
|
||||
Body->AggGeom.BoxElems.Add(Box);
|
||||
PhysicsAsset->SkeletalBodySetups.Add(Body);
|
||||
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine vehicle: chassis body %.0f x %.0f x %.0f cm on bone '%s'"),
|
||||
Box.X, Box.Y, Box.Z, *ChassisBone.ToString());
|
||||
|
||||
PhysicsAsset->MarkPackageDirty();
|
||||
UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: physics asset %s with %d bodies"),
|
||||
|
||||
Reference in new issue
Block a user