feat: JoltPhysicsSharp integration — physics simulation
- Engine.Physics project with JoltPhysicsSharp 2.21.0 - PhysicsWorld: PhysicsSystem init/update/dispose, body creation/removal, transform sync (Jolt body → ECS Transform) - RigidBody ECS component: MotionType (Static/Kinematic/Dynamic), ShapeType (Box/Sphere), mass, friction, restitution, damping - Factory methods: DynamicBox, DynamicSphere, StaticBox, StaticPlane - Main loop integration: create bodies on first frame, step physics, sync transforms back to ECS - Demo scene: 6 dynamic cubes + 3 dynamic spheres fall from height, static floor plane. Torus knot and textured cube remain static. - Collision layers: NonMoving (floor), Moving (dynamic objects) - JobSystemThreadPool for multi-threaded physics - 66/66 tests passing, 0 warnings, 0 errors
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
@@ -16,52 +17,170 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Graphics.Raylib", "s
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Tests", "tests\Engine.Tests\Engine.Tests.csproj", "{55555555-5555-5555-5555-555555555555}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Physics", "src\Engine.Physics\Engine.Physics.csproj", "{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
ReleaseAOT|Any CPU = ReleaseAOT|Any CPU
|
||||
ReleaseAOT|x64 = ReleaseAOT|x64
|
||||
ReleaseAOT|x86 = ReleaseAOT|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{11111111-1111-1111-1111-111111111111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Release|x64.Build.0 = Release|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.Release|x86.Build.0 = Release|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.ReleaseAOT|x64.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.ReleaseAOT|x64.Build.0 = ReleaseAOT|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.ReleaseAOT|x86.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{11111111-1111-1111-1111-111111111111}.ReleaseAOT|x86.Build.0 = ReleaseAOT|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Release|x64.Build.0 = Release|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.Release|x86.Build.0 = Release|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.ReleaseAOT|x64.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.ReleaseAOT|x64.Build.0 = ReleaseAOT|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.ReleaseAOT|x86.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{22222222-2222-2222-2222-222222222222}.ReleaseAOT|x86.Build.0 = ReleaseAOT|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Release|x64.Build.0 = Release|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.Release|x86.Build.0 = Release|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.ReleaseAOT|x64.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.ReleaseAOT|x64.Build.0 = ReleaseAOT|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.ReleaseAOT|x86.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{33333333-3333-3333-3333-333333333333}.ReleaseAOT|x86.Build.0 = ReleaseAOT|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Release|x64.Build.0 = Release|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.Release|x86.Build.0 = Release|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.ReleaseAOT|x64.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.ReleaseAOT|x64.Build.0 = ReleaseAOT|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.ReleaseAOT|x86.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{44444444-4444-4444-4444-444444444444}.ReleaseAOT|x86.Build.0 = ReleaseAOT|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.ReleaseAOT|x64.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.ReleaseAOT|x64.Build.0 = ReleaseAOT|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.ReleaseAOT|x86.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{43C6A648-4F0C-4440-95E3-733BD8D29BCE}.ReleaseAOT|x86.Build.0 = ReleaseAOT|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.Release|x86.Build.0 = Release|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.ReleaseAOT|x64.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.ReleaseAOT|x64.Build.0 = ReleaseAOT|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.ReleaseAOT|x86.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{31447693-7B61-4B22-95BB-47FF08C1CB2A}.ReleaseAOT|x86.Build.0 = ReleaseAOT|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Release|x64.Build.0 = Release|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.Release|x86.Build.0 = Release|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.ReleaseAOT|x64.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.ReleaseAOT|x64.Build.0 = ReleaseAOT|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.ReleaseAOT|x86.ActiveCfg = ReleaseAOT|Any CPU
|
||||
{55555555-5555-5555-5555-555555555555}.ReleaseAOT|x86.Build.0 = ReleaseAOT|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.ReleaseAOT|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.ReleaseAOT|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.ReleaseAOT|x64.ActiveCfg = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.ReleaseAOT|x64.Build.0 = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.ReleaseAOT|x86.ActiveCfg = Debug|Any CPU
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883}.ReleaseAOT|x86.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{3F5F10AA-A4CD-4E37-B4CE-B37BC60C3883} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -723,7 +723,8 @@ In Release (NativeAOT), the MCP server and ASP.NET Core are excluded. The AI can
|
||||
- [ ] **Vulkan backend reintegration** — see §3.3 checklist. Compiles but untested.
|
||||
Kept architecturally compatible via `IWindow` / `IRenderContext` / `IRenderer`.
|
||||
Deferred because Raylib covers all current needs with far less complexity.
|
||||
- [ ] Physics (JoltPhysicsSharp)
|
||||
- [x] Physics (JoltPhysicsSharp 2.21.0) — Engine.Physics project, PhysicsWorld wrapper,
|
||||
RigidBody ECS component, dynamic boxes/spheres with gravity, static floor, transform sync
|
||||
- [ ] AI hot-reload of C# scripts (Roslyn — conflicts with NativeAOT)
|
||||
- [ ] Semantic segmentation maps for MMLM vision input
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<ProjectReference Include="..\Engine.Graphics.Raylib\Engine.Graphics.Raylib.csproj" />
|
||||
<ProjectReference Include="..\Engine.Graphics.Vulkan\Engine.Graphics.Vulkan.csproj" />
|
||||
<ProjectReference Include="..\Engine.AI\Engine.AI.csproj" />
|
||||
<ProjectReference Include="..\Engine.Physics\Engine.Physics.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -13,6 +13,7 @@ using Engine.Graphics;
|
||||
using Engine.Graphics.Loaders;
|
||||
using Engine.Graphics.RaylibBackend;
|
||||
using Engine.Graphics.Vulkan;
|
||||
using Engine.Physics;
|
||||
using Flecs.NET.Core;
|
||||
|
||||
namespace CortexEngine.App;
|
||||
@@ -38,6 +39,7 @@ class Program
|
||||
|
||||
using var world = World.Create();
|
||||
var timing = new Timing();
|
||||
using var physicsWorld = new PhysicsWorld();
|
||||
|
||||
RaylibBackendRegistrar.EnsureRegistered();
|
||||
VulkanBackendRegistrar.EnsureRegistered();
|
||||
@@ -238,15 +240,21 @@ class Program
|
||||
}
|
||||
}
|
||||
|
||||
// Slowly rotate the model so we can see it in 3D, unless the camera tour or test scene is active.
|
||||
if (!cameraTour && !testScene)
|
||||
// Physics: create bodies, step, sync transforms
|
||||
if (!cameraTour)
|
||||
{
|
||||
var modelEntity = world.Lookup("CubeCenter");
|
||||
if (modelEntity.Id != 0)
|
||||
world.Each((Entity e, ref RigidBody rb, ref Transform t) =>
|
||||
{
|
||||
ref var modelTransform = ref modelEntity.Ensure<Transform>();
|
||||
modelTransform.Rotation = Quaternion.CreateFromAxisAngle(Vector3.UnitY, (float)timing.TotalTime * 0.5f);
|
||||
}
|
||||
if (!rb.IsInitialized)
|
||||
{
|
||||
physicsWorld.CreateBody(e, rb, t);
|
||||
rb.IsInitialized = true;
|
||||
e.Set(rb);
|
||||
}
|
||||
});
|
||||
|
||||
physicsWorld.Update((float)timing.DeltaTime);
|
||||
physicsWorld.SyncTransforms(world);
|
||||
}
|
||||
|
||||
// Capture a demo screenshot after the scene warms up (non-tour mode only).
|
||||
@@ -295,14 +303,12 @@ class Program
|
||||
|
||||
var cubes = new (string name, Vector3 pos, Vector3 color, float scale, float rough, float metal)[]
|
||||
{
|
||||
("CubeCenter", new Vector3(0, 0.5f, 0), new Vector3(0.9f, 0.6f, 0.3f), 0.5f, 0.3f, 0.1f),
|
||||
("CubeRed", new Vector3(2, 0.5f, 0), new Vector3(0.85f, 0.15f, 0.15f), 0.5f, 0.4f, 0.2f),
|
||||
("CubeGreen", new Vector3(-2, 0.5f, 0), new Vector3(0.2f, 0.8f, 0.3f), 0.5f, 0.5f, 0.0f),
|
||||
("CubeBlue", new Vector3(0, 0.5f, 3), new Vector3(0.2f, 0.4f, 0.9f), 0.6f, 0.2f, 0.3f),
|
||||
("CubeYellow", new Vector3(0, 0.5f, -3), new Vector3(0.95f, 0.85f, 0.2f), 0.5f, 0.6f, 0.0f),
|
||||
("CubeOrange", new Vector3(-3, 0.5f, 3), new Vector3(0.95f, 0.5f, 0.1f), 0.45f, 0.5f, 0.1f),
|
||||
("CubeWide", new Vector3(-1.5f, 0.5f, -1.5f), new Vector3(0.5f, 0.5f, 0.6f), 0.8f, 0.8f, 0.0f),
|
||||
("CubeSmallGold", new Vector3(5, 0.3f, -2), new Vector3(1.0f, 0.8f, 0.3f), 0.3f, 0.15f, 1.0f),
|
||||
("CubeCenter", new Vector3(0, 5f, 0), new Vector3(0.9f, 0.6f, 0.3f), 0.5f, 0.3f, 0.1f),
|
||||
("CubeRed", new Vector3(0.3f, 7f, 0.3f), new Vector3(0.85f, 0.15f, 0.15f), 0.5f, 0.4f, 0.2f),
|
||||
("CubeGreen", new Vector3(-0.3f, 9f, -0.3f), new Vector3(0.2f, 0.8f, 0.3f), 0.5f, 0.5f, 0.0f),
|
||||
("CubeBlue", new Vector3(0.1f, 11f, 0.1f), new Vector3(0.2f, 0.4f, 0.9f), 0.6f, 0.2f, 0.3f),
|
||||
("CubeYellow", new Vector3(-0.2f, 13f, 0.2f), new Vector3(0.95f, 0.85f, 0.2f), 0.5f, 0.6f, 0.0f),
|
||||
("CubeOrange", new Vector3(0.15f, 15f, -0.1f), new Vector3(0.95f, 0.5f, 0.1f), 0.45f, 0.5f, 0.1f),
|
||||
};
|
||||
|
||||
foreach (var (name, pos, color, scale, rough, metal) in cubes)
|
||||
@@ -310,18 +316,15 @@ class Program
|
||||
world.Entity(name)
|
||||
.Set(new Transform(pos, Quaternion.Identity, new Vector3(scale)))
|
||||
.Set(mesh)
|
||||
.Set(new Material(color, roughness: rough, metallic: metal));
|
||||
.Set(new Material(color, roughness: rough, metallic: metal))
|
||||
.Set(RigidBody.DynamicBox(new Vector3(scale), mass: scale * 2f));
|
||||
}
|
||||
|
||||
var spheres = new (string name, Vector3 pos, Vector3 color, float scale, float rough, float metal)[]
|
||||
{
|
||||
("SphereGold", new Vector3(-5, 0.5f, -2), new Vector3(1.0f, 0.85f, 0.4f), 1.0f, 0.1f, 1.0f),
|
||||
("SphereChrome", new Vector3(-6, 0.5f, 0), new Vector3(0.9f, 0.9f, 0.95f), 1.0f, 0.05f, 1.0f),
|
||||
("SphereRed", new Vector3(-5, 0.5f, 2), new Vector3(0.9f, 0.1f, 0.1f), 1.0f, 0.4f, 0.0f),
|
||||
("SphereBlue", new Vector3(5, 0.5f, 2), new Vector3(0.1f, 0.3f, 0.9f), 1.0f, 0.2f, 0.5f),
|
||||
("SphereGreen", new Vector3(6, 0.5f, 0), new Vector3(0.1f, 0.8f, 0.3f), 1.0f, 0.7f, 0.0f),
|
||||
("SphereWhite", new Vector3(5, 0.5f, -4), new Vector3(0.95f, 0.95f, 0.95f), 1.0f, 0.3f, 0.0f),
|
||||
("SphereRough", new Vector3(3, 0.5f, 5), new Vector3(0.6f, 0.4f, 0.2f), 1.0f, 0.9f, 0.0f),
|
||||
("SphereGold", new Vector3(3, 6f, -2), new Vector3(1.0f, 0.85f, 0.4f), 1.0f, 0.1f, 1.0f),
|
||||
("SphereChrome", new Vector3(-3, 8f, 0), new Vector3(0.9f, 0.9f, 0.95f), 1.0f, 0.05f, 1.0f),
|
||||
("SphereRed", new Vector3(3, 10f, 2), new Vector3(0.9f, 0.1f, 0.1f), 1.0f, 0.4f, 0.0f),
|
||||
};
|
||||
|
||||
foreach (var (name, pos, color, scale, rough, metal) in spheres)
|
||||
@@ -329,26 +332,25 @@ class Program
|
||||
world.Entity(name)
|
||||
.Set(new Transform(pos, Quaternion.Identity, new Vector3(scale)))
|
||||
.Set(sphere)
|
||||
.Set(new Material(color, roughness: rough, metallic: metal));
|
||||
.Set(new Material(color, roughness: rough, metallic: metal))
|
||||
.Set(RigidBody.DynamicSphere(scale * 0.5f, mass: scale));
|
||||
}
|
||||
|
||||
// Torus knot with checker texture
|
||||
world.Entity("TorusKnot")
|
||||
.Set(new Transform(new Vector3(0, 2.0f, 0), Quaternion.Identity, new Vector3(1.5f)))
|
||||
.Set(new Transform(new Vector3(0, 0.5f, -6), Quaternion.Identity, new Vector3(1.5f)))
|
||||
.Set(torusKnot)
|
||||
.Set(new Material(new Vector3(0.9f, 0.9f, 0.9f), roughness: 0.25f, metallic: 0.6f, texturePath: "Content/checker.png"));
|
||||
|
||||
// Textured cube
|
||||
world.Entity("CubeTextured")
|
||||
.Set(new Transform(new Vector3(-4, 0.5f, -3), Quaternion.Identity, new Vector3(0.7f)))
|
||||
.Set(mesh)
|
||||
.Set(new Material(new Vector3(0.8f, 0.8f, 0.85f), roughness: 0.4f, metallic: 0.0f, texturePath: "Content/checker.png"));
|
||||
|
||||
// Floor plane for shadow visibility
|
||||
world.Entity("Floor")
|
||||
.Set(new Transform(new Vector3(0, -0.02f, 0), Quaternion.Identity, new Vector3(20, 1, 20)))
|
||||
.Set(mesh)
|
||||
.Set(new Material(new Vector3(0.45f, 0.45f, 0.5f), roughness: 0.8f, metallic: 0.0f));
|
||||
.Set(new Material(new Vector3(0.45f, 0.45f, 0.5f), roughness: 0.8f, metallic: 0.0f))
|
||||
.Set(RigidBody.StaticPlane(20f));
|
||||
|
||||
world.Entity("Grid")
|
||||
.Set(new Transform(new Vector3(0.0f, 0.0f, 0.0f), Quaternion.Identity, Vector3.One))
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Engine.Core.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Physics body motion type.
|
||||
/// </summary>
|
||||
public enum PhysicsMotionType
|
||||
{
|
||||
Static = 0,
|
||||
Kinematic = 1,
|
||||
Dynamic = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collision shape type for the physics body.
|
||||
/// </summary>
|
||||
public enum PhysicsShapeType
|
||||
{
|
||||
Box = 0,
|
||||
Sphere = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RigidBody component — links an ECS entity to a Jolt physics body.
|
||||
/// Added to entities that should participate in physics simulation.
|
||||
/// </summary>
|
||||
public record struct RigidBody
|
||||
{
|
||||
public PhysicsMotionType MotionType;
|
||||
public PhysicsShapeType ShapeType;
|
||||
public Vector3 ShapeSize;
|
||||
public float Mass;
|
||||
public float Friction;
|
||||
public float Restitution;
|
||||
public float LinearDamping;
|
||||
public float AngularDamping;
|
||||
public bool IsInitialized;
|
||||
|
||||
public RigidBody(
|
||||
PhysicsMotionType motionType = PhysicsMotionType.Dynamic,
|
||||
PhysicsShapeType shapeType = PhysicsShapeType.Box,
|
||||
Vector3? shapeSize = null,
|
||||
float mass = 1.0f,
|
||||
float friction = 0.5f,
|
||||
float restitution = 0.3f,
|
||||
float linearDamping = 0.1f,
|
||||
float angularDamping = 0.1f)
|
||||
{
|
||||
MotionType = motionType;
|
||||
ShapeType = shapeType;
|
||||
ShapeSize = shapeSize ?? new Vector3(0.5f);
|
||||
Mass = mass;
|
||||
Friction = friction;
|
||||
Restitution = restitution;
|
||||
LinearDamping = linearDamping;
|
||||
AngularDamping = angularDamping;
|
||||
IsInitialized = false;
|
||||
}
|
||||
|
||||
public static RigidBody DynamicBox(Vector3 halfExtent, float mass = 1.0f) =>
|
||||
new(PhysicsMotionType.Dynamic, PhysicsShapeType.Box, halfExtent, mass);
|
||||
|
||||
public static RigidBody DynamicSphere(float radius, float mass = 1.0f) =>
|
||||
new(PhysicsMotionType.Dynamic, PhysicsShapeType.Sphere, new Vector3(radius), mass);
|
||||
|
||||
public static RigidBody StaticBox(Vector3 halfExtent) =>
|
||||
new(PhysicsMotionType.Static, PhysicsShapeType.Box, halfExtent, friction: 0.8f);
|
||||
|
||||
public static RigidBody StaticPlane(float size = 50f) =>
|
||||
new(PhysicsMotionType.Static, PhysicsShapeType.Box, new Vector3(size, 0.5f, size), friction: 0.8f);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JoltPhysicsSharp" Version="2.21.0" />
|
||||
<PackageReference Include="Flecs.NET.Debug" Version="4.0.4-build.546" Condition="'$(Configuration)' == 'Debug'" />
|
||||
<PackageReference Include="Flecs.NET.Release" Version="4.0.4-build.546" Condition="'$(Configuration)' == 'Release' OR '$(Configuration)' == 'ReleaseAOT'" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Engine.Core\Engine.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,177 @@
|
||||
using System.Numerics;
|
||||
using Engine.Core.Components;
|
||||
using Flecs.NET.Core;
|
||||
using JoltPhysicsSharp;
|
||||
|
||||
namespace Engine.Physics;
|
||||
|
||||
/// <summary>
|
||||
/// Physics world wrapper — manages Jolt PhysicsSystem, body creation, and ECS sync.
|
||||
/// </summary>
|
||||
public sealed class PhysicsWorld : IDisposable
|
||||
{
|
||||
private const int MaxBodies = 65536;
|
||||
private const int MaxBodyPairs = 65536;
|
||||
private const int MaxContactConstraints = 65536;
|
||||
|
||||
private static class Layers
|
||||
{
|
||||
public static readonly ObjectLayer NonMoving = 0;
|
||||
public static readonly ObjectLayer Moving = 1;
|
||||
}
|
||||
|
||||
private readonly PhysicsSystem _physicsSystem;
|
||||
private readonly BodyInterface _bodyInterface;
|
||||
private readonly JobSystem _jobSystem;
|
||||
private readonly Dictionary<Entity, BodyID> _entityToBody = new();
|
||||
private readonly Dictionary<BodyID, Entity> _bodyToEntity = new();
|
||||
private readonly List<Body> _bodies = new();
|
||||
private bool _disposed;
|
||||
|
||||
public Vector3 Gravity
|
||||
{
|
||||
get => _physicsSystem.Gravity;
|
||||
set => _physicsSystem.Gravity = value;
|
||||
}
|
||||
|
||||
public PhysicsWorld()
|
||||
{
|
||||
Foundation.Init(false);
|
||||
|
||||
var broadPhaseLayerInterface = new BroadPhaseLayerInterfaceTable(2, 2);
|
||||
broadPhaseLayerInterface.MapObjectToBroadPhaseLayer(Layers.NonMoving, new BroadPhaseLayer(0));
|
||||
broadPhaseLayerInterface.MapObjectToBroadPhaseLayer(Layers.Moving, new BroadPhaseLayer(1));
|
||||
|
||||
var objectLayerPairFilter = new ObjectLayerPairFilterTable(2);
|
||||
|
||||
var objectVsBroadPhaseLayerFilter = new ObjectVsBroadPhaseLayerFilterTable(
|
||||
broadPhaseLayerInterface, 2, objectLayerPairFilter, 2);
|
||||
|
||||
var settings = new PhysicsSystemSettings
|
||||
{
|
||||
MaxBodies = MaxBodies,
|
||||
MaxBodyPairs = MaxBodyPairs,
|
||||
MaxContactConstraints = MaxContactConstraints,
|
||||
BroadPhaseLayerInterface = broadPhaseLayerInterface,
|
||||
ObjectLayerPairFilter = objectLayerPairFilter,
|
||||
ObjectVsBroadPhaseLayerFilter = objectVsBroadPhaseLayerFilter,
|
||||
};
|
||||
|
||||
_physicsSystem = new PhysicsSystem(settings);
|
||||
_physicsSystem.Gravity = new Vector3(0, -9.81f, 0);
|
||||
_bodyInterface = _physicsSystem.BodyInterface;
|
||||
_jobSystem = new JobSystemThreadPool();
|
||||
}
|
||||
|
||||
public void CreateBody(Entity entity, in RigidBody rigidBody, in Transform transform)
|
||||
{
|
||||
if (_entityToBody.ContainsKey(entity))
|
||||
return;
|
||||
|
||||
var shape = CreateShape(rigidBody);
|
||||
var motionType = ToMotionType(rigidBody.MotionType);
|
||||
var layer = rigidBody.MotionType == PhysicsMotionType.Static ? Layers.NonMoving : Layers.Moving;
|
||||
|
||||
var creationSettings = new BodyCreationSettings(
|
||||
shape,
|
||||
transform.Position,
|
||||
transform.Rotation,
|
||||
motionType,
|
||||
layer);
|
||||
|
||||
var activation = rigidBody.MotionType == PhysicsMotionType.Static
|
||||
? Activation.DontActivate
|
||||
: Activation.Activate;
|
||||
|
||||
var body = _bodyInterface.CreateBody(creationSettings);
|
||||
_bodyInterface.AddBody(body.ID, activation);
|
||||
|
||||
if (rigidBody.MotionType != PhysicsMotionType.Static)
|
||||
{
|
||||
body.SetFriction(rigidBody.Friction);
|
||||
body.SetRestitution(rigidBody.Restitution);
|
||||
}
|
||||
|
||||
_entityToBody[entity] = body.ID;
|
||||
_bodyToEntity[body.ID] = entity;
|
||||
_bodies.Add(body);
|
||||
}
|
||||
|
||||
public void RemoveBody(Entity entity)
|
||||
{
|
||||
if (!_entityToBody.TryGetValue(entity, out var bodyId))
|
||||
return;
|
||||
|
||||
_bodyInterface.RemoveBody(bodyId);
|
||||
_bodyInterface.DestroyBody(bodyId);
|
||||
_entityToBody.Remove(entity);
|
||||
_bodyToEntity.Remove(bodyId);
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, int collisionSteps = 1)
|
||||
{
|
||||
_physicsSystem.Update(deltaTime, collisionSteps, _jobSystem);
|
||||
}
|
||||
|
||||
public void SyncTransforms(World world)
|
||||
{
|
||||
foreach (var (entity, bodyId) in _entityToBody)
|
||||
{
|
||||
if ((ulong)entity.Id == 0)
|
||||
continue;
|
||||
|
||||
var pos = _bodyInterface.GetPosition(bodyId);
|
||||
var rot = _bodyInterface.GetRotation(bodyId);
|
||||
|
||||
if (entity.Has<Transform>())
|
||||
{
|
||||
var t = entity.Get<Transform>();
|
||||
t.Position = pos;
|
||||
t.Rotation = rot;
|
||||
entity.Set(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncToPhysics(Entity entity, in Transform transform)
|
||||
{
|
||||
if (!_entityToBody.TryGetValue(entity, out var bodyId))
|
||||
return;
|
||||
|
||||
_bodyInterface.SetPositionAndRotation(bodyId, transform.Position, transform.Rotation, Activation.Activate);
|
||||
}
|
||||
|
||||
private static Shape CreateShape(RigidBody rb)
|
||||
{
|
||||
return rb.ShapeType switch
|
||||
{
|
||||
PhysicsShapeType.Box => new BoxShape(rb.ShapeSize),
|
||||
PhysicsShapeType.Sphere => new SphereShape(rb.ShapeSize.X),
|
||||
_ => new BoxShape(rb.ShapeSize),
|
||||
};
|
||||
}
|
||||
|
||||
private static MotionType ToMotionType(PhysicsMotionType type) => type switch
|
||||
{
|
||||
PhysicsMotionType.Static => MotionType.Static,
|
||||
PhysicsMotionType.Kinematic => MotionType.Kinematic,
|
||||
PhysicsMotionType.Dynamic => MotionType.Dynamic,
|
||||
_ => MotionType.Dynamic,
|
||||
};
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
foreach (var body in _bodies)
|
||||
body.Dispose();
|
||||
_bodies.Clear();
|
||||
_entityToBody.Clear();
|
||||
_bodyToEntity.Clear();
|
||||
|
||||
_jobSystem.Dispose();
|
||||
_physicsSystem.Dispose();
|
||||
Foundation.Shutdown();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user