aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules
diff options
context:
space:
mode:
authorUbitUmarov2017-09-05 20:25:12 +0100
committerUbitUmarov2017-09-05 20:25:12 +0100
commitca493a1bebfe544c31883fc8796ce1d05a4ed181 (patch)
treecb5583832fd78bae24ebb9e04559d9eb5bade896 /OpenSim/Region/PhysicsModules
parentMerge branch 'master' into httptests (diff)
parentBulletSim: Merge branch 'BulletSim2017' (diff)
downloadopensim-SC-ca493a1bebfe544c31883fc8796ce1d05a4ed181.zip
opensim-SC-ca493a1bebfe544c31883fc8796ce1d05a4ed181.tar.gz
opensim-SC-ca493a1bebfe544c31883fc8796ce1d05a4ed181.tar.bz2
opensim-SC-ca493a1bebfe544c31883fc8796ce1d05a4ed181.tar.xz
Merge branch 'master' into httptests
Diffstat (limited to 'OpenSim/Region/PhysicsModules')
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs22
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs8
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs21
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs5
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs1
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSParam.cs11
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs2
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs1
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSScene.cs298
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs6
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs1
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/Tests/Raycast.cs124
12 files changed, 414 insertions, 86 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
index 42db7fe..840e453 100755
--- a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
@@ -1405,6 +1405,19 @@ public override float GetMargin(BulletShape shape)
1405} 1405}
1406 1406
1407// ===================================================================================== 1407// =====================================================================================
1408// Raycast
1409public override SweepHit ConvexSweepTest2(BulletWorld world, BulletBody sweepObject, Vector3 from, Vector3 to, float margin) {
1410 BulletWorldUnman worldu = world as BulletWorldUnman;
1411 BulletBodyUnman bodyu = sweepObject as BulletBodyUnman;
1412 return BSAPICPP.ConvexSweepTest2(worldu.ptr, bodyu.ptr, from, to, margin);
1413}
1414
1415public override RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask) {
1416 BulletWorldUnman worldu = world as BulletWorldUnman;
1417 return BSAPICPP.RayTest2(worldu.ptr, from, to, filterGroup, filterMask);
1418}
1419
1420// =====================================================================================
1408// Debugging 1421// Debugging
1409public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject) 1422public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
1410{ 1423{
@@ -2084,6 +2097,15 @@ public static extern void SetMargin2(IntPtr shape, float val);
2084[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 2097[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2085public static extern float GetMargin2(IntPtr shape); 2098public static extern float GetMargin2(IntPtr shape);
2086 2099
2100
2101// =====================================================================================
2102// Raycast
2103[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2104public static extern SweepHit ConvexSweepTest2(IntPtr sim, IntPtr obj, Vector3 from, Vector3 to, float margin);
2105
2106[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2107public static extern RaycastHit RayTest2(IntPtr sim, Vector3 from, Vector3 to, uint filterGroup, uint filterMask);
2108
2087// ===================================================================================== 2109// =====================================================================================
2088// Debugging 2110// Debugging
2089[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 2111[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
index 37017b0..7d58728 100755
--- a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
@@ -2459,6 +2459,14 @@ private sealed class BulletConstraintXNA : BulletConstraint
2459 } 2459 }
2460 return false; 2460 return false;
2461 } 2461 }
2462
2463 public override SweepHit ConvexSweepTest2(BulletWorld world, BulletBody obj, Vector3 from, Vector3 to, float margin) {
2464 return new SweepHit();
2465 }
2466
2467 public override RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask) {
2468 return new RaycastHit();
2469 }
2462} 2470}
2463 2471
2464 2472
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
index 816189f..a288048 100644
--- a/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
@@ -121,6 +121,14 @@ public struct SweepHit
121 public float Fraction; 121 public float Fraction;
122 public Vector3 Normal; 122 public Vector3 Normal;
123 public Vector3 Point; 123 public Vector3 Point;
124
125 public bool hasHit()
126 {
127 float sum = Fraction
128 + Normal.X + Normal.Y + Normal.Z
129 + Point.X + Point.Y + Point.Z;
130 return (sum != 0) || (ID != 0);
131 }
124} 132}
125[StructLayout(LayoutKind.Sequential)] 133[StructLayout(LayoutKind.Sequential)]
126public struct RaycastHit 134public struct RaycastHit
@@ -128,6 +136,13 @@ public struct RaycastHit
128 public UInt32 ID; 136 public UInt32 ID;
129 public float Fraction; 137 public float Fraction;
130 public Vector3 Normal; 138 public Vector3 Normal;
139 public Vector3 Point;
140
141 public bool hasHit()
142 {
143 float sum = Normal.X + Normal.Y + Normal.Z + Point.X + Point.Y + Point.Z;
144 return (sum != 0);
145 }
131} 146}
132[StructLayout(LayoutKind.Sequential)] 147[StructLayout(LayoutKind.Sequential)]
133public struct CollisionDesc 148public struct CollisionDesc
@@ -742,6 +757,12 @@ public abstract void SetMargin(BulletShape shape, float val);
742public abstract float GetMargin(BulletShape shape); 757public abstract float GetMargin(BulletShape shape);
743 758
744// ===================================================================================== 759// =====================================================================================
760// Raycast
761public abstract SweepHit ConvexSweepTest2(BulletWorld world, BulletBody obj, Vector3 from, Vector3 to, float margin);
762
763public abstract RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask);
764
765// =====================================================================================
745// Debugging 766// Debugging
746public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { } 767public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
747 768
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
index 57f03fb..7faee70 100644
--- a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
@@ -496,8 +496,7 @@ public sealed class BSCharacter : BSPhysObject
496 public override OMV.Vector3 ForceVelocity { 496 public override OMV.Vector3 ForceVelocity {
497 get { return RawVelocity; } 497 get { return RawVelocity; }
498 set { 498 set {
499 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); 499 DetailLog("{0},BSCharacter.ForceVelocity.set={1}", LocalID, value);
500 DetailLog("{0}: BSCharacter.ForceVelocity.set = {1}", LocalID, value);
501 500
502 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); 501 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
503 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); 502 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
@@ -638,8 +637,6 @@ public sealed class BSCharacter : BSPhysObject
638 public override float ForceBuoyancy { 637 public override float ForceBuoyancy {
639 get { return _buoyancy; } 638 get { return _buoyancy; }
640 set { 639 set {
641 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
642
643 _buoyancy = value; 640 _buoyancy = value;
644 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 641 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
645 // Buoyancy is faked by changing the gravity applied to the object 642 // Buoyancy is faked by changing the gravity applied to the object
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
index 953ddee..dc390b2 100755
--- a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
@@ -450,6 +450,7 @@ public sealed class BSLinksetCompound : BSLinkset
450 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); 450 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
451 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", 451 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
452 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); 452 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
453 m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World); // DEBUG DEBUG
453 454
454 // With all of the linkset packed into the root prim, it has the mass of everyone. 455 // With all of the linkset packed into the root prim, it has the mass of everyone.
455 LinksetMass = ComputeLinksetMass(); 456 LinksetMass = ComputeLinksetMass();
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
index 352c03e..fcda92c 100755
--- a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
@@ -230,6 +230,8 @@ public static class BSParam
230 public static float LinkConstraintCFM { get; private set; } 230 public static float LinkConstraintCFM { get; private set; }
231 public static float LinkConstraintSolverIterations { get; private set; } 231 public static float LinkConstraintSolverIterations { get; private set; }
232 232
233 public static bool UseBulletRaycast { get; private set; }
234
233 public static float PID_D { get; private set; } // derivative 235 public static float PID_D { get; private set; } // derivative
234 public static float PID_P { get; private set; } // proportional 236 public static float PID_P { get; private set; } // proportional
235 237
@@ -823,6 +825,9 @@ public static class BSParam
823 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", 825 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
824 40 ), 826 40 ),
825 827
828 new ParameterDefn<bool>("UseBulletRaycast", "If 'true', use the raycast function of the Bullet physics engine",
829 true ),
830
826 new ParameterDefn<float>("DebugNumber", "A console setable number sometimes used for debugging", 831 new ParameterDefn<float>("DebugNumber", "A console setable number sometimes used for debugging",
827 1.0f ), 832 1.0f ),
828 833
@@ -833,7 +838,7 @@ public static class BSParam
833 new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", 838 new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
834 0f, 839 0f,
835 (s) => { return 0f; }, 840 (s) => { return 0f; },
836 (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ), 841 (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ),
837 new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver", 842 new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
838 0f, 843 0f,
839 (s) => { return 0f; }, 844 (s) => { return 0f; },
@@ -919,10 +924,10 @@ public static class BSParam
919 // ===================================================================== 924 // =====================================================================
920 // There are parameters that, when set, cause things to happen in the physics engine. 925 // There are parameters that, when set, cause things to happen in the physics engine.
921 // This causes the broadphase collision cache to be cleared. 926 // This causes the broadphase collision cache to be cleared.
922 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime) 927 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v)
923 { 928 {
924 BSScene physScene = pPhysScene; 929 BSScene physScene = pPhysScene;
925 physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate() 930 physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetBroadphasePoolTainted", delegate()
926 { 931 {
927 physScene.PE.ResetBroadphasePool(physScene.World); 932 physScene.PE.ResetBroadphasePool(physScene.World);
928 }); 933 });
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
index b153761..f085d70 100644
--- a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
@@ -790,8 +790,6 @@ public class BSPrim : BSPhysObject
790 public override OMV.Vector3 ForceVelocity { 790 public override OMV.Vector3 ForceVelocity {
791 get { return RawVelocity; } 791 get { return RawVelocity; }
792 set { 792 set {
793 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
794
795 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); 793 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
796 if (PhysBody.HasPhysicalBody) 794 if (PhysBody.HasPhysicalBody)
797 { 795 {
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
index d8ed56b..3f90fc5 100755
--- a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
@@ -81,7 +81,6 @@ public class BSPrimDisplaced : BSPrim
81 // Called at taint time. 81 // Called at taint time.
82 public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) 82 public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement)
83 { 83 {
84 PhysScene.AssertInTaintTime("BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement");
85 Vector3 comDisp; 84 Vector3 comDisp;
86 if (UserSetCenterOfMassDisplacement.HasValue) 85 if (UserSetCenterOfMassDisplacement.HasValue)
87 comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; 86 comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement;
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
index 7ff0a07..163efaa 100644
--- a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
@@ -124,9 +124,10 @@ namespace OpenSim.Region.PhysicsModule.BulletS
124 // True if initialized and ready to do simulation steps 124 // True if initialized and ready to do simulation steps
125 private bool m_initialized = false; 125 private bool m_initialized = false;
126 126
127 // Flag which is true when processing taints. 127 // Object locked whenever execution is inside the physics engine
128 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. 128 public Object PhysicsEngineLock = new object();
129 public bool InTaintTime { get; private set; } 129 // Flag that is true when the simulator is active and shouldn't be touched
130 public bool InSimulationTime { get; private set; }
130 131
131 // Pinned memory used to pass step information between managed and unmanaged 132 // Pinned memory used to pass step information between managed and unmanaged
132 internal int m_maxCollisionsPerFrame; 133 internal int m_maxCollisionsPerFrame;
@@ -344,7 +345,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
344 // Put some informational messages into the log file. 345 // Put some informational messages into the log file.
345 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); 346 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
346 347
347 InTaintTime = false; 348 InSimulationTime = false;
348 m_initialized = true; 349 m_initialized = true;
349 350
350 // If the physics engine runs on its own thread, start same. 351 // If the physics engine runs on its own thread, start same.
@@ -657,48 +658,57 @@ namespace OpenSim.Region.PhysicsModule.BulletS
657 658
658 int beforeTime = Util.EnvironmentTickCount(); 659 int beforeTime = Util.EnvironmentTickCount();
659 int simTime = 0; 660 int simTime = 0;
661 int numTaints = 0;
662 int numSubSteps = 0;
660 663
661 int numTaints = _taintOperations.Count; 664 lock (PhysicsEngineLock)
662 InTaintTime = true; // Only used for debugging so locking is not necessary. 665 {
666 InSimulationTime = true;
667 // update the prim states while we know the physics engine is not busy
668 numTaints += ProcessTaints();
663 669
664 // update the prim states while we know the physics engine is not busy 670 // Some of the physical objects requre individual, pre-step calls
665 ProcessTaints(); 671 // (vehicles and avatar movement, in particular)
672 TriggerPreStepEvent(timeStep);
666 673
667 // Some of the physical objects requre individual, pre-step calls 674 // the prestep actions might have added taints
668 // (vehicles and avatar movement, in particular) 675 numTaints += ProcessTaints();
669 TriggerPreStepEvent(timeStep);
670 676
671 // the prestep actions might have added taints 677 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
672 numTaints += _taintOperations.Count; 678 // Only enable this in a limited test world with few objects.
673 ProcessTaints(); 679 if (m_physicsPhysicalDumpEnabled)
680 PE.DumpAllInfo(World);
674 681
675 InTaintTime = false; // Only used for debugging so locking is not necessary. 682 // step the physical world one interval
683 m_simulationStep++;
684 try
685 {
686 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
687 }
688 catch (Exception e)
689 {
690 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
691 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
692 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
693 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
694 updatedEntityCount = 0;
695 collidersCount = 0;
696 }
676 697
677 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. 698 // Make the physics engine dump useful statistics periodically
678 // Only enable this in a limited test world with few objects. 699 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
679 if (m_physicsPhysicalDumpEnabled) 700 PE.DumpPhysicsStatistics(World);
680 PE.DumpAllInfo(World);
681 701
682 // step the physical world one interval 702 InSimulationTime = false;
683 m_simulationStep++; 703
684 int numSubSteps = 0; 704 // Some actors want to know when the simulation step is complete.
685 try 705 TriggerPostStepEvent(timeStep);
686 { 706
687 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); 707 // In case there were any parameter updates that happened during the simulation step
688 } 708 numTaints += ProcessTaints();
689 catch (Exception e)
690 {
691 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
692 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
693 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
694 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
695 updatedEntityCount = 0;
696 collidersCount = 0;
697 }
698 709
699 // Make the physics engine dump useful statistics periodically 710 InSimulationTime = false;
700 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) 711 }
701 PE.DumpPhysicsStatistics(World);
702 712
703 // Get a value for 'now' so all the collision and update routines don't have to get their own. 713 // Get a value for 'now' so all the collision and update routines don't have to get their own.
704 SimulationNowTime = Util.EnvironmentTickCount(); 714 SimulationNowTime = Util.EnvironmentTickCount();
@@ -748,9 +758,6 @@ namespace OpenSim.Region.PhysicsModule.BulletS
748 } 758 }
749 } 759 }
750 760
751 // Some actors want to know when the simulation step is complete.
752 TriggerPostStepEvent(timeStep);
753
754 simTime = Util.EnvironmentTickCountSubtract(beforeTime); 761 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
755 if (PhysicsLogging.Enabled) 762 if (PhysicsLogging.Enabled)
756 { 763 {
@@ -956,6 +963,149 @@ namespace OpenSim.Region.PhysicsModule.BulletS
956 963
957 #endregion // Terrain 964 #endregion // Terrain
958 965
966 #region Raycast
967
968 public override bool SupportsRayCast()
969 {
970 return BSParam.UseBulletRaycast;
971 }
972
973 public override bool SupportsRaycastWorldFiltered()
974 {
975 return BSParam.UseBulletRaycast;
976 }
977
978
979 /// <summary>
980 /// Queue a raycast against the physics scene.
981 /// The provided callback method will be called when the raycast is complete
982 ///
983 /// Many physics engines don't support collision testing at the same time as
984 /// manipulating the physics scene, so we queue the request up and callback
985 /// a custom method when the raycast is complete.
986 /// This allows physics engines that give an immediate result to callback immediately
987 /// and ones that don't, to callback when it gets a result back.
988 /// public delegate void RayCallback(List<ContactResult> list);
989 ///
990 /// ODE for example will not allow you to change the scene while collision testing or
991 /// it asserts, 'opteration not valid for locked space'. This includes adding a ray to the scene.
992 ///
993 /// This is named RayCastWorld to not conflict with modrex's Raycast method.
994 /// </summary>
995 /// <param name="position">Origin of the ray</param>
996 /// <param name="direction">Direction of the ray</param>
997 /// <param name="length">Length of ray in meters</param>
998 /// <param name="retMethod">Method to call when the raycast is complete</param>
999 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
1000 {
1001 if (retMethod != null)
1002 {
1003 if (BSParam.UseBulletRaycast)
1004 {
1005 Vector3 posFrom = position;
1006 Vector3 posTo = Vector3.Normalize(direction) * length + position;
1007
1008 TaintedObject(DetailLogZero, "BSScene.RaycastWorld1", delegate ()
1009 {
1010 RaycastHit hitInfo = PE.RayTest2(World, posFrom, posTo, 0xffff, 0xffff);
1011 retMethod(true, hitInfo.Point, hitInfo.ID, hitInfo.Fraction, hitInfo.Normal);
1012 });
1013 }
1014 else
1015 {
1016 retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero);
1017 }
1018 }
1019 }
1020
1021 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod)
1022 {
1023 if (retMethod != null)
1024 {
1025 if (BSParam.UseBulletRaycast)
1026 {
1027 List<ContactResult> hitInfo = RaycastWorld(position, direction, length, count);
1028 retMethod(hitInfo);
1029 }
1030 else
1031 {
1032 retMethod(new List<ContactResult>());
1033 }
1034 }
1035 }
1036
1037 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int count)
1038 {
1039 return (List<ContactResult>)RaycastWorld(position, direction, length, count, RayFilterFlags.All);
1040 }
1041
1042 public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int count, RayFilterFlags filter)
1043 {
1044 List<ContactResult> ret = new List<ContactResult>();
1045 if (BSParam.UseBulletRaycast)
1046 {
1047 uint collisionFilter = 0;
1048 uint collisionMask = 0;
1049 if ((filter & RayFilterFlags.land) != 0)
1050 {
1051 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Terrain].group;
1052 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Terrain].mask;
1053 }
1054 if ((filter & RayFilterFlags.agent) != 0)
1055 {
1056 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Avatar].group;
1057 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Avatar].mask;
1058 }
1059 if ((filter & RayFilterFlags.nonphysical) != 0)
1060 {
1061 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Static].group;
1062 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Static].mask;
1063 }
1064 if ((filter & RayFilterFlags.physical) != 0)
1065 {
1066 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.Dynamic].group;
1067 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.Dynamic].mask;
1068 }
1069 // if ((filter & RayFilterFlags.phantom) != 0)
1070 // {
1071 // collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].group;
1072 // collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].mask;
1073 // }
1074 if ((filter & RayFilterFlags.volumedtc) != 0)
1075 {
1076 collisionFilter |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].group;
1077 collisionMask |= BulletSimData.CollisionTypeMasks[CollisionType.VolumeDetect].mask;
1078 }
1079 DetailLog("{0},RaycastWorld,pos={1},dir={2},len={3},count={4},filter={5},filter={6},mask={7}",
1080 DetailLogZero, position, direction, length, count, filter, collisionFilter, collisionMask);
1081 // NOTE: locking ensures the physics engine is not executing.
1082 // The caller might have to wait for the physics engine to finish.
1083 lock (PhysicsEngineLock)
1084 {
1085 Vector3 posFrom = position;
1086 Vector3 posTo = Vector3.Normalize(direction) * length + position;
1087 DetailLog("{0},RaycastWorld,RayTest2,from={1},to={2}",
1088 DetailLogZero, posFrom, posTo);
1089 RaycastHit hitInfo = PE.RayTest2(World, posFrom, posTo, collisionFilter, collisionMask);
1090 if (hitInfo.hasHit())
1091 {
1092 ContactResult result = new ContactResult();
1093 result.Pos = hitInfo.Point;
1094 result.Normal = hitInfo.Normal;
1095 result.ConsumerID = hitInfo.ID;
1096 result.Depth = hitInfo.Fraction;
1097 ret.Add(result);
1098 DetailLog("{0},RaycastWorld,hit,pos={1},norm={2},depth={3},id={4}",
1099 DetailLogZero, result.Pos, result.Normal, result.Depth, result.ConsumerID);
1100 }
1101 }
1102 }
1103 return ret;
1104 }
1105
1106 #endregion Raycast
1107
1108
959 public override Dictionary<uint, float> GetTopColliders() 1109 public override Dictionary<uint, float> GetTopColliders()
960 { 1110 {
961 Dictionary<uint, float> topColliders; 1111 Dictionary<uint, float> topColliders;
@@ -1068,32 +1218,35 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1068 // Calls to the PhysicsActors can't directly call into the physics engine 1218 // Calls to the PhysicsActors can't directly call into the physics engine
1069 // because it might be busy. We delay changes to a known time. 1219 // because it might be busy. We delay changes to a known time.
1070 // We rely on C#'s closure to save and restore the context for the delegate. 1220 // We rely on C#'s closure to save and restore the context for the delegate.
1071 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback) 1221 // NOTE: 'inTaintTime' is no longer used. This entry exists so all the calls don't have to be changed.
1222 // public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1223 // {
1224 // TaintedObject(BSScene.DetailLogZero, pIdent, pCallback);
1225 // }
1226 // NOTE: 'inTaintTime' is no longer used. This entry exists so all the calls don't have to be changed.
1227 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1072 { 1228 {
1073 TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback); 1229 TaintedObject(m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1074 } 1230 }
1075 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback) 1231 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
1076 { 1232 {
1077 TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback); 1233 TaintedObject(m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1078 }
1079 public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1080 {
1081 TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
1082 }
1083 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1084 {
1085 TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1086 } 1234 }
1087 // Sometimes a potentially tainted operation can be used in and out of taint time. 1235 // Sometimes a potentially tainted operation can be used in and out of taint time.
1088 // This routine executes the command immediately if in taint-time otherwise it is queued. 1236 // This routine executes the command immediately if in taint-time otherwise it is queued.
1089 public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback) 1237 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
1090 { 1238 {
1091 if (!m_initialized) return; 1239 if (!m_initialized) return;
1092 1240
1093 if (inTaintTime) 1241 if (Monitor.TryEnter(PhysicsEngineLock))
1242 {
1243 // If we can get exclusive access to the physics engine, just do the operation
1094 pCallback(); 1244 pCallback();
1245 Monitor.Exit(PhysicsEngineLock);
1246 }
1095 else 1247 else
1096 { 1248 {
1249 // The physics engine is busy, queue the operation
1097 lock (_taintLock) 1250 lock (_taintLock)
1098 { 1251 {
1099 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback)); 1252 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
@@ -1120,14 +1273,21 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1120 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 1273 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
1121 // a callback into itself to do the actual property change. That callback is called 1274 // a callback into itself to do the actual property change. That callback is called
1122 // here just before the physics engine is called to step the simulation. 1275 // here just before the physics engine is called to step the simulation.
1123 public void ProcessTaints() 1276 // Returns the number of taints processed
1277 // NOTE: Called while PhysicsEngineLock is locked
1278 public int ProcessTaints()
1124 { 1279 {
1125 ProcessRegularTaints(); 1280 int ret = 0;
1126 ProcessPostTaintTaints(); 1281 ret += ProcessRegularTaints();
1282 ret += ProcessPostTaintTaints();
1283 return ret;
1127 } 1284 }
1128 1285
1129 private void ProcessRegularTaints() 1286 // Returns the number of taints processed
1287 // NOTE: Called while PhysicsEngineLock is locked
1288 private int ProcessRegularTaints()
1130 { 1289 {
1290 int ret = 0;
1131 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process 1291 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
1132 { 1292 {
1133 // swizzle a new list into the list location so we can process what's there 1293 // swizzle a new list into the list location so we can process what's there
@@ -1144,6 +1304,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1144 { 1304 {
1145 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG 1305 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
1146 tcbe.callback(); 1306 tcbe.callback();
1307 ret++;
1147 } 1308 }
1148 catch (Exception e) 1309 catch (Exception e)
1149 { 1310 {
@@ -1152,6 +1313,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1152 } 1313 }
1153 oldList.Clear(); 1314 oldList.Clear();
1154 } 1315 }
1316 return ret;
1155 } 1317 }
1156 1318
1157 // Schedule an update to happen after all the regular taints are processed. 1319 // Schedule an update to happen after all the regular taints are processed.
@@ -1170,8 +1332,11 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1170 } 1332 }
1171 1333
1172 // Taints that happen after the normal taint processing but before the simulation step. 1334 // Taints that happen after the normal taint processing but before the simulation step.
1173 private void ProcessPostTaintTaints() 1335 // Returns the number of taints processed
1336 // NOTE: Called while PhysicsEngineLock is locked
1337 private int ProcessPostTaintTaints()
1174 { 1338 {
1339 int ret = 0;
1175 if (m_initialized && _postTaintOperations.Count > 0) 1340 if (m_initialized && _postTaintOperations.Count > 0)
1176 { 1341 {
1177 Dictionary<string, TaintCallbackEntry> oldList; 1342 Dictionary<string, TaintCallbackEntry> oldList;
@@ -1187,6 +1352,7 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1187 { 1352 {
1188 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG 1353 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
1189 kvp.Value.callback(); 1354 kvp.Value.callback();
1355 ret++;
1190 } 1356 }
1191 catch (Exception e) 1357 catch (Exception e)
1192 { 1358 {
@@ -1195,20 +1361,8 @@ namespace OpenSim.Region.PhysicsModule.BulletS
1195 } 1361 }
1196 oldList.Clear(); 1362 oldList.Clear();
1197 } 1363 }
1364 return ret;
1198 } 1365 }
1199
1200 // Only used for debugging. Does not change state of anything so locking is not necessary.
1201 public bool AssertInTaintTime(string whereFrom)
1202 {
1203 if (!InTaintTime)
1204 {
1205 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
1206 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
1207 // Util.PrintCallStack(DetailLog);
1208 }
1209 return InTaintTime;
1210 }
1211
1212 #endregion // Taints 1366 #endregion // Taints
1213 1367
1214 #region IPhysicsParameters 1368 #region IPhysicsParameters
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
index 4ec6f51..86bf23f 100755
--- a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
@@ -75,8 +75,6 @@ public sealed class BSShapeCollection : IDisposable
75 // Called at taint-time. 75 // Called at taint-time.
76 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback) 76 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
77 { 77 {
78 m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
79
80 bool ret = false; 78 bool ret = false;
81 79
82 // This lock could probably be pushed down lower but building shouldn't take long 80 // This lock could probably be pushed down lower but building shouldn't take long
@@ -229,6 +227,8 @@ public sealed class BSShapeCollection : IDisposable
229 ret = CreateGeomMeshOrHull(prim, shapeCallback); 227 ret = CreateGeomMeshOrHull(prim, shapeCallback);
230 } 228 }
231 229
230 m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World); // DEBUG DEBUG
231
232 return ret; 232 return ret;
233 } 233 }
234 234
@@ -344,8 +344,6 @@ public sealed class BSShapeCollection : IDisposable
344 if (!body.HasPhysicalBody) 344 if (!body.HasPhysicalBody)
345 return; 345 return;
346 346
347 m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
348
349 lock (m_collectionActivityLock) 347 lock (m_collectionActivityLock)
350 { 348 {
351 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); 349 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
index 3329395..308769b 100755
--- a/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
@@ -100,6 +100,7 @@ public class BulletBody
100 } 100 }
101} 101}
102 102
103// Handle to btCollisionObject - a shape that can be added to a btRidgidBody
103public class BulletShape 104public class BulletShape
104{ 105{
105 public BulletShape() 106 public BulletShape()
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/Raycast.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/Raycast.cs
new file mode 100755
index 0000000..bfa95c1
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/Raycast.cs
@@ -0,0 +1,124 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Framework;
37using OpenSim.Region.PhysicsModule.BulletS;
38using OpenSim.Region.PhysicsModules.SharedBase;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.PhysicsModule.BulletS.Tests
44{
45 [TestFixture]
46 public class BulletSimRaycast : OpenSimTestCase
47 {
48 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
49 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
50
51 BSScene _physicsScene { get; set; }
52 BSPrim _targetSphere { get; set; }
53 Vector3 _targetSpherePosition { get; set; }
54 float _simulationTimeStep = 0.089f;
55
56 uint _targetLocalID = 123;
57
58 [TestFixtureSetUp]
59 public void Init()
60 {
61 Dictionary<string, string> engineParams = new Dictionary<string, string>();
62 engineParams.Add("UseBulletRaycast", "true");
63 _physicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
64
65 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere();
66 Vector3 pos = new Vector3(100.0f, 100.0f, 50f);
67 _targetSpherePosition = pos;
68 Vector3 size = new Vector3(10f, 10f, 10f);
69 pbs.Scale = size;
70 Quaternion rot = Quaternion.Identity;
71 bool isPhys = false;
72
73 _physicsScene.AddPrimShape("TargetSphere", pbs, pos, size, rot, isPhys, _targetLocalID);
74 _targetSphere = (BSPrim)_physicsScene.PhysObjects[_targetLocalID];
75 // The actual prim shape creation happens at taint time
76 _physicsScene.ProcessTaints();
77
78 }
79
80 [TestFixtureTearDown]
81 public void TearDown()
82 {
83 if (_physicsScene != null)
84 {
85 // The Dispose() will also free any physical objects in the scene
86 _physicsScene.Dispose();
87 _physicsScene = null;
88 }
89 }
90
91 // There is a 10x10x10 sphere at <100,100,50>
92 // Shoot rays around the sphere and verify it hits and doesn't hit
93 // TestCase parameters are <x,y,z> of start and <x,y,z> of end and expected result
94 [TestCase(100f, 50f, 50f, 100f, 150f, 50f, true, "Pass through sphere from front")]
95 [TestCase(50f, 100f, 50f, 150f, 100f, 50f, true, "Pass through sphere from side")]
96 [TestCase(50f, 50f, 50f, 150f, 150f, 50f, true, "Pass through sphere diaginally")]
97 [TestCase(100f, 100f, 100f, 100f, 100f, 20f, true, "Pass through sphere from above")]
98 [TestCase(20f, 20f, 50f, 80f, 80f, 50f, false, "Not reach sphere")]
99 [TestCase(50f, 50f, 65f, 150f, 150f, 65f, false, "Passed over sphere")]
100 public void RaycastAroundObject(float fromX, float fromY, float fromZ, float toX, float toY, float toZ, bool expected, string msg) {
101 Vector3 fromPos = new Vector3(fromX, fromY, fromZ);
102 Vector3 toPos = new Vector3(toX, toY, toZ);
103 Vector3 direction = toPos - fromPos;
104 float len = Vector3.Distance(fromPos, toPos);
105
106 List<ContactResult> results = _physicsScene.RaycastWorld(fromPos, direction, len, 1);
107
108 if (expected) {
109 // The test coordinates should generate a hit
110 Assert.True(results.Count != 0, msg + ": Did not return a hit but expected to.");
111 Assert.True(results.Count == 1, msg + ": Raycast returned not just one hit result.");
112 Assert.True(results[0].ConsumerID == _targetLocalID, msg + ": Raycast returned a collision object other than the target");
113 }
114 else
115 {
116 // The test coordinates should not generate a hit
117 if (results.Count > 0)
118 {
119 Assert.False(results.Count > 0, msg + ": Returned a hit at " + results[0].Pos.ToString());
120 }
121 }
122 }
123 }
124} \ No newline at end of file