From 3d20020c506d2896708b3211de9b4f0db84f2b3f Mon Sep 17 00:00:00 2001 From: "nicogo.eth" Date: Tue, 3 Feb 2026 07:46:50 +0100 Subject: [PATCH 1/3] fix --- .../DebugRenderProcessor.cs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs index 427c0489a7..e471cf0c9b 100644 --- a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs +++ b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs @@ -36,7 +36,7 @@ public bool Visible get => _visible; set { - if (_sceneSystem.SceneInstance.GetProcessor() is { } proc) + if (_sceneSystem.SceneInstance.GetProcessor() is { } proc && _visibilityGroup is not null) { if (_visible == value) return; @@ -66,7 +66,7 @@ public bool Visible protected override void OnEntityComponentAdding(Entity entity, DebugRenderComponent component, DebugRenderComponent data) { base.OnEntityComponentAdding(entity, component, data); - if (_sceneSystem.SceneInstance.GetProcessor() is not null) + if (_sceneSystem?.SceneInstance?.GetProcessor() is not null && _visibilityGroup is not null) Visible = component.Visible; else if (component.Visible) _latent = true; @@ -76,19 +76,9 @@ protected override void OnEntityComponentAdding(Entity entity, DebugRenderCompon protected override void OnSystemAdd() { - SinglePassWireframeRenderFeature wireframeRenderFeature; - _shapeCacheSystem = Services.GetOrCreate(); _game = Services.GetSafeServiceAs(); _sceneSystem = Services.GetSafeServiceAs(); - - if (_sceneSystem.GraphicsCompositor.RenderFeatures.OfType().FirstOrDefault() is null) - { - wireframeRenderFeature = new(); - _sceneSystem.GraphicsCompositor.RenderFeatures.Add(wireframeRenderFeature); - } - - _visibilityGroup = _sceneSystem.SceneInstance.VisibilityGroups.First(); } protected override void OnSystemRemove() @@ -98,6 +88,18 @@ protected override void OnSystemRemove() public override void Draw(RenderContext context) { + if (_visibilityGroup is null) + { + if (_sceneSystem.SceneInstance.VisibilityGroups.Count == 0) + return; + + _visibilityGroup = _sceneSystem.SceneInstance.VisibilityGroups.First(); + if (_sceneSystem.GraphicsCompositor.RenderFeatures.OfType().FirstOrDefault() is null) + { + _sceneSystem.GraphicsCompositor.RenderFeatures.Add(new SinglePassWireframeRenderFeature()); + } + } + if (_latent) { Visible = true; From b843a9db9d9a9a7a465e50dd96dde478eca117a8 Mon Sep 17 00:00:00 2001 From: "nicogo.eth" Date: Tue, 3 Feb 2026 17:51:15 +0100 Subject: [PATCH 2/3] Add contacts --- .../DebugRenderComponent.cs | 20 ++- .../DebugRenderProcessor.cs | 114 +++++++++++++++++- .../Contacts/ContactEventsManager.cs | 73 ++++++++++- 3 files changed, 200 insertions(+), 7 deletions(-) diff --git a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderComponent.cs b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderComponent.cs index ed77314830..d2f2616868 100644 --- a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderComponent.cs +++ b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderComponent.cs @@ -5,6 +5,7 @@ using Stride.Engine; using Stride.Engine.Design; using Stride.Input; +using static Stride.BepuPhysics.Debug.DebugRenderProcessor; namespace Stride.BepuPhysics.Debug; @@ -14,21 +15,34 @@ namespace Stride.BepuPhysics.Debug; public class DebugRenderComponent : SyncScript { internal DebugRenderProcessor? _processor; - bool _state = true; + bool _visibleState = true; + SynchronizationMode _modeState = SynchronizationMode.Physics; public Keys Key { get; set; } = Keys.F11; [DataMember] public bool Visible { - get => _processor?.Visible ?? _state; + get => _processor?.Visible ?? _visibleState; set { - _state = value; + _visibleState = value; if (_processor is not null) _processor.Visible = value; } } + [DataMember] + public SynchronizationMode Mode + { + get => _processor?.Mode ?? _modeState; + set + { + _modeState = value; + if (_processor is not null) + _processor.Mode = value; + } + } + public override void Update() { diff --git a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs index e471cf0c9b..1b30d844d0 100644 --- a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs +++ b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs @@ -1,6 +1,8 @@ // 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 BepuPhysics.Collidables; +using SharpFont; using Stride.BepuPhysics.Debug.Effects; using Stride.BepuPhysics.Debug.Effects.RenderFeatures; using Stride.BepuPhysics.Definitions; @@ -17,6 +19,7 @@ namespace Stride.BepuPhysics.Debug; public class DebugRenderProcessor : EntityProcessor { public SynchronizationMode Mode { get; set; } = SynchronizationMode.Physics; // Setting it to Physics by default to show when there is a large discrepancy between the entity and physics + public bool ShowCollisions { get; set; } = true; private bool _latent; private bool _visible; @@ -25,6 +28,7 @@ public class DebugRenderProcessor : EntityProcessor private ShapeCacheSystem _shapeCacheSystem = null!; private VisibilityGroup _visibilityGroup = null!; private readonly Dictionary _wireFrameRenderObject = new(); + private readonly List _wireFrameRenderObjectCollisions = new(); public DebugRenderProcessor() { @@ -70,7 +74,7 @@ protected override void OnEntityComponentAdding(Entity entity, DebugRenderCompon Visible = component.Visible; else if (component.Visible) _latent = true; - + Mode = component.Mode; component._processor = this; } @@ -108,9 +112,13 @@ public override void Draw(RenderContext context) } base.Draw(context); + var simulations = new List(); foreach (var (collidable, (wireframes, cache)) in _wireFrameRenderObject) { + if (collidable.Simulation != null && !simulations.Contains(collidable.Simulation)) + simulations.Add(collidable.Simulation); + Matrix matrix; switch (Mode) { @@ -144,6 +152,110 @@ public override void Draw(RenderContext context) wireframe.Color = GetCurrentColor(collidable); } } + + foreach (var collisionWireframe in _wireFrameRenderObjectCollisions) + { + collisionWireframe.Dispose(); + _visibilityGroup.RenderObjects.Remove(collisionWireframe); + } + _wireFrameRenderObjectCollisions.Clear(); + + foreach (var sim in simulations) + { + sim.ContactEvents.DebugCollectAllContacts = ShowCollisions; + + var points = sim.ContactEvents.DebugPoints; + for (int i = 0; i < points.Length; i++) + { + var p = points[i]; + + // ------------------------- + // 1) Point de contact (sphère) + // ------------------------- + { + var w = WireFrameRenderObject.New( + _game.GraphicsDevice, + _shapeCacheSystem._sphereShapeData.Indices, + _shapeCacheSystem._sphereShapeData.Vertices); + + w.Color = Color.Red; + + var scale = new Vector3(0.05f); + Matrix.Scaling(ref scale, out w.CollidableBaseMatrix); + + Matrix world; + var wpos = p.WorldPoint; + Matrix.Translation(ref wpos, out world); + + w.WorldMatrix = w.CollidableBaseMatrix * world; + + _wireFrameRenderObjectCollisions.Add(w); + _visibilityGroup.RenderObjects.Add(w); + } + + // ------------------------- + // 2) Normale (cylindre = tige) + // + petite sphère au bout = "pointe" + // ------------------------- + { + // Paramètres visuels + float normalLength = 0.35f; // longueur de la normale + float shaftRadius = 0.02f; // rayon du cylindre + float tipRadius = 0.035f; // rayon de la pointe (sphère) + + var n = p.WorldNormal; + if (n.LengthSquared() < 1e-6f) + continue; + + n.Normalize(); + + var start = p.WorldPoint; + var end = start + n * normalLength; + var mid = (start + end) * 0.5f; + + // Rotation : aligner l'axe Y du cylindre sur la normale + // (le Cylinder.New(...) est généralement aligné sur Y dans Stride) + var rot = Quaternion.BetweenDirections(Vector3.UnitY, n); + + // ---- tige (cylindre) ---- + var shaft = WireFrameRenderObject.New( + _game.GraphicsDevice, + _shapeCacheSystem._cylinderShapeData.Indices, + _shapeCacheSystem._cylinderShapeData.Vertices); + + shaft.Color = Color.Yellow; + + // Cylinder.New(1,1,8) => hauteur ~ 1 autour de Y. + // On scale Y = normalLength, XZ = rayon + var shaftScale = new Vector3(shaftRadius, normalLength, shaftRadius); + Matrix.Transformation(ref shaftScale, ref rot, ref mid, out shaft.CollidableBaseMatrix); + + // Ici on a directement construit une matrice monde dans CollidableBaseMatrix, + // donc WorldMatrix = CollidableBaseMatrix et world = Identity. + shaft.WorldMatrix = shaft.CollidableBaseMatrix; + + _wireFrameRenderObjectCollisions.Add(shaft); + _visibilityGroup.RenderObjects.Add(shaft); + + // ---- pointe (petite sphère au bout) ---- + var tip = WireFrameRenderObject.New( + _game.GraphicsDevice, + _shapeCacheSystem._sphereShapeData.Indices, + _shapeCacheSystem._sphereShapeData.Vertices); + + tip.Color = Color.Yellow; + + var tipScale = new Vector3(tipRadius); + Matrix.Transformation(ref tipScale, ref rot, ref end, out tip.CollidableBaseMatrix); + tip.WorldMatrix = tip.CollidableBaseMatrix; + + _wireFrameRenderObjectCollisions.Add(tip); + _visibilityGroup.RenderObjects.Add(tip); + } + } + } + + } private void StartTracking(CollidableProcessor proc) diff --git a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs index dcd5adaddb..23c366b5b5 100644 --- a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs +++ b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs @@ -25,7 +25,10 @@ internal class ContactEventsManager : IDisposable private IndexSet _staticListenerFlags; private IndexSet _bodyListenerFlags; private IPerTypeManifoldStore[][] _manifoldStoresPerWorker; - + private readonly List[] _debugPointsPerWorker; + private readonly List _debugPointsMerged = new(256); + internal bool DebugCollectAllContacts; + internal ReadOnlySpan DebugPoints => CollectionsMarshal.AsSpan(_debugPointsMerged); public ContactEventsManager(BufferPool pool, BepuSimulation simulation, int workerCount) { _pool = pool; @@ -33,6 +36,9 @@ public ContactEventsManager(BufferPool pool, BepuSimulation simulation, int work _manifoldStoresPerWorker = new IPerTypeManifoldStore[workerCount][]; for (int i = 0; i < _manifoldStoresPerWorker.Length; i++) _manifoldStoresPerWorker[i] = []; + _debugPointsPerWorker = new List[workerCount]; + for (int i = 0; i < workerCount; i++) + _debugPointsPerWorker[i] = new List(128); } public void Initialize() @@ -163,10 +169,52 @@ public void StoreManifold(int workerIndex, CollidablePair pair, int c { bool aListener = IsRegistered(pair.A); bool bListener = IsRegistered(pair.B); - if (aListener == false && bListener == false) + if (aListener == false && bListener == false && !DebugCollectAllContacts) return; - IPerTypeManifoldStore.StoreManifold(_manifoldStoresPerWorker, workerIndex, ref manifold, pair, childIndexA, childIndexB); + if (aListener || bListener) + IPerTypeManifoldStore.StoreManifold(_manifoldStoresPerWorker, workerIndex, ref manifold, pair, childIndexA, childIndexB); + + CollectDebugContacts(workerIndex, pair, ref manifold); + } + private void CollectDebugContacts(int workerIndex, CollidablePair pair, ref TManifold manifold) + where TManifold : unmanaged, IContactManifold + { + var compA = _simulation.GetComponent(pair.A); + if (compA.Pose is not { } poseA) + return; + + var worldRotStride = poseA.Orientation.ToStride(); + var worldOriginStride = poseA.Position.ToStride(); + + for (int j = 0; j < manifold.Count; j++) + { + float depth = manifold.GetDepth(j); + if (depth < 0) + continue; + + var offsetN = manifold.GetOffset(j); + var normalN = manifold.GetNormal(j); + + var offsetStride = offsetN.ToStride(); + var normalStride = normalN.ToStride(); + + // Point monde: origin + rotate(offset) + var worldPointStride = worldOriginStride + offsetStride; + + // Normal monde: rotate(normal) + var worldNormalStride = Vector3.Transform(normalStride, worldRotStride); + + _debugPointsPerWorker[workerIndex].Add(new DebugContactPoint + { + WorldPoint = worldPointStride, + WorldNormal = worldNormalStride, + Depth = depth, + PackedA = pair.A.Packed, + PackedB = pair.B.Packed + }); + } + } private void RunManifoldEvent(Span> unsafeInfos) where TManifold : unmanaged, IContactManifold @@ -283,6 +331,17 @@ public void Flush() //Remove any stale collisions. Stale collisions are those which should have received a new manifold update but did not because the manifold is no longer active. foreach (var pair in _outdatedPairs) ClearCollision(pair); + + _debugPointsMerged.Clear(); + for (int i = 0; i < _debugPointsPerWorker.Length; i++) + { + var list = _debugPointsPerWorker[i]; + if (list.Count > 0) + { + _debugPointsMerged.AddRange(list); + list.Clear(); + } + } } /// @@ -445,6 +504,14 @@ private enum Events TouchingB = 0b10, } + internal struct DebugContactPoint + { + public Stride.Core.Mathematics.Vector3 WorldPoint; + public Stride.Core.Mathematics.Vector3 WorldNormal; + public float Depth; + public uint PackedA; + public uint PackedB; + } private struct EmptyManifold : IContactManifold { From aede655a401e56a75fa345ee91e983d71b3c330d Mon Sep 17 00:00:00 2001 From: "nicogo.eth" Date: Tue, 3 Feb 2026 18:22:32 +0100 Subject: [PATCH 3/3] add contact debug render --- .../DebugRenderProcessor.cs | 260 ++++++++++++------ .../Stride.BepuPhysics/CharacterComponent.cs | 2 +- .../Contacts/ContactEventsManager.cs | 6 +- 3 files changed, 182 insertions(+), 86 deletions(-) diff --git a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs index 1b30d844d0..f9728ec999 100644 --- a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs +++ b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics.Debug/DebugRenderProcessor.cs @@ -2,7 +2,6 @@ // Distributed under the MIT license. See the LICENSE.md file in the project root for more information. using BepuPhysics.Collidables; -using SharpFont; using Stride.BepuPhysics.Debug.Effects; using Stride.BepuPhysics.Debug.Effects.RenderFeatures; using Stride.BepuPhysics.Definitions; @@ -28,7 +27,43 @@ public class DebugRenderProcessor : EntityProcessor private ShapeCacheSystem _shapeCacheSystem = null!; private VisibilityGroup _visibilityGroup = null!; private readonly Dictionary _wireFrameRenderObject = new(); - private readonly List _wireFrameRenderObjectCollisions = new(); + + // Collision gizmo pooling: + private readonly List _collisionGizmos = new(); + private int _collisionGizmosUsedThisFrame; + + private sealed class CollisionGizmo + { + public WireFrameRenderObject Point = null!; + public WireFrameRenderObject Shaft = null!; + public WireFrameRenderObject Tip = null!; + + public void SetVisible(bool visible, VisibilityGroup visibilityGroup) + { + if (visible && !Point.Enabled) + { + visibilityGroup.RenderObjects.Add(Point); + visibilityGroup.RenderObjects.Add(Shaft); + visibilityGroup.RenderObjects.Add(Tip); + } + else if (!visible && Point.Enabled) + { + visibilityGroup.RenderObjects.Remove(Point); + visibilityGroup.RenderObjects.Remove(Shaft); + visibilityGroup.RenderObjects.Remove(Tip); + } + Point.Enabled = visible; + Shaft.Enabled = visible; + Tip.Enabled = visible; + } + + public void Dispose() + { + Point.Dispose(); + Shaft.Dispose(); + Tip.Dispose(); + } + } public DebugRenderProcessor() { @@ -112,9 +147,10 @@ public override void Draw(RenderContext context) } base.Draw(context); - var simulations = new List(); - foreach (var (collidable, (wireframes, cache)) in _wireFrameRenderObject) + // Collect sims that have at least one tracked collidable. + var simulations = new List(); + foreach (var (collidable, (wireframes, _)) in _wireFrameRenderObject) { if (collidable.Simulation != null && !simulations.Contains(collidable.Simulation)) simulations.Add(collidable.Simulation); @@ -153,118 +189,102 @@ public override void Draw(RenderContext context) } } - foreach (var collisionWireframe in _wireFrameRenderObjectCollisions) + // Collisions rendering (pooled) + if (!ShowCollisions) { - collisionWireframe.Dispose(); - _visibilityGroup.RenderObjects.Remove(collisionWireframe); + // Ensure physics doesn't waste time collecting. + for (int s = 0; s < simulations.Count; s++) + simulations[s].ContactEvents.DebugCollectAllContacts = false; + + HideAllCollisionGizmos(); + return; } - _wireFrameRenderObjectCollisions.Clear(); - foreach (var sim in simulations) + _collisionGizmosUsedThisFrame = 0; + + for (int s = 0; s < simulations.Count; s++) { - sim.ContactEvents.DebugCollectAllContacts = ShowCollisions; + var sim = simulations[s]; + sim.ContactEvents.DebugCollectAllContacts = true; var points = sim.ContactEvents.DebugPoints; + if (points.Length == 0) + continue; + + EnsureCollisionGizmoCapacity(_collisionGizmosUsedThisFrame + points.Length); + for (int i = 0; i < points.Length; i++) { var p = points[i]; - // ------------------------- - // 1) Point de contact (sphère) - // ------------------------- - { - var w = WireFrameRenderObject.New( - _game.GraphicsDevice, - _shapeCacheSystem._sphereShapeData.Indices, - _shapeCacheSystem._sphereShapeData.Vertices); + // Visual parameters + float pointRadius = 0.05f; + float normalLength = 0.35f; + float shaftRadius = 0.02f; + float tipRadius = 0.035f; - w.Color = Color.Red; + var n = p.WorldNormal; + if (n.LengthSquared() < 1e-6f) + continue; - var scale = new Vector3(0.05f); - Matrix.Scaling(ref scale, out w.CollidableBaseMatrix); + n.Normalize(); - Matrix world; - var wpos = p.WorldPoint; - Matrix.Translation(ref wpos, out world); + var start = p.WorldPoint; + var end = start + n * normalLength; + var mid = (start + end) * 0.5f; - w.WorldMatrix = w.CollidableBaseMatrix * world; + // Align cylinder Y axis to normal + var rot = Quaternion.BetweenDirections(Vector3.UnitY, n); - _wireFrameRenderObjectCollisions.Add(w); - _visibilityGroup.RenderObjects.Add(w); - } + var gizmo = _collisionGizmos[_collisionGizmosUsedThisFrame++]; - // ------------------------- - // 2) Normale (cylindre = tige) - // + petite sphère au bout = "pointe" - // ------------------------- + // 1) contact point sphere { - // Paramètres visuels - float normalLength = 0.35f; // longueur de la normale - float shaftRadius = 0.02f; // rayon du cylindre - float tipRadius = 0.035f; // rayon de la pointe (sphère) + gizmo.Point.Color = Color.Red; - var n = p.WorldNormal; - if (n.LengthSquared() < 1e-6f) - continue; - - n.Normalize(); + var scale = new Vector3(pointRadius); + Matrix.Scaling(ref scale, out gizmo.Point.CollidableBaseMatrix); - var start = p.WorldPoint; - var end = start + n * normalLength; - var mid = (start + end) * 0.5f; - - // Rotation : aligner l'axe Y du cylindre sur la normale - // (le Cylinder.New(...) est généralement aligné sur Y dans Stride) - var rot = Quaternion.BetweenDirections(Vector3.UnitY, n); + Matrix world; + Matrix.Translation(ref start, out world); - // ---- tige (cylindre) ---- - var shaft = WireFrameRenderObject.New( - _game.GraphicsDevice, - _shapeCacheSystem._cylinderShapeData.Indices, - _shapeCacheSystem._cylinderShapeData.Vertices); + gizmo.Point.WorldMatrix = gizmo.Point.CollidableBaseMatrix * world; + } - shaft.Color = Color.Yellow; + // 2) normal shaft (cylinder) + { + gizmo.Shaft.Color = Color.Yellow; - // Cylinder.New(1,1,8) => hauteur ~ 1 autour de Y. - // On scale Y = normalLength, XZ = rayon var shaftScale = new Vector3(shaftRadius, normalLength, shaftRadius); - Matrix.Transformation(ref shaftScale, ref rot, ref mid, out shaft.CollidableBaseMatrix); - - // Ici on a directement construit une matrice monde dans CollidableBaseMatrix, - // donc WorldMatrix = CollidableBaseMatrix et world = Identity. - shaft.WorldMatrix = shaft.CollidableBaseMatrix; - - _wireFrameRenderObjectCollisions.Add(shaft); - _visibilityGroup.RenderObjects.Add(shaft); - // ---- pointe (petite sphère au bout) ---- - var tip = WireFrameRenderObject.New( - _game.GraphicsDevice, - _shapeCacheSystem._sphereShapeData.Indices, - _shapeCacheSystem._sphereShapeData.Vertices); + // WorldMatrix directly + Matrix.Transformation(ref shaftScale, ref rot, ref mid, out gizmo.Shaft.WorldMatrix); + gizmo.Shaft.CollidableBaseMatrix = gizmo.Shaft.WorldMatrix; + } - tip.Color = Color.Yellow; + // 3) normal tip (sphere) + { + gizmo.Tip.Color = Color.Yellow; var tipScale = new Vector3(tipRadius); - Matrix.Transformation(ref tipScale, ref rot, ref end, out tip.CollidableBaseMatrix); - tip.WorldMatrix = tip.CollidableBaseMatrix; - - _wireFrameRenderObjectCollisions.Add(tip); - _visibilityGroup.RenderObjects.Add(tip); + Matrix.Transformation(ref tipScale, ref rot, ref end, out gizmo.Tip.WorldMatrix); + gizmo.Tip.CollidableBaseMatrix = gizmo.Tip.WorldMatrix; } + + gizmo.SetVisible(true, _visibilityGroup); } } - + // Hide unused + for (int i = _collisionGizmosUsedThisFrame; i < _collisionGizmos.Count; i++) + _collisionGizmos[i].SetVisible(false, _visibilityGroup); } private void StartTracking(CollidableProcessor proc) { var shapeAndOffsets = new List(); for (var collidables = proc.ComponentDataEnumerator; collidables.MoveNext();) - { StartTrackingCollidable(collidables.Current.Key, shapeAndOffsets); - } } private void StartTrackingCollidable(CollidableComponent collidable) => StartTrackingCollidable(collidable, new()); @@ -291,10 +311,11 @@ private void StartTrackingCollidable(CollidableComponent collidable, List, /// and 1 would return true only when a surface matches exactly. /// - protected bool GroundTest(NVector3 groundNormal, float threshold = 0f) + protected bool GroundTest(NVector3 groundNormal, float threshold = 0.1f) { IsGrounded = false; if (Simulation == null || Contacts.Count == 0) diff --git a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs index 23c366b5b5..976d3302a1 100644 --- a/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs +++ b/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs @@ -199,11 +199,9 @@ private void CollectDebugContacts(int workerIndex, CollidablePair pai var offsetStride = offsetN.ToStride(); var normalStride = normalN.ToStride(); - // Point monde: origin + rotate(offset) - var worldPointStride = worldOriginStride + offsetStride; + var worldPointStride = worldOriginStride + offsetStride; - // Normal monde: rotate(normal) - var worldNormalStride = Vector3.Transform(normalStride, worldRotStride); + var worldNormalStride = normalStride;// Vector3.Transform(normalStride, worldRotStride); _debugPointsPerWorker[workerIndex].Add(new DebugContactPoint {