Skip to content

Commit

Permalink
terrain physics optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
turanszkij committed Feb 22, 2025
1 parent 6aa0633 commit 65081ab
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 74 deletions.
15 changes: 15 additions & 0 deletions WickedEngine/wiPhysics_Jolt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ namespace wi::physics
}
return *(RigidBody*)physicscomponent.physicsobject.get();
}
const RigidBody& GetRigidBody(const wi::scene::RigidBodyPhysicsComponent& physicscomponent)
{
return *(RigidBody*)physicscomponent.physicsobject.get();
}
SoftBody& GetSoftBody(wi::scene::SoftBodyPhysicsComponent& physicscomponent)
{
if (physicscomponent.physicsobject == nullptr)
Expand All @@ -321,6 +325,10 @@ namespace wi::physics
}
return *(SoftBody*)physicscomponent.physicsobject.get();
}
const SoftBody& GetSoftBody(const wi::scene::SoftBodyPhysicsComponent& physicscomponent)
{
return *(SoftBody*)physicscomponent.physicsobject.get();
}

void AddRigidBody(
wi::scene::Scene& scene,
Expand All @@ -341,6 +349,13 @@ namespace wi::physics
XMStoreFloat4x4(&transform.world, parentMatrix * transform.GetLocalMatrix());
transform.ApplyTransform();

if (mesh != nullptr && mesh->precomputed_rigidbody_physics_shape.physicsobject != nullptr)
{
// The shape comes from mesh's precomputed shape:
const RigidBody& precomputed_rigidbody_with_shape = GetRigidBody(mesh->precomputed_rigidbody_physics_shape);
physicsobject.shape = precomputed_rigidbody_with_shape.shape;
}

if (physicsobject.shape == nullptr) // shape creation can be called from outside as optimization from threads
{
CreateRigidBodyShape(physicscomponent, transform.scale_local, mesh);
Expand Down
128 changes: 65 additions & 63 deletions WickedEngine/wiScene_Components.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,69 @@ namespace wi::scene
void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri);
};

struct RigidBodyPhysicsComponent
{
enum FLAGS
{
EMPTY = 0,
DISABLE_DEACTIVATION = 1 << 0,
KINEMATIC = 1 << 1,
START_DEACTIVATED = 1 << 2,
};
uint32_t _flags = EMPTY;

enum CollisionShape
{
BOX,
SPHERE,
CAPSULE,
CONVEX_HULL,
TRIANGLE_MESH,
CYLINDER,
ENUM_FORCE_UINT32 = 0xFFFFFFFF
};
CollisionShape shape;
float mass = 1.0f; // Set to 0 to make body static
float friction = 0.2f;
float restitution = 0.1f;
float damping_linear = 0.05f;
float damping_angular = 0.05f;
float buoyancy = 1.2f;
XMFLOAT3 local_offset = XMFLOAT3(0, 0, 0);

struct BoxParams
{
XMFLOAT3 halfextents = XMFLOAT3(1, 1, 1);
} box;
struct SphereParams
{
float radius = 1;
} sphere;
struct CapsuleParams
{
float radius = 1;
float height = 1;
} capsule; // also cylinder params

// This will force LOD level for rigid body if it is a TRIANGLE_MESH shape:
// The geometry for LOD level will be taken from MeshComponent.
// The physics object will need to be recreated for it to take effect.
uint32_t mesh_lod = 0;

// Non-serialized attributes:
std::shared_ptr<void> physicsobject = nullptr; // You can set to null to recreate the physics object the next time phsyics system will be running.

constexpr void SetDisableDeactivation(bool value) { if (value) { _flags |= DISABLE_DEACTIVATION; } else { _flags &= ~DISABLE_DEACTIVATION; } }
constexpr void SetKinematic(bool value) { if (value) { _flags |= KINEMATIC; } else { _flags &= ~KINEMATIC; } }
constexpr void SetStartDeactivated(bool value) { if (value) { _flags |= START_DEACTIVATED; } else { _flags &= ~START_DEACTIVATED; } }

constexpr bool IsDisableDeactivation() const { return _flags & DISABLE_DEACTIVATION; }
constexpr bool IsKinematic() const { return _flags & KINEMATIC; }
constexpr bool IsStartDeactivated() const { return _flags & START_DEACTIVATED; }

void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri);
};

struct MeshComponent
{
enum FLAGS
Expand Down Expand Up @@ -512,6 +575,8 @@ namespace wi::scene
};
wi::vector<SubsetClusterRange> cluster_ranges;

RigidBodyPhysicsComponent precomputed_rigidbody_physics_shape; // you can precompute a physics shape here if you need without using a real rigid body component yet

constexpr void SetRenderable(bool value) { if (value) { _flags |= RENDERABLE; } else { _flags &= ~RENDERABLE; } }
constexpr void SetDoubleSided(bool value) { if (value) { _flags |= DOUBLE_SIDED; } else { _flags &= ~DOUBLE_SIDED; } }
constexpr void SetDoubleSidedShadow(bool value) { if (value) { _flags |= DOUBLE_SIDED_SHADOW; } else { _flags &= ~DOUBLE_SIDED_SHADOW; } }
Expand Down Expand Up @@ -955,69 +1020,6 @@ namespace wi::scene
};
};

