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 1 commit 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
40 changes: 37 additions & 3 deletions build/Stride.sln
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.BepuPhysics.Debug",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.3D", "..\sources\tools\Stride.Importer.3D\Stride.Importer.3D.csproj", "{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stride.BepuPhysics.Tests", "..\sources\engine\Stride.BepuPhysics\Stride.BepuPhysics.Tests\Stride.BepuPhysics.Tests.csproj", "{7B70C783-4085-4702-B3C6-6570FD85CB8F}"
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
Expand Down Expand Up @@ -1515,12 +1519,40 @@ Global
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Win32.Build.0 = Release|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Any CPU.Build.0 = Release|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Debug|Win32.ActiveCfg = Debug|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Debug|Win32.Build.0 = Debug|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Any CPU.Build.0 = Release|Any CPU
{7B70C783-4085-4702-B3C6-6570FD85CB8F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{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 @@ -1651,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
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,18 @@
// 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 Stride.DotRecast.Definitions;

namespace Stride.BepuPhysics.Navigation.Definitions;

[DataContract]
public class BepuNavMeshInfo
{
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;
}
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);
}
}
Loading