Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: DotRecast for Bepu physics navigation and nav mesh generation #2529

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions build/Stride.sln
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.3D", "..\so
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.BepuPhysics.Tests", "..\sources\engine\Stride.BepuPhysics\Stride.BepuPhysics.Tests\Stride.BepuPhysics.Tests.csproj", "{7B70C783-4085-4702-B3C6-6570FD85CB8F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.DotRecast", "..\sources\engine\Stride.DotRecast\Stride.DotRecast\Stride.DotRecast.csproj", "{BF9881A7-79D2-49C5-8841-DDDE1A691664}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.BepuPhysics.Navigation", "..\sources\engine\Stride.BepuPhysics\Stride.BepuPhysics.Navigation\Stride.BepuPhysics.Navigation.csproj", "{41756CA4-EF28-40DE-A525-51F74398F08C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1525,6 +1529,30 @@ Global
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.ActiveCfg = Release|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Win32.Build.0 = Release|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Debug|Win32.ActiveCfg = Debug|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Debug|Win32.Build.0 = Debug|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Release|Any CPU.Build.0 = Release|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Release|Win32.ActiveCfg = Release|Any CPU
{BF9881A7-79D2-49C5-8841-DDDE1A691664}.Release|Win32.Build.0 = Release|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Debug|Win32.ActiveCfg = Debug|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Debug|Win32.Build.0 = Debug|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Release|Any CPU.Build.0 = Release|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Release|Win32.ActiveCfg = Release|Any CPU
{41756CA4-EF28-40DE-A525-51F74398F08C}.Release|Win32.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1655,6 +1683,8 @@ Global
{7715D094-DF59-4D91-BC9A-9A5118039ECB} = {DE048114-9AE4-467E-A879-188DC0D88A59}
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C}
{7B70C783-4085-4702-B3C6-6570FD85CB8F} = {DE048114-9AE4-467E-A879-188DC0D88A59}
{BF9881A7-79D2-49C5-8841-DDDE1A691664} = {4C142567-C42B-40F5-B092-798882190209}
{41756CA4-EF28-40DE-A525-51F74398F08C} = {DE048114-9AE4-467E-A879-188DC0D88A59}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FF877973-604D-4EA7-B5F5-A129961F9EF2}
Expand Down
4 changes: 2 additions & 2 deletions sources/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PackageVersion Include="DotRecast.Core" Version="2024.1.1" />
<PackageVersion Include="DotRecast.Detour" Version="2024.2.1" />
<PackageVersion Include="DotRecast.Recast" Version="2024.2.1" />
<PackageVersion Include="DotRecast.Recast.Toolset" Version="2024.3.1" />
<PackageVersion Include="DotRecast.Recast.Toolset" Version="2024.4.1" />
<PackageVersion Include="FFmpeg.AutoGen" Version="3.4.0.2" />
<PackageVersion Include="K4os.Compression.LZ4.Legacy" Version="1.3.6" />
<PackageVersion Include="Microsoft.Management.Infrastructure" Version="3.0.0-preview.4" />
Expand Down Expand Up @@ -144,4 +144,4 @@
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" PrivateAssets="all" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using Stride.Navigation;