struct RigidBodyPhysicsComponent
{
enum FLAGS
{
EMPTY = 0,
DISABLE_DEACTIVATION = 1 << 0,
KINEMATIC = 1 << 1,
START_DEACTIVATED = 1 << 2,
};
uint32_t _flags = EMPTY;

enum CollisionShape
{
BOX,
SPHERE,
CAPSULE,
CONVEX_HULL,
TRIANGLE_MESH,
CYLINDER,
ENUM_FORCE_UINT32 = 0xFFFFFFFF
};
CollisionShape shape;
float mass = 1.0f; // Set to 0 to make body static
float friction = 0.2f;
float restitution = 0.1f;
float damping_linear = 0.05f;
float damping_angular = 0.05f;
float buoyancy = 1.2f;
XMFLOAT3 local_offset = XMFLOAT3(0, 0, 0);

struct BoxParams
{
XMFLOAT3 halfextents = XMFLOAT3(1, 1, 1);
} box;
struct SphereParams
{
float radius = 1;
} sphere;
struct CapsuleParams
{
float radius = 1;
float height = 1;
} capsule; // also cylinder params

// This will force LOD level for rigid body if it is a TRIANGLE_MESH shape:
// The geometry for LOD level will be taken from MeshComponent.
// The physics object will need to be recreated for it to take effect.
uint32_t mesh_lod = 0;

// Non-serialized attributes:
std::shared_ptr<void> physicsobject = nullptr; // You can set to null to recreate the physics object the next time phsyics system will be running.

constexpr void SetDisableDeactivation(bool value) { if (value) { _flags |= DISABLE_DEACTIVATION; } else { _flags &= ~DISABLE_DEACTIVATION; } }
constexpr void SetKinematic(bool value) { if (value) { _flags |= KINEMATIC; } else { _flags &= ~KINEMATIC; } }
constexpr void SetStartDeactivated(bool value) { if (value) { _flags |= START_DEACTIVATED; } else { _flags &= ~START_DEACTIVATED; } }

constexpr bool IsDisableDeactivation() const { return _flags & DISABLE_DEACTIVATION; }
constexpr bool IsKinematic() const { return _flags & KINEMATIC; }
constexpr bool IsStartDeactivated() const { return _flags & START_DEACTIVATED; }

void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri);
};

struct SoftBodyPhysicsComponent
{
enum FLAGS
Expand Down
31 changes: 21 additions & 10 deletions WickedEngine/wiTerrain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,8 +556,8 @@ namespace wi::terrain

void Terrain::Generation_Update(const CameraComponent& camera)
{
// The generation task is always cancelled every frame so we are sure that generation is not running at this point
Generation_Cancel();
if (wi::jobsystem::IsBusy(generator->workload))
return; // updating can't run while generation is running. Note: we could cancel here, but it could take long until cancel request is fulfilled (happened with physics mesh creations)

bool restart_generation = false;
if (!IsGenerationStarted())
Expand Down Expand Up @@ -803,12 +803,20 @@ namespace wi::terrain
{
const ObjectComponent* object = scene->objects.GetComponent(chunk_data.entity);

if (rigidbody == nullptr && dist < physics_generation)
if (dist < physics_generation)
{
RigidBodyPhysicsComponent& newrigidbody = scene->rigidbodies.Create(chunk_data.entity);
newrigidbody.shape = RigidBodyPhysicsComponent::TRIANGLE_MESH;
newrigidbody.mass = 0; // terrain chunks are static
newrigidbody.friction = 0.8f;
if (rigidbody == nullptr)
{
RigidBodyPhysicsComponent& newrigidbody = scene->rigidbodies.Create(chunk_data.entity);
newrigidbody.shape = RigidBodyPhysicsComponent::TRIANGLE_MESH;
newrigidbody.mass = 0; // terrain chunks are static
newrigidbody.friction = 0.8f;
newrigidbody.mesh_lod = 2;
}
}
else if(rigidbody != nullptr)
{
scene->rigidbodies.Remove(chunk_data.entity);
}
}
else
Expand Down Expand Up @@ -842,6 +850,7 @@ namespace wi::terrain
}

// Start the generation on a background thread and keep it running until the next frame
generator->cancelled.store(false);
generator->workload.priority = wi::jobsystem::Priority::Low;
wi::jobsystem::Execute(generator->workload, [=](wi::jobsystem::JobArgs a) {

Expand Down Expand Up @@ -1023,13 +1032,15 @@ namespace wi::terrain
// Create the textures for virtual texture update:
CreateChunkRegionTexture(chunk_data);

const int dist = std::max(std::abs(center_chunk.x - chunk.x), std::abs(center_chunk.z - chunk.z));
if (IsPhysicsEnabled() && dist < physics_generation)
if (IsPhysicsEnabled())
{
RigidBodyPhysicsComponent& newrigidbody = generator->scene.rigidbodies.Create(chunk_data.entity);
// Precompute the physics shape here on separate thread, because computing shape for triangle mesh would be slow on main thread:
// Note that this is mesh.precomputed_rigidbody_physics_shape and not a component in scene.rigidbodies, so this only contains the shape, not the simulated rigid bodies
RigidBodyPhysicsComponent& newrigidbody = mesh.precomputed_rigidbody_physics_shape;
newrigidbody.shape = RigidBodyPhysicsComponent::TRIANGLE_MESH;
newrigidbody.mass = 0; // terrain chunks are static
newrigidbody.friction = 0.8f;
newrigidbody.mesh_lod = 2;
wi::physics::CreateRigidBodyShape(newrigidbody, transform.scale_local, &mesh);
}

Expand Down
2 changes: 1 addition & 1 deletion WickedEngine/wiVersion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 71;
// minor bug fixes, alterations, refactors, updates
const int revision = 687;
const int revision = 688;

const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);

Expand Down

0 comments on commit 65081ab

Please sign in to comment.