diff --git a/Source/Editor/Windows/Profiler/Physics.cs b/Source/Editor/Windows/Profiler/Physics.cs
new file mode 100644
index 000000000..b2f52462d
--- /dev/null
+++ b/Source/Editor/Windows/Profiler/Physics.cs
@@ -0,0 +1,113 @@
+// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
+
+using FlaxEngine;
+using FlaxEngine.GUI;
+
+namespace FlaxEditor.Windows.Profiler
+{
+ ///
+ /// The physics simulation profiling mode.
+ ///
+ ///
+ internal sealed class Physics : ProfilerMode
+ {
+ private readonly SingleChart _activeBodiesChart;
+ private readonly SingleChart _activeJointsChart;
+ private readonly SingleChart _dynamicBodiesChart;
+ private readonly SingleChart _staticBodiesChart;
+ private readonly SingleChart _newPairsChart;
+ private readonly SingleChart _newTouchesChart;
+
+ public Physics()
+ : base("Physics")
+ {
+ // Layout
+ var panel = new Panel(ScrollBars.Vertical)
+ {
+ AnchorPreset = AnchorPresets.StretchAll,
+ Offsets = Margin.Zero,
+ Parent = this,
+ };
+ var layout = new VerticalPanel
+ {
+ AnchorPreset = AnchorPresets.HorizontalStretchTop,
+ Offsets = Margin.Zero,
+ IsScrollable = true,
+ Parent = panel,
+ };
+
+ // Charts
+ _activeBodiesChart = new SingleChart
+ {
+ Title = "Active Bodies",
+ Parent = layout,
+ };
+ _activeBodiesChart.SelectedSampleChanged += OnSelectedSampleChanged;
+ _activeJointsChart = new SingleChart
+ {
+ Title = "Active Joints",
+ Parent = layout,
+ };
+ _activeJointsChart.SelectedSampleChanged += OnSelectedSampleChanged;
+ _dynamicBodiesChart = new SingleChart
+ {
+ Title = "Dynamic Bodies",
+ Parent = layout,
+ };
+ _dynamicBodiesChart.SelectedSampleChanged += OnSelectedSampleChanged;
+ _staticBodiesChart = new SingleChart
+ {
+ Title = "Static Bodies",
+ Parent = layout,
+ };
+ _staticBodiesChart.SelectedSampleChanged += OnSelectedSampleChanged;
+ _newPairsChart = new SingleChart
+ {
+ Title = "New Pairs",
+ Parent = layout,
+ };
+ _newPairsChart.SelectedSampleChanged += OnSelectedSampleChanged;
+ _newTouchesChart = new SingleChart
+ {
+ Title = "New Touches",
+ Parent = layout,
+ };
+ _newTouchesChart.SelectedSampleChanged += OnSelectedSampleChanged;
+ }
+
+ ///
+ public override void Clear()
+ {
+ _activeBodiesChart.Clear();
+ _activeJointsChart.Clear();
+ _dynamicBodiesChart.Clear();
+ _staticBodiesChart.Clear();
+ _newPairsChart.Clear();
+ _newTouchesChart.Clear();
+ }
+
+ ///
+ public override void Update(ref SharedUpdateData sharedData)
+ {
+ PhysicsStatistics statistics = FlaxEngine.Physics.DefaultScene.Statistics;
+
+ _activeBodiesChart.AddSample(statistics.ActiveDynamicBodies + statistics.ActiveKinematicBodies);
+ _activeJointsChart.AddSample(statistics.ActiveJoints);
+ _dynamicBodiesChart.AddSample(statistics.DynamicBodies + statistics.KinematicBodies);
+ _staticBodiesChart.AddSample(statistics.StaticBodies);
+ _newPairsChart.AddSample(statistics.NewPairs);
+ _newTouchesChart.AddSample(statistics.NewTouches);
+ }
+
+ ///
+ public override void UpdateView(int selectedFrame, bool showOnlyLastUpdateEvents)
+ {
+ _activeBodiesChart.SelectedSampleIndex = selectedFrame;
+ _activeJointsChart.SelectedSampleIndex = selectedFrame;
+ _dynamicBodiesChart.SelectedSampleIndex = selectedFrame;
+ _staticBodiesChart.SelectedSampleIndex = selectedFrame;
+ _newPairsChart.SelectedSampleIndex = selectedFrame;
+ _newTouchesChart.SelectedSampleIndex = selectedFrame;
+ }
+ }
+}
diff --git a/Source/Editor/Windows/Profiler/ProfilerWindow.cs b/Source/Editor/Windows/Profiler/ProfilerWindow.cs
index b97e3a988..a723d64f2 100644
--- a/Source/Editor/Windows/Profiler/ProfilerWindow.cs
+++ b/Source/Editor/Windows/Profiler/ProfilerWindow.cs
@@ -200,6 +200,7 @@ namespace FlaxEditor.Windows.Profiler
AddMode(new Memory());
AddMode(new Assets());
AddMode(new Network());
+ AddMode(new Physics());
// Init view
_frameIndex = -1;
diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp
index 91e795a83..a0fbeefcc 100644
--- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp
+++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp
@@ -10,6 +10,7 @@
#include "Engine/Physics/CollisionData.h"
#include "Engine/Physics/PhysicalMaterial.h"
#include "Engine/Physics/PhysicsScene.h"
+#include "Engine/Physics/PhysicsStatistics.h"
#include "Engine/Physics/CollisionCooking.h"
#include "Engine/Physics/Actors/IPhysicsActor.h"
#include "Engine/Physics/Joints/Limits.h"
@@ -1340,6 +1341,30 @@ void PhysicsBackend::AddSceneActorAction(void* scene, void* actor, ActionType ac
FlushLocker.Unlock();
}
+#if COMPILE_WITH_PROFILER
+
+void PhysicsBackend::GetSceneStatistics(void* scene, PhysicsStatistics& result)
+{
+ PROFILE_CPU_NAMED("Physics.Statistics");
+ auto scenePhysX = (ScenePhysX*)scene;
+
+ PxSimulationStatistics px;
+ scenePhysX->Scene->getSimulationStatistics(px);
+
+ result.ActiveDynamicBodies = px.nbActiveDynamicBodies;
+ result.ActiveKinematicBodies = px.nbActiveKinematicBodies;
+ result.ActiveJoints = px.nbActiveConstraints;
+ result.StaticBodies = px.nbStaticBodies;
+ result.DynamicBodies = px.nbDynamicBodies;
+ result.KinematicBodies = px.nbKinematicBodies;
+ result.NewPairs = px.nbNewPairs;
+ result.LostPairs = px.nbLostPairs;
+ result.NewTouches = px.nbNewTouches;
+ result.LostTouches = px.nbLostTouches;
+}
+
+#endif
+
bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
{
SCENE_QUERY_SETUP(true);
diff --git a/Source/Engine/Physics/Physics.cpp b/Source/Engine/Physics/Physics.cpp
index 30d5cbe0c..007bfb6fd 100644
--- a/Source/Engine/Physics/Physics.cpp
+++ b/Source/Engine/Physics/Physics.cpp
@@ -5,6 +5,7 @@
#include "PhysicsBackend.h"
#include "PhysicalMaterial.h"
#include "PhysicsSettings.h"
+#include "PhysicsStatistics.h"
#include "Engine/Engine/Time.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Profiler/ProfilerCPU.h"
@@ -417,6 +418,17 @@ void PhysicsScene::SetOrigin(const Vector3& value)
}
}
+#if COMPILE_WITH_PROFILER
+
+PhysicsStatistics PhysicsScene::GetStatistics() const
+{
+ PhysicsStatistics result;
+ PhysicsBackend::GetSceneStatistics(_scene, result);
+ return result;
+}
+
+#endif
+
bool PhysicsScene::Init(const StringView& name, const PhysicsSettings& settings)
{
if (_scene)
diff --git a/Source/Engine/Physics/PhysicsBackend.h b/Source/Engine/Physics/PhysicsBackend.h
index fda15a079..f72c7f679 100644
--- a/Source/Engine/Physics/PhysicsBackend.h
+++ b/Source/Engine/Physics/PhysicsBackend.h
@@ -98,6 +98,9 @@ public:
static void AddSceneActor(void* scene, void* actor);
static void RemoveSceneActor(void* scene, void* actor);
static void AddSceneActorAction(void* scene, void* actor, ActionType action);
+#if COMPILE_WITH_PROFILER
+ static void GetSceneStatistics(void* scene, PhysicsStatistics& result);
+#endif
// Scene Queries
static bool RayCast(void* scene, const Vector3& origin, const Vector3& direction, float maxDistance, uint32 layerMask, bool hitTriggers);
diff --git a/Source/Engine/Physics/PhysicsBackendEmpty.cpp b/Source/Engine/Physics/PhysicsBackendEmpty.cpp
index 49861f0df..516562e28 100644
--- a/Source/Engine/Physics/PhysicsBackendEmpty.cpp
+++ b/Source/Engine/Physics/PhysicsBackendEmpty.cpp
@@ -123,6 +123,14 @@ void PhysicsBackend::AddSceneActorAction(void* scene, void* actor, ActionType ac
{
}
+#if COMPILE_WITH_PROFILER
+
+void PhysicsBackend::GetSceneStatistics(void* scene, PhysicsStatistics& result)
+{
+}
+
+#endif
+
bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
{
return false;
diff --git a/Source/Engine/Physics/PhysicsScene.h b/Source/Engine/Physics/PhysicsScene.h
index 81fab3507..bc6da6618 100644
--- a/Source/Engine/Physics/PhysicsScene.h
+++ b/Source/Engine/Physics/PhysicsScene.h
@@ -100,6 +100,13 @@ public:
///
API_PROPERTY() void SetOrigin(const Vector3& value);
+#if COMPILE_WITH_PROFILER
+ ///
+ /// Gets the physics simulation statistics for the scene.
+ ///
+ API_PROPERTY() PhysicsStatistics GetStatistics() const;
+#endif
+
public:
///
/// Initializes the scene.
diff --git a/Source/Engine/Physics/PhysicsStatistics.h b/Source/Engine/Physics/PhysicsStatistics.h
new file mode 100644
index 000000000..acb4393e9
--- /dev/null
+++ b/Source/Engine/Physics/PhysicsStatistics.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#include "Types.h"
+#include "Engine/Scripting/ScriptingType.h"
+
+///
+/// Physics simulation statistics container for profiler.
+///
+API_STRUCT(NoDefault) struct FLAXENGINE_API PhysicsStatistics
+{
+ DECLARE_SCRIPTING_TYPE_MINIMAL(PhysicsStatistics);
+
+ // Number of active dynamic bodies for the current simulation step. Does not include active kinematic bodies.
+ API_FIELD() uint32 ActiveDynamicBodies;
+ // Number of active kinematic bodies for the current simulation step.
+ API_FIELD() uint32 ActiveKinematicBodies;
+ // Number of active joints object for the current simulation step.
+ API_FIELD() uint32 ActiveJoints;
+ // Number of static bodies for the current simulation step.
+ API_FIELD() uint32 StaticBodies;
+ // Number of dynamic bodies for the current simulation step.
+ API_FIELD() uint32 DynamicBodies;
+ // Number of kinematic bodies for the current simulation step.
+ API_FIELD() uint32 KinematicBodies;
+ // Number of new pairs found during this frame.
+ API_FIELD() uint32 NewPairs;
+ // Number of lost pairs during this frame.
+ API_FIELD() uint32 LostPairs;
+ // Number of new touches found during this frame.
+ API_FIELD() uint32 NewTouches;
+ // Number of lost touches during this frame.
+ API_FIELD() uint32 LostTouches;
+
+ PhysicsStatistics()
+ {
+ Platform::MemoryClear(this, sizeof(PhysicsStatistics));
+ }
+};
diff --git a/Source/Engine/Physics/Types.h b/Source/Engine/Physics/Types.h
index b5b34ceec..ed12f8611 100644
--- a/Source/Engine/Physics/Types.h
+++ b/Source/Engine/Physics/Types.h
@@ -7,6 +7,7 @@
#include "Engine/Core/Math/Vector3.h"
#include "Engine/Scripting/ScriptingType.h"
+struct PhysicsStatistics;
class PhysicsColliderActor;
class PhysicsScene;
class Joint;