namespace Stride.BepuPhysics.Navigation.Components;
[DefaultEntityComponentProcessor(typeof(RecastDynamicMeshProcessor), ExecutionMode = ExecutionMode.Runtime)]
//[DefaultEntityComponentProcessor(typeof(RecastDynamicMeshProcessor), ExecutionMode = ExecutionMode.Runtime)]
[ComponentCategory("Bepu")]
[DataContract("BepuNavigationBoundingBoxComponent")]
public class BepuNavigationBoundingBoxComponent : NavigationBoundingBoxComponent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ namespace Stride.BepuPhysics.Navigation.Components;
[DefaultEntityComponentProcessor(typeof(RecastNavigationProcessor), ExecutionMode = ExecutionMode.Runtime)]
public class RecastNavigationComponent : StartupScript
{

/// <summary>
/// The agent's navigation mesh id. Will be used to determine where a path is searched.
/// </summary>
public int AgentNavMeshId { get; set; }

/// <summary>
/// The speed at which the agent moves.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Stride.BepuPhysics.Definitions;
using Stride.Core.Mathematics;

namespace Stride.BepuPhysics.Navigation.Definitions;

internal class AsyncMeshInput
{
public readonly List<BasicMeshBuffers> ShapeData = [];
public readonly List<ShapeTransform> TransformsOut = [];
public readonly List<(Matrix entity, int count)> Matrices = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using System.Collections.Concurrent;
using DotRecast.Core;
using DotRecast.Detour;
using DotRecast.Detour.Dynamic;
using DotRecast.Recast;
using Stride.Core;
using Stride.DotRecast.Definitions;

namespace Stride.BepuPhysics.Navigation.Definitions;

[DataContract]
public class BepuNavMeshInfo
{
public bool IsDynamic { get; set; } = true;

public BuildSettings BuildSettings { get; set; } = new();

/// <summary>
/// Collision masks that will be included in the navigation mesh build.
/// </summary>
public CollisionMask CollisionMask { get; set; } = CollisionMask.Everything;

[DataMemberIgnore]
public DtNavMesh NavMesh { get; set; }
[DataMemberIgnore]
public DtDynamicNavMeshConfig Config;
[DataMemberIgnore]
public RcContext Context { get; set; }
[DataMemberIgnore]
public RcBuilder Builder { get; set; }
[DataMemberIgnore]
public Dictionary<long, DtDynamicTile> Tiles = [];
[DataMemberIgnore]
public DtNavMeshParams NavMeshParams;
[DataMemberIgnore]
public Dictionary<int, StaticComponent> StaticComponents = [];
[DataMemberIgnore]
public BlockingCollection<IDtDaynmicTileJob> UpdateQueue = [];
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using Stride.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stride.BepuPhysics.Navigation.Definitions;
[DataContract()]
[Display("Pathfinding Settings")]
public class PathfindingSettings
public class NavMeshShapeData
{
public int MaxAllowedVisitedTiles { get; set; } = 16;
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
using Stride.Core;
using Stride.Core.Threading;
using Stride.Data;
using Stride.DotRecast.Definitions;

namespace Stride.BepuPhysics.Navigation.Definitions;
[DataContract("RecastNavigationConfiguration")]
[Display("Recast Navigation")]
public class RecastNavigationConfiguration : Configuration
{
[Display("Build Settings", Expand = ExpandRule.Never)]
public BuildSettings BuildSettings { get; set; } = new();

[Display("Pathfinding Settings", Expand = ExpandRule.Never)]
public PathfindingSettings PathfindingSettings { get; set; } = new();

[Display("NavMeshes", Expand = ExpandRule.Once)]
public List<BepuNavMeshInfo> NavMeshes = [];

/// <summary>
/// Total thread count to use for pathfinding. Divided by 2 due to noticable stutter if all threads are used.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using System.Runtime.InteropServices;
using DotRecast.Detour;
using DotRecast.Recast.Toolset;
using Stride.BepuPhysics.Definitions;
using Stride.Core.Mathematics;
using Stride.BepuPhysics.Navigation.Definitions;
using Stride.DotRecast;
using Stride.DotRecast.Definitions;

namespace Stride.BepuPhysics.Navigation.GenericBuilder;
public class BepuNavMeshBuilder
{

/// <summary>
/// Used for Bepu specific mesh building.
/// </summary>
/// <param name="navSettings"></param>
/// <param name="input"></param>
/// <param name="threads"></param>
/// <param name="cancelToken"></param>
/// <returns></returns>
internal static DtNavMesh CreateBepuNavMesh(RcNavMeshBuildSettings navSettings, AsyncMeshInput input, int threads, CancellationToken cancelToken)
{
// /!\ THIS IS NOT RUNNING ON THE MAIN THREAD /!\

var verts = new List<VertexPosition3>();
var indices = new List<int>();
for (int collidableI = 0, shapeI = 0; collidableI < input.Matrices.Count; collidableI++)
{
var (collidableMatrix, shapeCount) = input.Matrices[collidableI];
collidableMatrix.Decompose(out _, out Matrix worldMatrix, out var translation);
worldMatrix.TranslationVector = translation;

for (int j = 0; j < shapeCount; j++, shapeI++)
{
var transform = input.TransformsOut[shapeI];
Matrix.Transformation(ref transform.Scale, ref transform.RotationLocal, ref transform.PositionLocal, out var localMatrix);
var finalMatrix = localMatrix * worldMatrix;

var shape = input.ShapeData[shapeI];
verts.EnsureCapacity(verts.Count + shape.Vertices.Length);
indices.EnsureCapacity(indices.Count + shape.Indices.Length);

int vertexBufferStart = verts.Count;

for (int i = 0; i < shape.Indices.Length; i += 3)
{
var index0 = shape.Indices[i];
var index1 = shape.Indices[i + 1];
var index2 = shape.Indices[i + 2];
indices.Add(vertexBufferStart + index0);
indices.Add(vertexBufferStart + index2);
indices.Add(vertexBufferStart + index1);
}

for (int l = 0; l < shape.Vertices.Length; l++)
{
var vertex = shape.Vertices[l].Position;
Vector3.Transform(ref vertex, ref finalMatrix, out Vector3 transformedVertex);
verts.Add(new(transformedVertex));
}
}
}

// Get the backing array of this list,
// get a span to that backing array,
var spanToPoints = CollectionsMarshal.AsSpan(verts);
// cast the type of span to read it as if it was a series of contiguous floats instead of contiguous vectors
var reinterpretedPoints = MemoryMarshal.Cast<VertexPosition3, float>(spanToPoints);
SimpleGeomProvider geom = new(reinterpretedPoints.ToArray(), [.. indices]);

return NavMeshBuilder.CreateNavMeshFromGeometry(navSettings, geom, threads, cancelToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using Stride.Engine;

namespace Stride.BepuPhysics.Navigation.Processors;
public class BepuStaticColliderTrackingProcessor : EntityProcessor<StaticComponent>
{
public delegate void CollectionChangedEventHandler(StaticComponent component);

public event CollectionChangedEventHandler ColliderAdded;
public event CollectionChangedEventHandler ColliderRemoved;

/// <inheritdoc />
protected override void OnEntityComponentAdding(Entity entity, StaticComponent component, StaticComponent data)
{
ColliderAdded?.Invoke(component);
}

/// <inheritdoc />
protected override void OnEntityComponentRemoved(Entity entity, StaticComponent component, StaticComponent data)
{
ColliderRemoved?.Invoke(component);
}
}

This file was deleted.

Loading