BulletSim: most of the plumbing for raycast. Needs new BulletSim.dll to
work.BulletSim2017
parent
22c7450363
commit
0afa3a294a
|
@ -1404,6 +1404,19 @@ public override float GetMargin(BulletShape shape)
|
||||||
return BSAPICPP.GetMargin2(shapeu.ptr);
|
return BSAPICPP.GetMargin2(shapeu.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =====================================================================================
|
||||||
|
// Raycast
|
||||||
|
public override SweepHit ConvexSweepTest2(BulletWorld world, BulletBody sweepObject, Vector3 from, Vector3 to, float margin) {
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
BulletBodyUnman bodyu = sweepObject as BulletBodyUnman;
|
||||||
|
return BSAPICPP.ConvexSweepTest2(worldu.ptr, bodyu.ptr, from, to, margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask) {
|
||||||
|
BulletWorldUnman worldu = world as BulletWorldUnman;
|
||||||
|
return BSAPICPP.RayTest2(worldu.ptr, from, to, filterGroup, filterMask);
|
||||||
|
}
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// Debugging
|
// Debugging
|
||||||
public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
|
public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
|
||||||
|
@ -2084,6 +2097,15 @@ public static extern void SetMargin2(IntPtr shape, float val);
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern float GetMargin2(IntPtr shape);
|
public static extern float GetMargin2(IntPtr shape);
|
||||||
|
|
||||||
|
|
||||||
|
// =====================================================================================
|
||||||
|
// Raycast
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern SweepHit ConvexSweepTest2(IntPtr sim, IntPtr obj, Vector3 from, Vector3 to, float margin);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern RaycastHit RayTest2(IntPtr sim, Vector3 from, Vector3 to, uint filterGroup, uint filterMask);
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// Debugging
|
// Debugging
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
|
|
@ -2459,6 +2459,14 @@ private sealed class BulletConstraintXNA : BulletConstraint
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override SweepHit ConvexSweepTest2(BulletWorld world, BulletBody obj, Vector3 from, Vector3 to, float margin) {
|
||||||
|
return new SweepHit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask) {
|
||||||
|
return new RaycastHit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,7 @@ public struct RaycastHit
|
||||||
public UInt32 ID;
|
public UInt32 ID;
|
||||||
public float Fraction;
|
public float Fraction;
|
||||||
public Vector3 Normal;
|
public Vector3 Normal;
|
||||||
|
public Vector3 Point;
|
||||||
}
|
}
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct CollisionDesc
|
public struct CollisionDesc
|
||||||
|
@ -741,6 +742,12 @@ public abstract void SetMargin(BulletShape shape, float val);
|
||||||
|
|
||||||
public abstract float GetMargin(BulletShape shape);
|
public abstract float GetMargin(BulletShape shape);
|
||||||
|
|
||||||
|
// =====================================================================================
|
||||||
|
// Raycast
|
||||||
|
public abstract SweepHit ConvexSweepTest2(BulletWorld world, BulletBody obj, Vector3 from, Vector3 to, float margin);
|
||||||
|
|
||||||
|
public abstract RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask);
|
||||||
|
|
||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
// Debugging
|
// Debugging
|
||||||
public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
|
public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
|
||||||
|
|
|
@ -450,6 +450,7 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
|
m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
|
||||||
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
|
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
|
||||||
LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
|
LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
|
||||||
|
m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World); // DEBUG DEBUG
|
||||||
|
|
||||||
// With all of the linkset packed into the root prim, it has the mass of everyone.
|
// With all of the linkset packed into the root prim, it has the mass of everyone.
|
||||||
LinksetMass = ComputeLinksetMass();
|
LinksetMass = ComputeLinksetMass();
|
||||||
|
|
|
@ -230,6 +230,8 @@ public static class BSParam
|
||||||
public static float LinkConstraintCFM { get; private set; }
|
public static float LinkConstraintCFM { get; private set; }
|
||||||
public static float LinkConstraintSolverIterations { get; private set; }
|
public static float LinkConstraintSolverIterations { get; private set; }
|
||||||
|
|
||||||
|
public static bool UseBulletRaycast { get; private set; }
|
||||||
|
|
||||||
public static float PID_D { get; private set; } // derivative
|
public static float PID_D { get; private set; } // derivative
|
||||||
public static float PID_P { get; private set; } // proportional
|
public static float PID_P { get; private set; } // proportional
|
||||||
|
|
||||||
|
@ -823,6 +825,9 @@ public static class BSParam
|
||||||
new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
|
new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
|
||||||
40 ),
|
40 ),
|
||||||
|
|
||||||
|
new ParameterDefn<bool>("UseBulletRaycast", "If 'true', use the raycast function of the Bullet physics engine",
|
||||||
|
true ),
|
||||||
|
|
||||||
new ParameterDefn<float>("DebugNumber", "A console setable number sometimes used for debugging",
|
new ParameterDefn<float>("DebugNumber", "A console setable number sometimes used for debugging",
|
||||||
1.0f ),
|
1.0f ),
|
||||||
|
|
||||||
|
|
|
@ -956,6 +956,98 @@ namespace OpenSim.Region.PhysicsModule.BulletS
|
||||||
|
|
||||||
#endregion // Terrain
|
#endregion // Terrain
|
||||||
|
|
||||||
|
#region Raycast
|
||||||
|
|
||||||
|
public override bool SupportsRayCast()
|
||||||
|
{
|
||||||
|
return BSParam.UseBulletRaycast;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool SupportsRaycastWorldFiltered()
|
||||||
|
{
|
||||||
|
return BSParam.UseBulletRaycast;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a raycast against the physics scene.
|
||||||
|
/// The provided callback method will be called when the raycast is complete
|
||||||
|
///
|
||||||
|
/// Many physics engines don't support collision testing at the same time as
|
||||||
|
/// manipulating the physics scene, so we queue the request up and callback
|
||||||
|
/// a custom method when the raycast is complete.
|
||||||
|
/// This allows physics engines that give an immediate result to callback immediately
|
||||||
|
/// and ones that don't, to callback when it gets a result back.
|
||||||
|
/// public delegate void RayCallback(List<ContactResult> list);
|
||||||
|
///
|
||||||
|
/// ODE for example will not allow you to change the scene while collision testing or
|
||||||
|
/// it asserts, 'opteration not valid for locked space'. This includes adding a ray to the scene.
|
||||||
|
///
|
||||||
|
/// This is named RayCastWorld to not conflict with modrex's Raycast method.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">Origin of the ray</param>
|
||||||
|
/// <param name="direction">Direction of the ray</param>
|
||||||
|
/// <param name="length">Length of ray in meters</param>
|
||||||
|
/// <param name="retMethod">Method to call when the raycast is complete</param>
|
||||||
|
public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
|
||||||
|
{
|
||||||
|
if (retMethod != null)
|
||||||
|
{
|
||||||
|
if (BSParam.UseBulletRaycast)
|
||||||
|
{
|
||||||
|
Vector3 posFrom = position;
|
||||||
|
Vector3 posTo = Vector3.Normalize(direction) * length + position;
|
||||||
|
|
||||||
|
TaintedObject(DetailLogZero, "BSScene.RaycastWorld1", delegate ()
|
||||||
|
{
|
||||||
|
RaycastHit hitInfo = PE.RayTest2(World, posFrom, posTo, 0xffff, 0xffff);
|
||||||
|
retMethod(true, hitInfo.Point, hitInfo.ID, hitInfo.Fraction, hitInfo.Normal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod)
|
||||||
|
{
|
||||||
|
if (retMethod != null)
|
||||||
|
{
|
||||||
|
if (BSParam.UseBulletRaycast)
|
||||||
|
{
|
||||||
|
List<ContactResult> hitInfo = RaycastWorld(position, direction, length, count);
|
||||||
|
retMethod(hitInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retMethod(new List<ContactResult>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
|
||||||
|
{
|
||||||
|
List<ContactResult> ret = new List<ContactResult>();
|
||||||
|
if (BSParam.UseBulletRaycast)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
|
||||||
|
{
|
||||||
|
object ret = null;
|
||||||
|
if (BSParam.UseBulletRaycast)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Raycast
|
||||||
|
|
||||||
|
|
||||||
public override Dictionary<uint, float> GetTopColliders()
|
public override Dictionary<uint, float> GetTopColliders()
|
||||||
{
|
{
|
||||||
Dictionary<uint, float> topColliders;
|
Dictionary<uint, float> topColliders;
|
||||||
|
|
|
@ -229,6 +229,8 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
ret = CreateGeomMeshOrHull(prim, shapeCallback);
|
ret = CreateGeomMeshOrHull(prim, shapeCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World); // DEBUG DEBUG
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.PhysicsModule.BulletS;
|
||||||
|
using OpenSim.Region.PhysicsModules.SharedBase;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
|
using OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.PhysicsModule.BulletS.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class BulletSimRaycast : OpenSimTestCase
|
||||||
|
{
|
||||||
|
// Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
|
||||||
|
// Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
|
||||||
|
|
||||||
|
BSScene PhysicsScene { get; set; }
|
||||||
|
BSPrim TargetSphere { get; set; }
|
||||||
|
Vector3 TargetSpherePosition { get; set; }
|
||||||
|
float simulationTimeStep = 0.089f;
|
||||||
|
|
||||||
|
[TestFixtureSetUp]
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
Dictionary<string, string> engineParams = new Dictionary<string, string>();
|
||||||
|
engineParams.Add("UseBulletRaycast", "true");
|
||||||
|
PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
|
||||||
|
|
||||||
|
PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere();
|
||||||
|
Vector3 pos = new Vector3(100.0f, 100.0f, 50f);
|
||||||
|
pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f;
|
||||||
|
TargetSpherePosition = pos;
|
||||||
|
Vector3 size = new Vector3(10f, 10f, 10f);
|
||||||
|
pbs.Scale = size;
|
||||||
|
Quaternion rot = Quaternion.Identity;
|
||||||
|
bool isPhys = false;
|
||||||
|
uint localID = 123;
|
||||||
|
|
||||||
|
PhysicsScene.AddPrimShape("TargetSphere", pbs, pos, size, rot, isPhys, localID);
|
||||||
|
TargetSphere = (BSPrim)PhysicsScene.PhysObjects[localID];
|
||||||
|
// The actual prim shape creation happens at taint time
|
||||||
|
PhysicsScene.ProcessTaints();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestFixtureTearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
if (PhysicsScene != null)
|
||||||
|
{
|
||||||
|
// The Dispose() will also free any physical objects in the scene
|
||||||
|
PhysicsScene.Dispose();
|
||||||
|
PhysicsScene = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is a 10x10x10 sphere at <100,100,50>
|
||||||
|
// Shoot rays around the sphere and verify it hits and doesn't hit
|
||||||
|
// TestCase parameters are <x,y,z> of start and <x,y,z> of end and expected result
|
||||||
|
[TestCase(20f, 20f, 50f, 50f, 50f, 50f, true)] // in front to sphere
|
||||||
|
[TestCase(20f, 20f, 100f, 50f, 50f, 50f, true)] // from above to sphere
|
||||||
|
[TestCase(50f, 50f, 50f, 150f, 150f, 50f, true)] // through sphere
|
||||||
|
[TestCase(50f, 50f, 65f, 150f, 150f, 65f, false)] // pass over sphere
|
||||||
|
public void RaycastAroundObject(float fromX, float fromY, float fromZ, float toX, float toY, float toZ, bool expected) {
|
||||||
|
Vector3 fromPos = new Vector3(fromX, fromY, fromZ);
|
||||||
|
Vector3 toPos = new Vector3(toX, toY, toZ);
|
||||||
|
Vector3 direction = toPos - fromPos;
|
||||||
|
float len = Vector3.Distance(fromPos, toPos);
|
||||||
|
|
||||||
|
List<ContactResult> results = PhysicsScene.RaycastWorld(fromPos, direction, len, 1);
|
||||||
|
|
||||||
|
if (expected) {
|
||||||
|
Assert.True(results.Count > 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.False(results.Count > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue