Decouple graphics and input from simulations. Cleanup.
This commit is contained in:
Родитель
7d3fcd57ff
Коммит
8e5164df0e
|
@ -0,0 +1,3 @@
|
|||
obj
|
||||
bin
|
||||
packages
|
|
@ -15,31 +15,17 @@ namespace BulletSharp
|
|||
{
|
||||
}
|
||||
|
||||
public BvhTriangleMeshShape(StridingMeshInterface meshInterface, bool useQuantizedAabbCompression)
|
||||
: base(btBvhTriangleMeshShape_new(meshInterface._native, useQuantizedAabbCompression))
|
||||
{
|
||||
_meshInterface = meshInterface;
|
||||
}
|
||||
|
||||
public BvhTriangleMeshShape(StridingMeshInterface meshInterface, bool useQuantizedAabbCompression,
|
||||
bool buildBvh)
|
||||
: base(btBvhTriangleMeshShape_new2(meshInterface._native, useQuantizedAabbCompression,
|
||||
bool buildBvh = true)
|
||||
: base(btBvhTriangleMeshShape_new(meshInterface._native, useQuantizedAabbCompression,
|
||||
buildBvh))
|
||||
{
|
||||
_meshInterface = meshInterface;
|
||||
}
|
||||
|
||||
public BvhTriangleMeshShape(StridingMeshInterface meshInterface, bool useQuantizedAabbCompression,
|
||||
Vector3 bvhAabbMin, Vector3 bvhAabbMax)
|
||||
: base(btBvhTriangleMeshShape_new3(meshInterface._native, useQuantizedAabbCompression,
|
||||
ref bvhAabbMin, ref bvhAabbMax))
|
||||
{
|
||||
_meshInterface = meshInterface;
|
||||
}
|
||||
|
||||
public BvhTriangleMeshShape(StridingMeshInterface meshInterface, bool useQuantizedAabbCompression,
|
||||
Vector3 bvhAabbMin, Vector3 bvhAabbMax, bool buildBvh)
|
||||
: base(btBvhTriangleMeshShape_new4(meshInterface._native, useQuantizedAabbCompression,
|
||||
Vector3 bvhAabbMin, Vector3 bvhAabbMax, bool buildBvh = true)
|
||||
: base(btBvhTriangleMeshShape_new2(meshInterface._native, useQuantizedAabbCompression,
|
||||
ref bvhAabbMin, ref bvhAabbMax, buildBvh))
|
||||
{
|
||||
_meshInterface = meshInterface;
|
||||
|
@ -153,13 +139,9 @@ namespace BulletSharp
|
|||
}
|
||||
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern IntPtr btBvhTriangleMeshShape_new(IntPtr meshInterface, bool useQuantizedAabbCompression);
|
||||
static extern IntPtr btBvhTriangleMeshShape_new(IntPtr meshInterface, bool useQuantizedAabbCompression, bool buildBvh);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern IntPtr btBvhTriangleMeshShape_new2(IntPtr meshInterface, bool useQuantizedAabbCompression, bool buildBvh);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern IntPtr btBvhTriangleMeshShape_new3(IntPtr meshInterface, bool useQuantizedAabbCompression, [In] ref Vector3 bvhAabbMin, [In] ref Vector3 bvhAabbMax);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern IntPtr btBvhTriangleMeshShape_new4(IntPtr meshInterface, bool useQuantizedAabbCompression, [In] ref Vector3 bvhAabbMin, [In] ref Vector3 bvhAabbMax, bool buildBvh);
|
||||
static extern IntPtr btBvhTriangleMeshShape_new2(IntPtr meshInterface, bool useQuantizedAabbCompression, [In] ref Vector3 bvhAabbMin, [In] ref Vector3 bvhAabbMax, bool buildBvh);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern void btBvhTriangleMeshShape_buildOptimizedBvh(IntPtr obj);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
|
|
|
@ -366,6 +366,12 @@ namespace BulletSharp
|
|||
set { btCollisionObject_setRollingFriction(_native, value); }
|
||||
}
|
||||
|
||||
public float SpinningFriction
|
||||
{
|
||||
get { return btCollisionObject_getSpinningFriction(_native); }
|
||||
set { btCollisionObject_setSpinningFriction(_native, value); }
|
||||
}
|
||||
|
||||
public object UserObject { get; set; }
|
||||
|
||||
public int UserIndex
|
||||
|
@ -503,6 +509,8 @@ namespace BulletSharp
|
|||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern float btCollisionObject_getRollingFriction(IntPtr obj);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern float btCollisionObject_getSpinningFriction(IntPtr obj);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern int btCollisionObject_getWorldArrayIndex(IntPtr obj);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern int btCollisionObject_getUserIndex(IntPtr obj);
|
||||
|
@ -586,6 +594,8 @@ namespace BulletSharp
|
|||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern void btCollisionObject_setRollingFriction(IntPtr obj, float frict);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern void btCollisionObject_setSpinningFriction(IntPtr obj, float frict);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern void btCollisionObject_setWorldArrayIndex(IntPtr obj, int id);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern void btCollisionObject_setUserIndex(IntPtr obj, int index);
|
||||
|
|
|
@ -15,14 +15,6 @@ namespace BulletSharp
|
|||
{
|
||||
}
|
||||
|
||||
public HeightfieldTerrainShape(int heightStickWidth, int heightStickLength,
|
||||
IntPtr heightfieldData, float maxHeight, int upAxis, bool useFloatData,
|
||||
bool flipQuadEdges)
|
||||
: base(btHeightfieldTerrainShape_new2(heightStickWidth, heightStickLength,
|
||||
heightfieldData, maxHeight, upAxis, useFloatData, flipQuadEdges))
|
||||
{
|
||||
}
|
||||
|
||||
public void SetUseDiamondSubdivision()
|
||||
{
|
||||
btHeightfieldTerrainShape_setUseDiamondSubdivision(_native);
|
||||
|
@ -43,6 +35,11 @@ namespace BulletSharp
|
|||
btHeightfieldTerrainShape_setUseZigzagSubdivision2(_native, useZigzagSubdivision);
|
||||
}
|
||||
|
||||
private void Validate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
static extern IntPtr btHeightfieldTerrainShape_new(int heightStickWidth, int heightStickLength, IntPtr heightfieldData, float heightScale, float minHeight, float maxHeight, int upAxis, PhyScalarType heightDataType, bool flipQuadEdges);
|
||||
[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]
|
||||
|
|
|
@ -14,10 +14,11 @@ namespace BulletSharp
|
|||
|
||||
public MultiBodyPoint2Point(MultiBody body, int link, RigidBody bodyB, Vector3 pivotInA,
|
||||
Vector3 pivotInB)
|
||||
: base(btMultiBodyPoint2Point_new(body._native, link, bodyB._native,
|
||||
: base(btMultiBodyPoint2Point_new(body._native, link, bodyB != null ? bodyB._native : IntPtr.Zero,
|
||||
ref pivotInA, ref pivotInB))
|
||||
{
|
||||
}
|
||||
_multiBodyA = body;
|
||||
}
|
||||
|
||||
public MultiBodyPoint2Point(MultiBody bodyA, int linkA, MultiBody bodyB,
|
||||
int linkB, Vector3 pivotInA, Vector3 pivotInB)
|
||||
|
|
|
@ -3102,7 +3102,7 @@ namespace BulletSharp.SoftBody
|
|||
static extern void btSoftBody_SolverState_setVelmrg(IntPtr obj, float value);
|
||||
}
|
||||
|
||||
public class SRayCast
|
||||
public class SoftBodyRayCast
|
||||
{
|
||||
public SoftBody Body { get; set; }
|
||||
public FeatureType Feature { get; set; }
|
||||
|
@ -3236,8 +3236,8 @@ namespace BulletSharp.SoftBody
|
|||
_collisionShape = new SoftBodyCollisionShape(btCollisionObject_getCollisionShape(_native));
|
||||
}
|
||||
|
||||
public SoftBody(SoftBodyWorldInfo worldInfo, int nodeCount, Vector3[] x, float[] m)
|
||||
: base(btSoftBody_new(worldInfo._native, nodeCount, x, m))
|
||||
public SoftBody(SoftBodyWorldInfo worldInfo, int nodeCount, Vector3[] positions, float[] masses)
|
||||
: base(btSoftBody_new(worldInfo._native, nodeCount, positions, masses))
|
||||
{
|
||||
_collisionShape = new SoftBodyCollisionShape(btCollisionObject_getCollisionShape(_native));
|
||||
_worldInfo = worldInfo;
|
||||
|
@ -3650,7 +3650,7 @@ namespace BulletSharp.SoftBody
|
|||
btSoftBody_randomizeConstraints(_native);
|
||||
}
|
||||
|
||||
public bool RayTestRef(ref Vector3 rayFrom, ref Vector3 rayTo, SRayCast results)
|
||||
public bool RayTestRef(ref Vector3 rayFrom, ref Vector3 rayTo, SoftBodyRayCast results)
|
||||
{
|
||||
IntPtr rayCast = btSoftBody_sRayCast_new();
|
||||
bool ret = btSoftBody_rayTest(_native, ref rayFrom, ref rayTo, rayCast);
|
||||
|
@ -3662,7 +3662,7 @@ namespace BulletSharp.SoftBody
|
|||
return ret;
|
||||
}
|
||||
|
||||
public bool RayTest(Vector3 rayFrom, Vector3 rayTo, SRayCast results)
|
||||
public bool RayTest(Vector3 rayFrom, Vector3 rayTo, SoftBodyRayCast results)
|
||||
{
|
||||
IntPtr rayCast = btSoftBody_sRayCast_new();
|
||||
bool ret = btSoftBody_rayTest(_native, ref rayFrom, ref rayTo, rayCast);
|
||||
|
|
|
@ -225,126 +225,126 @@ namespace BulletSharp.SoftBody
|
|||
}
|
||||
|
||||
public static SoftBody CreatePatch(SoftBodyWorldInfo worldInfo, Vector3 corner00,
|
||||
Vector3 corner10, Vector3 corner01, Vector3 corner11, int resx, int resy,
|
||||
int fixeds, bool gendiags)
|
||||
Vector3 corner10, Vector3 corner01, Vector3 corner11, int resolutionX, int resolutionY,
|
||||
int fixedCorners, bool generateDiagonals)
|
||||
{
|
||||
// Create nodes
|
||||
if ((resx < 2) || (resy < 2))
|
||||
if ((resolutionX < 2) || (resolutionY < 2))
|
||||
return null;
|
||||
|
||||
int rx = resx;
|
||||
int ry = resy;
|
||||
int tot = rx * ry;
|
||||
Vector3[] x = new Vector3[tot];
|
||||
float[] m = new float[tot];
|
||||
int rx = resolutionX;
|
||||
int ry = resolutionY;
|
||||
int total = rx * ry;
|
||||
var positions = new Vector3[total];
|
||||
var masses = new float[total];
|
||||
|
||||
for (int iy = 0; iy < ry; iy++)
|
||||
for (int y = 0; y < ry; y++)
|
||||
{
|
||||
float ty = iy / (float)(ry - 1);
|
||||
float ty = y / (float)(ry - 1);
|
||||
Vector3 py0, py1;
|
||||
Vector3.Lerp(ref corner00, ref corner01, ty, out py0);
|
||||
Vector3.Lerp(ref corner10, ref corner11, ty, out py1);
|
||||
for (int ix = 0; ix < rx; ix++)
|
||||
{
|
||||
float tx = ix / (float)(rx - 1);
|
||||
int index = rx * iy + ix;
|
||||
Vector3.Lerp(ref py0, ref py1, tx, out x[index]);
|
||||
m[index] = 1;
|
||||
int index = rx * y + ix;
|
||||
Vector3.Lerp(ref py0, ref py1, tx, out positions[index]);
|
||||
masses[index] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
var psb = new SoftBody(worldInfo, tot, x, m);
|
||||
var body = new SoftBody(worldInfo, total, positions, masses);
|
||||
|
||||
if ((fixeds & 1) != 0)
|
||||
psb.SetMass(0, 0);
|
||||
if ((fixeds & 2) != 0)
|
||||
psb.SetMass(rx - 1, 0);
|
||||
if ((fixeds & 4) != 0)
|
||||
psb.SetMass(rx * (ry - 1), 0);
|
||||
if ((fixeds & 8) != 0)
|
||||
psb.SetMass(rx * (ry - 1) + rx - 1, 0);
|
||||
if ((fixedCorners & 1) != 0)
|
||||
body.SetMass(0, 0);
|
||||
if ((fixedCorners & 2) != 0)
|
||||
body.SetMass(rx - 1, 0);
|
||||
if ((fixedCorners & 4) != 0)
|
||||
body.SetMass(rx * (ry - 1), 0);
|
||||
if ((fixedCorners & 8) != 0)
|
||||
body.SetMass(rx * (ry - 1) + rx - 1, 0);
|
||||
|
||||
// Create links and faces
|
||||
for (int iy = 0; iy < ry; ++iy)
|
||||
for (int y = 0; y < ry; ++y)
|
||||
{
|
||||
for (int ix = 0; ix < rx; ++ix)
|
||||
for (int x = 0; x < rx; ++x)
|
||||
{
|
||||
int ixy = rx * iy + ix;
|
||||
int ixy = rx * y + x;
|
||||
int ix1y = ixy + 1;
|
||||
int ixy1 = rx * (iy + 1) + ix;
|
||||
int ixy1 = rx * (y + 1) + x;
|
||||
|
||||
bool mdx = (ix + 1) < rx;
|
||||
bool mdy = (iy + 1) < ry;
|
||||
bool mdx = (x + 1) < rx;
|
||||
bool mdy = (y + 1) < ry;
|
||||
if (mdx)
|
||||
psb.AppendLink(ixy, ix1y);
|
||||
body.AppendLink(ixy, ix1y);
|
||||
if (mdy)
|
||||
psb.AppendLink(ixy, ixy1);
|
||||
body.AppendLink(ixy, ixy1);
|
||||
if (mdx && mdy)
|
||||
{
|
||||
int ix1y1 = ixy1 + 1;
|
||||
if (((ix + iy) & 1) != 0)
|
||||
if (((x + y) & 1) != 0)
|
||||
{
|
||||
psb.AppendFace(ixy, ix1y, ix1y1);
|
||||
psb.AppendFace(ixy, ix1y1, ixy1);
|
||||
if (gendiags)
|
||||
body.AppendFace(ixy, ix1y, ix1y1);
|
||||
body.AppendFace(ixy, ix1y1, ixy1);
|
||||
if (generateDiagonals)
|
||||
{
|
||||
psb.AppendLink(ixy, ix1y1);
|
||||
body.AppendLink(ixy, ix1y1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
psb.AppendFace(ixy1, ixy, ix1y);
|
||||
psb.AppendFace(ixy1, ix1y, ix1y1);
|
||||
if (gendiags)
|
||||
body.AppendFace(ixy1, ixy, ix1y);
|
||||
body.AppendFace(ixy1, ix1y, ix1y1);
|
||||
if (generateDiagonals)
|
||||
{
|
||||
psb.AppendLink(ix1y, ixy1);
|
||||
body.AppendLink(ix1y, ixy1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return psb;
|
||||
return body;
|
||||
}
|
||||
|
||||
public static SoftBody CreatePatchUV(SoftBodyWorldInfo worldInfo, Vector3 corner00,
|
||||
Vector3 corner10, Vector3 corner01, Vector3 corner11, int resx, int resy,
|
||||
int fixeds, bool gendiags, float[] texCoords = null)
|
||||
Vector3 corner10, Vector3 corner01, Vector3 corner11, int resolutionX, int resolutionY,
|
||||
int fixedCorners, bool generateDiagonals, float[] texCoords = null)
|
||||
{
|
||||
var body = new SoftBody(btSoftBodyHelpers_CreatePatchUV(worldInfo._native,
|
||||
ref corner00, ref corner10, ref corner01, ref corner11, resx, resy,
|
||||
fixeds, gendiags, texCoords));
|
||||
ref corner00, ref corner10, ref corner01, ref corner11, resolutionX, resolutionY,
|
||||
fixedCorners, generateDiagonals, texCoords));
|
||||
body.WorldInfo = worldInfo;
|
||||
return body;
|
||||
}
|
||||
|
||||
public static SoftBody CreateRope(SoftBodyWorldInfo worldInfo, Vector3 from,
|
||||
Vector3 to, int res, int fixeds)
|
||||
Vector3 to, int resolution, int fixedTips)
|
||||
{
|
||||
// Create nodes
|
||||
int r = res + 2;
|
||||
Vector3[] x = new Vector3[r];
|
||||
float[] m = new float[r];
|
||||
int numLinks = resolution + 2;
|
||||
var positions = new Vector3[numLinks];
|
||||
var masses = new float[numLinks];
|
||||
|
||||
for (int i = 0; i < r; i++)
|
||||
for (int i = 0; i < numLinks; i++)
|
||||
{
|
||||
Vector3.Lerp(ref from, ref to, i / (float)(r - 1), out x[i]);
|
||||
m[i] = 1;
|
||||
Vector3.Lerp(ref from, ref to, i / (float)(numLinks - 1), out positions[i]);
|
||||
masses[i] = 1;
|
||||
}
|
||||
|
||||
var psb = new SoftBody(worldInfo, r, x, m);
|
||||
if ((fixeds & 1) != 0)
|
||||
psb.SetMass(0, 0);
|
||||
if ((fixeds & 2) != 0)
|
||||
psb.SetMass(r - 1, 0);
|
||||
var body = new SoftBody(worldInfo, numLinks, positions, masses);
|
||||
if ((fixedTips & 1) != 0)
|
||||
body.SetMass(0, 0);
|
||||
if ((fixedTips & 2) != 0)
|
||||
body.SetMass(numLinks - 1, 0);
|
||||
|
||||
// Create links
|
||||
for (int i = 1; i < r; i++)
|
||||
for (int i = 1; i < numLinks; i++)
|
||||
{
|
||||
psb.AppendLink(i - 1, i);
|
||||
body.AppendLink(i - 1, i);
|
||||
}
|
||||
|
||||
return psb;
|
||||
return body;
|
||||
}
|
||||
|
||||
public static void Draw(SoftBody psb, IDebugDraw iDraw, DrawFlags drawFlags = DrawFlags.Std)
|
||||
|
|
|
@ -1,95 +1,94 @@
|
|||
using System;
|
||||
using BulletSharp;
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using DemoFramework;
|
||||
using System;
|
||||
|
||||
namespace BasicDemo
|
||||
{
|
||||
class BasicDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(30, 20, 15);
|
||||
Vector3 target = new Vector3(0, 3, 0);
|
||||
|
||||
// create 125 (5x5x5) dynamic objects
|
||||
const int ArraySizeX = 5, ArraySizeY = 5, ArraySizeZ = 5;
|
||||
Vector3 startPosition = new Vector3(0, 2, 0);
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Basic Demo");
|
||||
DemoRunner.Run<BasicDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
internal sealed class BasicDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
demo.FreeLook.Eye = new Vector3(30, 20, 15);
|
||||
demo.FreeLook.Target = new Vector3(0, 3, 0);
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Basic Demo";
|
||||
return new BasicDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class BasicDemoSimulation : ISimulation
|
||||
{
|
||||
private const int NumBoxesX = 5, NumBoxesY = 5, NumBoxesZ = 5;
|
||||
private Vector3 _startPosition = new Vector3(0, 2, 0);
|
||||
|
||||
public BasicDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Broadphase = new DbvtBroadphase();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
CreateGround();
|
||||
CreateBoxes();
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
var groundShape = new BoxShape(50, 1, 50);
|
||||
//groundShape.InitializePolyhedralFeatures();
|
||||
//var groundShape = new StaticPlaneShape(Vector3.UnitY, 1);
|
||||
|
||||
CollisionShapes.Add(groundShape);
|
||||
CollisionObject ground = LocalCreateRigidBody(0, Matrix.Identity, groundShape);
|
||||
CollisionObject ground = PhysicsHelper.CreateStaticBody(Matrix.Identity, groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
}
|
||||
|
||||
private void CreateBoxes()
|
||||
{
|
||||
const float mass = 1.0f;
|
||||
var colShape = new BoxShape(1);
|
||||
CollisionShapes.Add(colShape);
|
||||
Vector3 localInertia = colShape.CalculateLocalInertia(mass);
|
||||
var shape = new BoxShape(1);
|
||||
Vector3 localInertia = shape.CalculateLocalInertia(mass);
|
||||
var bodyInfo = new RigidBodyConstructionInfo(mass, null, shape, localInertia);
|
||||
|
||||
var rbInfo = new RigidBodyConstructionInfo(mass, null, colShape, localInertia);
|
||||
|
||||
for (int y = 0; y < ArraySizeY; y++)
|
||||
for (int y = 0; y < NumBoxesY; y++)
|
||||
{
|
||||
for (int x = 0; x < ArraySizeX; x++)
|
||||
for (int x = 0; x < NumBoxesX; x++)
|
||||
{
|
||||
for (int z = 0; z < ArraySizeZ; z++)
|
||||
for (int z = 0; z < NumBoxesZ; z++)
|
||||
{
|
||||
Vector3 position = startPosition + 2 * new Vector3(x, y, z);
|
||||
Vector3 position = _startPosition + 2 * new Vector3(x, y, z);
|
||||
|
||||
// make it drop from a height
|
||||
position += new Vector3(0, 10, 0);
|
||||
|
||||
// using MotionState is recommended, it provides interpolation capabilities
|
||||
// and only synchronizes 'active' objects
|
||||
rbInfo.MotionState = new DefaultMotionState(Matrix.Translation(position));
|
||||
var body = new RigidBody(rbInfo);
|
||||
bodyInfo.MotionState = new DefaultMotionState(Matrix.Translation(position));
|
||||
var body = new RigidBody(bodyInfo);
|
||||
|
||||
World.AddRigidBody(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rbInfo.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new BasicDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
bodyInfo.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,73 +6,80 @@ using System;
|
|||
|
||||
namespace BenchmarkDemo
|
||||
{
|
||||
class BenchmarkDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(60, 40, 20);
|
||||
Vector3 target = new Vector3(0, 5, -4);
|
||||
|
||||
const float defaultContactProcessingThreshold = 0.0f;
|
||||
|
||||
int scene = 1;
|
||||
Action[] _scenes;
|
||||
|
||||
public BenchmarkDemo()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
_scenes = new Action[] {
|
||||
Create3KBoxes, CreateStructures, CreateTaruStack, CreateShapesGravity, CreateTaruGravity
|
||||
};
|
||||
DemoRunner.Run<BenchmarkDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitialize()
|
||||
internal sealed class BenchmarkDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Benchmark Demo");
|
||||
Graphics.SetInfoText("Move using mouse and WASD+shift\n" +
|
||||
"F3 - Toggle debug\n" +
|
||||
//"F11 - Toggle fullscreen\n" +
|
||||
"Space - Shoot box");
|
||||
demo.FreeLook.Eye = new Vector3(60, 40, 20);
|
||||
demo.FreeLook.Target = new Vector3(0, 5, -4);
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Benchmark Demo";
|
||||
return new BenchmarkDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
internal sealed class BenchmarkDemoSimulation : ISimulation
|
||||
{
|
||||
private const float defaultContactProcessingThreshold = 0.0f;
|
||||
|
||||
private int _scene = 1;
|
||||
private Action[] _scenes;
|
||||
|
||||
public BenchmarkDemoSimulation()
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
using (var cci = new DefaultCollisionConstructionInfo()
|
||||
{ DefaultMaxPersistentManifoldPoolSize = 32768 })
|
||||
{
|
||||
CollisionConf = new DefaultCollisionConfiguration(cci);
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration(cci);
|
||||
}
|
||||
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Dispatcher.DispatcherFlags = DispatcherFlags.DisableContactPoolDynamicAllocation;
|
||||
|
||||
// the maximum size of the collision world. Make sure objects stay within these boundaries
|
||||
// The maximum size of the collision world. Make sure objects stay within these boundaries
|
||||
// Don't make the world AABB size too large, it will harm simulation quality and performance
|
||||
Vector3 worldAabbMin = new Vector3(-1000, -1000, -1000);
|
||||
Vector3 worldAabbMax = new Vector3(1000, 1000, 1000);
|
||||
var worldAabbMin = new Vector3(-1000, -1000, -1000);
|
||||
var worldAabbMax = new Vector3(1000, 1000, 1000);
|
||||
|
||||
var pairCache = new HashedOverlappingPairCache();
|
||||
Broadphase = new AxisSweep3(worldAabbMin, worldAabbMax, 3500, pairCache);
|
||||
//Broadphase = new DbvtBroadphase();
|
||||
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
World.SolverInfo.SolverMode |= SolverModes.EnableFrictionDirectionCaching;
|
||||
World.SolverInfo.NumIterations = 5;
|
||||
|
||||
_scenes[scene]();
|
||||
_scenes = new Action[] {
|
||||
Create3KBoxes, CreateStructures, CreateTaruStack, CreateShapesGravity, CreateTaruGravity
|
||||
};
|
||||
_scenes[_scene]();
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
var groundShape = new BoxShape(250, 50, 250);
|
||||
CollisionShapes.Add(groundShape);
|
||||
var ground = base.LocalCreateRigidBody(0, Matrix.Translation(0, -50, 0), groundShape);
|
||||
var ground = PhysicsHelper.CreateStaticBody(Matrix.Translation(0, -50, 0), groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void Create3KBoxes()
|
||||
{
|
||||
CreateGround();
|
||||
|
@ -93,7 +100,7 @@ namespace BenchmarkDemo
|
|||
private void CreateStructures()
|
||||
{
|
||||
CreateGround();
|
||||
Vector3 boxSize = new Vector3(1);
|
||||
var boxSize = new Vector3(1);
|
||||
CreatePyramid(new Vector3(-20, 0, 0), 12, boxSize);
|
||||
CreateWall(new Vector3(-2, 0, 0), 12, boxSize);
|
||||
CreateWall(new Vector3(4, 0, 0), 12, boxSize);
|
||||
|
@ -124,7 +131,7 @@ namespace BenchmarkDemo
|
|||
{
|
||||
const float cubeHalfExtent = 1.5f;
|
||||
const float cubeWidth = cubeHalfExtent * 2;
|
||||
Vector3 boxSize = new Vector3(cubeHalfExtent);
|
||||
var boxSize = new Vector3(cubeHalfExtent);
|
||||
float boxMass = 1.0f;
|
||||
float sphereRadius = 1.5f;
|
||||
float sphereMass = 1.0f;
|
||||
|
@ -313,34 +320,11 @@ namespace BenchmarkDemo
|
|||
}
|
||||
}
|
||||
|
||||
public override RigidBody LocalCreateRigidBody(float mass, Matrix startTransform, CollisionShape shape)
|
||||
private RigidBody LocalCreateRigidBody(float mass, Matrix startTransform, CollisionShape shape)
|
||||
{
|
||||
//rigidbody is dynamic if and only if mass is non zero, otherwise static
|
||||
bool isDynamic = (mass != 0.0f);
|
||||
Vector3 localInertia = isDynamic ? shape.CalculateLocalInertia(mass) : Vector3.Zero;
|
||||
|
||||
using (var rbInfo = new RigidBodyConstructionInfo(mass, null, shape, localInertia))
|
||||
{
|
||||
var body = new RigidBody(rbInfo)
|
||||
{
|
||||
ContactProcessingThreshold = defaultContactProcessingThreshold,
|
||||
WorldTransform = startTransform
|
||||
};
|
||||
World.AddRigidBody(body);
|
||||
return body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new BenchmarkDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
RigidBody body = PhysicsHelper.CreateBody(mass, startTransform, shape, World);
|
||||
body.ContactProcessingThreshold = defaultContactProcessingThreshold;
|
||||
return body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,29 +5,37 @@ using System;
|
|||
|
||||
namespace Box2DDemo
|
||||
{
|
||||
class Box2DDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(0, 15, 20);
|
||||
Vector3 target = new Vector3(10, 10, 0);
|
||||
|
||||
///create 25 (5x5) dynamic objects
|
||||
const int ArraySizeX = 5, ArraySizeY = 5;
|
||||
public float Depth = 0.04f;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Box 2D Demo");
|
||||
DemoRunner.Run<Box2DDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
internal sealed class Box2DDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
demo.FreeLook.Eye = new Vector3(0, 15, 20);
|
||||
demo.FreeLook.Target = new Vector3(10, 10, 0);
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Box 2D Demo";
|
||||
return new Box2DDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Box2DDemoSimulation : ISimulation
|
||||
{
|
||||
private const int NumObjectsX = 5, NumObjectsY = 5;
|
||||
private const float Depth = 0.04f;
|
||||
|
||||
public Box2DDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
|
||||
// Use the default collision dispatcher. For parallel processing you can use a diffent dispatcher.
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
var simplex = new VoronoiSimplexSolver();
|
||||
var pdSolver = new MinkowskiPenetrationDepthSolver();
|
||||
|
@ -41,21 +49,26 @@ namespace Box2DDemo
|
|||
|
||||
Broadphase = new DbvtBroadphase();
|
||||
|
||||
// the default constraint solver.
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
CreateGround();
|
||||
Create2dBodies();
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
var groundShape = new BoxShape(150, 7, 150);
|
||||
CollisionShapes.Add(groundShape);
|
||||
var ground = LocalCreateRigidBody(0, Matrix.Identity, groundShape);
|
||||
var ground = PhysicsHelper.CreateStaticBody(Matrix.Identity, groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
}
|
||||
|
||||
|
@ -71,14 +84,6 @@ namespace Box2DDemo
|
|||
var childShape2 = new CylinderShapeZ(1, 1, Depth);
|
||||
var colShape3 = new Convex2DShape(childShape2);
|
||||
|
||||
CollisionShapes.Add(colShape);
|
||||
CollisionShapes.Add(colShape2);
|
||||
CollisionShapes.Add(colShape3);
|
||||
|
||||
CollisionShapes.Add(childShape0);
|
||||
CollisionShapes.Add(childShape1);
|
||||
CollisionShapes.Add(childShape2);
|
||||
|
||||
colShape.Margin = 0.03f;
|
||||
|
||||
float mass = 1.0f;
|
||||
|
@ -86,15 +91,15 @@ namespace Box2DDemo
|
|||
|
||||
var rbInfo = new RigidBodyConstructionInfo(mass, null, colShape, localInertia);
|
||||
|
||||
Vector3 x = new Vector3(-ArraySizeX, 8, -20);
|
||||
Vector3 x = new Vector3(-NumObjectsX, 8, -20);
|
||||
Vector3 y = Vector3.Zero;
|
||||
Vector3 deltaX = new Vector3(1, 2, 0);
|
||||
Vector3 deltaY = new Vector3(2, 0, 0);
|
||||
|
||||
for (int i = 0; i < ArraySizeY; i++)
|
||||
for (int i = 0; i < NumObjectsY; i++)
|
||||
{
|
||||
y = x;
|
||||
for (int j = 0; j < ArraySizeX; j++)
|
||||
for (int j = 0; j < NumObjectsX; j++)
|
||||
{
|
||||
Matrix startTransform = Matrix.Translation(y - new Vector3(-10, 0, 0));
|
||||
|
||||
|
@ -130,16 +135,4 @@ namespace Box2DDemo
|
|||
rbInfo.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new Box2DDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,31 +8,44 @@ using System.IO;
|
|||
|
||||
namespace BspDemo
|
||||
{
|
||||
class BspDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(10, 10, 10);
|
||||
Vector3 target = new Vector3(0, 0, 0);
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.Up = Vector3.UnitZ;
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Quake BSP Physics Viewer");
|
||||
DemoRunner.Run<BspDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
internal sealed class BspDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
demo.FreeLook.Eye = new Vector3(10, 10, 10);
|
||||
demo.FreeLook.Target = Vector3.Zero;
|
||||
demo.FreeLook.Up = BspDemoSimulation.Up;
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Quake BSP Physics Viewer";
|
||||
return new BspDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class BspDemoSimulation : ISimulation
|
||||
{
|
||||
public BspDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
Broadphase = new DbvtBroadphase();
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World.Gravity = Freelook.Up * -10.0f;
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
World.Gravity = Up * -10.0f;
|
||||
|
||||
LoadBspFile();
|
||||
}
|
||||
|
||||
private void LoadBspFile()
|
||||
{
|
||||
var bspLoader = new BspLoader();
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
if (args.Length == 1)
|
||||
|
@ -43,46 +56,42 @@ namespace BspDemo
|
|||
{
|
||||
bspLoader.LoadBspFile(args[1]);
|
||||
}
|
||||
BspConverter bsp2Bullet = new BspToBulletConverter(this);
|
||||
|
||||
var bsp2Bullet = new BspToBulletConverter(World);
|
||||
bsp2Bullet.ConvertBsp(bspLoader, 0.1f);
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public static Vector3 Up { get; } = Vector3.UnitZ;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.StandardCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public class BspToBulletConverter : BspConverter
|
||||
internal sealed class BspToBulletConverter : BspConverter
|
||||
{
|
||||
private Demo _demo;
|
||||
private DynamicsWorld _world;
|
||||
|
||||
public BspToBulletConverter(Demo demo)
|
||||
public BspToBulletConverter(DynamicsWorld world)
|
||||
{
|
||||
_demo = demo;
|
||||
_world = world;
|
||||
}
|
||||
|
||||
public override void AddConvexVerticesCollider(List<Vector3> vertices, bool isEntity, Vector3 entityTargetLocation)
|
||||
public override void AddCollider(List<Vector3> vertices)
|
||||
{
|
||||
if (vertices.Count == 0) return;
|
||||
|
||||
// perhaps we can do something special with entities (isEntity)
|
||||
// like adding a collision triggering (as example)
|
||||
|
||||
const float mass = 0.0f;
|
||||
//can use a shift
|
||||
Matrix startTransform = Matrix.Translation(0, 0, -10.0f);
|
||||
Matrix startTransform = Matrix.Translation(0, 0, -10.0f); // shift
|
||||
var shape = new ConvexHullShape(vertices);
|
||||
_demo.CollisionShapes.Add(shape);
|
||||
|
||||
_demo.LocalCreateRigidBody(mass, startTransform, shape);
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new BspDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
PhysicsHelper.CreateBody(mass, startTransform, shape, _world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,56 +6,53 @@ using System.IO;
|
|||
|
||||
namespace BulletXmlImportDemo
|
||||
{
|
||||
class BulletXmlImportDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(30, 20, 10);
|
||||
Vector3 target = new Vector3(0, 5, -4);
|
||||
|
||||
BulletXmlWorldImporter importer;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - XML Import Demo");
|
||||
DemoRunner.Run<BulletXmlImportDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
internal sealed class BulletXmlImportDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
demo.FreeLook.Eye = new Vector3(30, 20, 10);
|
||||
demo.FreeLook.Target = new Vector3(0, 5, -4);
|
||||
demo.Graphics.WindowTitle = "BulletSharp - XML Import Demo";
|
||||
return new BulletXmlImportDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class BulletXmlImportDemoSimulation : ISimulation
|
||||
{
|
||||
private readonly BulletXmlWorldImporter _importer;
|
||||
|
||||
public BulletXmlImportDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Broadphase = new DbvtBroadphase();
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
|
||||
importer = new BulletXmlWorldImporter(World);
|
||||
if (!importer.LoadFile(Path.Combine("data", "bullet_basic.xml")))
|
||||
_importer = new BulletXmlWorldImporter(World);
|
||||
if (!_importer.LoadFile(Path.Combine("data", "bullet_basic.xml")))
|
||||
{
|
||||
//throw new FileNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExitPhysics()
|
||||
{
|
||||
importer.DeleteAllData();
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
base.ExitPhysics();
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
public void Dispose()
|
||||
{
|
||||
using (Demo demo = new BulletXmlImportDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
_importer.DeleteAllData();
|
||||
this.StandardCleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,85 +6,134 @@ using System.Windows.Forms;
|
|||
|
||||
namespace CcdPhysicsDemo
|
||||
{
|
||||
class CcdPhysicsDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
bool ccdMode = true;
|
||||
|
||||
Vector3 eye = new Vector3(0, 20, 80);
|
||||
Vector3 target = Vector3.Zero;
|
||||
|
||||
const float CubeHalfExtents = 1.0f;
|
||||
const float ExtraHeight = 1.0f;
|
||||
|
||||
void ToggleCcdMode()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
ccdMode = !ccdMode;
|
||||
DemoRunner.Run<CcdPhysicsDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
if (ccdMode)
|
||||
internal sealed class CcdPhysicsDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
private bool _ccdEnabled = true;
|
||||
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
demo.FreeLook.Eye = new Vector3(0, 20, 80);
|
||||
demo.FreeLook.Target = Vector3.Zero;
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Continous Collision Detection Demo";
|
||||
SetDemoText(demo);
|
||||
return new CcdPhysicsDemoSimulation(_ccdEnabled);
|
||||
}
|
||||
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
var keys = demo.Input.KeysPressed;
|
||||
if (keys.Contains(Keys.P))
|
||||
{
|
||||
DemoText = "CCD enabled (P to disable)";
|
||||
_ccdEnabled = !_ccdEnabled;
|
||||
SetDemoText(demo);
|
||||
demo.ResetScene();
|
||||
}
|
||||
else if (keys.Contains(Keys.Space))
|
||||
{
|
||||
var ccdDemo = demo.Simulation as CcdPhysicsDemoSimulation;
|
||||
Vector3 destination = demo.GetRayTo(demo.Input.MousePoint, demo.FreeLook.Eye, demo.FreeLook.Target, demo.Graphics.FieldOfView);
|
||||
ccdDemo.ShootBox(demo.FreeLook.Eye, destination);
|
||||
keys.Remove(Keys.Space);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDemoText(Demo demo)
|
||||
{
|
||||
if (_ccdEnabled)
|
||||
{
|
||||
demo.DemoText = "CCD enabled (P to disable)";
|
||||
}
|
||||
else
|
||||
{
|
||||
DemoText = "CCD enabled (P to enable)";
|
||||
demo.DemoText = "CCD enabled (P to enable)";
|
||||
}
|
||||
|
||||
ClientResetScene();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitialize()
|
||||
internal sealed class CcdPhysicsDemoSimulation : ISimulation
|
||||
{
|
||||
private const float CubeHalfExtents = 1.0f;
|
||||
private const float ExtraHeight = 1.0f;
|
||||
private const float ShootBoxInitialSpeed = 4000;
|
||||
|
||||
private readonly bool _ccdEnabled;
|
||||
private BoxShape _shootBoxShape = new BoxShape(1);
|
||||
|
||||
public CcdPhysicsDemoSimulation(bool ccdEnabled)
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
_ccdEnabled = ccdEnabled;
|
||||
|
||||
Graphics.SetFormText("BulletSharp - CCD Demo");
|
||||
DemoText = "CCD enabled (P to disable)";
|
||||
}
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
|
||||
public override void OnHandleInput()
|
||||
{
|
||||
if (Input.KeysPressed.Contains(Keys.P))
|
||||
{
|
||||
ToggleCcdMode();
|
||||
}
|
||||
|
||||
base.OnHandleInput();
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
{
|
||||
shootBoxInitialSpeed = 4000;
|
||||
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
//Dispatcher.RegisterCollisionCreateFunc(BroadphaseNativeType.BoxShape, BroadphaseNativeType.BoxShape,
|
||||
// CollisionConf.GetCollisionAlgorithmCreateFunc(BroadphaseNativeType.ConvexShape, BroadphaseNativeType.ConvexShape));
|
||||
|
||||
Broadphase = new DbvtBroadphase();
|
||||
|
||||
// the default constraint solver
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
World.SolverInfo.SolverMode |= SolverModes.Use2FrictionDirections | SolverModes.RandomizeOrder;
|
||||
//World.SolverInfo.SplitImpulse = 0;
|
||||
World.SolverInfo.NumIterations = 20;
|
||||
|
||||
World.DispatchInfo.UseContinuous = ccdMode;
|
||||
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
World.DispatchInfo.UseContinuous = _ccdEnabled;
|
||||
|
||||
CreateGround();
|
||||
CreateBoxStack();
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void ShootBox(Vector3 camPos, Vector3 destination)
|
||||
{
|
||||
const float mass = 1.0f;
|
||||
|
||||
if (_shootBoxShape == null)
|
||||
{
|
||||
_shootBoxShape = new BoxShape(1.0f);
|
||||
_shootBoxShape.InitializePolyhedralFeatures();
|
||||
}
|
||||
|
||||
RigidBody body = PhysicsHelper.CreateBody(mass, Matrix.Translation(camPos), _shootBoxShape, World);
|
||||
body.LinearFactor = new Vector3(1, 1, 1);
|
||||
//body.Restitution = 1;
|
||||
|
||||
Vector3 linVel = destination - camPos;
|
||||
linVel.Normalize();
|
||||
body.LinearVelocity = linVel * ShootBoxInitialSpeed;
|
||||
body.AngularVelocity = Vector3.Zero;
|
||||
body.ContactProcessingThreshold = 1e30f;
|
||||
|
||||
// when using CCD mode, disable regular CCD
|
||||
if (_ccdEnabled)
|
||||
{
|
||||
body.CcdMotionThreshold = 0.0001f;
|
||||
body.CcdSweptSphereRadius = 0.4f;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
BoxShape ground = new BoxShape(200, 1, 200);
|
||||
var ground = new BoxShape(200, 1, 200);
|
||||
ground.InitializePolyhedralFeatures();
|
||||
CollisionShapes.Add(ground);
|
||||
RigidBody body = LocalCreateRigidBody(0, Matrix.Identity, ground);
|
||||
RigidBody body = PhysicsHelper.CreateStaticBody(Matrix.Identity, ground, World);
|
||||
body.Friction = 0.5f;
|
||||
//body.RollingFriction = 0.3f;
|
||||
body.UserObject = "Ground";
|
||||
|
@ -94,7 +143,6 @@ namespace CcdPhysicsDemo
|
|||
{
|
||||
//var shape = new CylinderShape(CubeHalfExtents, CubeHalfExtents, CubeHalfExtents);
|
||||
var shape = new BoxShape(CubeHalfExtents);
|
||||
CollisionShapes.Add(shape);
|
||||
|
||||
const int numObjects = 120;
|
||||
for (int i = 0; i < numObjects; i++)
|
||||
|
@ -114,57 +162,17 @@ namespace CcdPhysicsDemo
|
|||
Matrix trans = Matrix.Translation(col * 2 * CubeHalfExtents + (row2 % 2) * CubeHalfExtents,
|
||||
row * 2 * CubeHalfExtents + CubeHalfExtents + ExtraHeight, 0);
|
||||
|
||||
RigidBody body = LocalCreateRigidBody(1, trans, shape);
|
||||
RigidBody body = PhysicsHelper.CreateBody(1, trans, shape, World);
|
||||
body.SetAnisotropicFriction(shape.AnisotropicRollingFrictionDirection, AnisotropicFrictionFlags.RollingFriction);
|
||||
body.Friction = 0.5f;
|
||||
//body.RollingFriction = 0.3f;
|
||||
|
||||
if (ccdMode)
|
||||
if (_ccdEnabled)
|
||||
{
|
||||
body.CcdMotionThreshold = 1e-7f;
|
||||
body.CcdSweptSphereRadius = 0.9f * CubeHalfExtents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ShootBox(Vector3 camPos, Vector3 destination)
|
||||
{
|
||||
const float mass = 1.0f;
|
||||
|
||||
if (shootBoxShape == null)
|
||||
{
|
||||
shootBoxShape = new BoxShape(1.0f);
|
||||
shootBoxShape.InitializePolyhedralFeatures();
|
||||
}
|
||||
|
||||
RigidBody body = LocalCreateRigidBody(mass, Matrix.Translation(camPos), shootBoxShape);
|
||||
body.LinearFactor = new Vector3(1, 1, 1);
|
||||
//body.Restitution = 1;
|
||||
|
||||
Vector3 linVel = destination - camPos;
|
||||
linVel.Normalize();
|
||||
body.LinearVelocity = linVel * shootBoxInitialSpeed;
|
||||
body.AngularVelocity = Vector3.Zero;
|
||||
body.ContactProcessingThreshold = 1e30f;
|
||||
|
||||
// when using ccdMode, disable regular CCD
|
||||
if (ccdMode)
|
||||
{
|
||||
body.CcdMotionThreshold = 0.0001f;
|
||||
body.CcdSweptSphereRadius = 0.4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new CcdPhysicsDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
<HintPath>..\..\bin\Release\BulletSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -10,182 +10,183 @@ using System.Windows.Forms;
|
|||
|
||||
namespace CharacterDemo
|
||||
{
|
||||
public class BspToBulletConverter : BspConverter
|
||||
internal static class Program
|
||||
{
|
||||
private Demo _demo;
|
||||
|
||||
public BspToBulletConverter(Demo demo)
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
_demo = demo;
|
||||
}
|
||||
|
||||
public override void AddConvexVerticesCollider(List<Vector3> vertices, bool isEntity, Vector3 entityTargetLocation)
|
||||
{
|
||||
if (vertices.Count == 0) return;
|
||||
|
||||
//ConvexHullShape creates an internal copy of the vertices
|
||||
var verticesTransformed = vertices.Select(v => new Vector3(0.5f * v.X, 0.375f * v.Z, -0.5f * v.Y));
|
||||
var shape = new ConvexHullShape(verticesTransformed);
|
||||
_demo.CollisionShapes.Add(shape);
|
||||
|
||||
const float mass = 0.0f;
|
||||
//can use a shift
|
||||
Matrix startTransform = Matrix.Translation(0, -10.0f, 0);
|
||||
_demo.LocalCreateRigidBody(mass, startTransform, shape);
|
||||
DemoRunner.Run<CharacterDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
class CharacterDemo : Demo
|
||||
internal sealed class CharacterDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
Vector3 eye = new Vector3(10, 0, 10);
|
||||
Vector3 target = new Vector3(0, 0, 0);
|
||||
|
||||
PairCachingGhostObject ghostObject;
|
||||
KinematicCharacterController character;
|
||||
ClosestConvexResultCallback convexResultCallback;
|
||||
SphereShape cameraSphere;
|
||||
|
||||
protected override void OnInitialize()
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
Freelook.Up = Vector3.UnitY;
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Character Demo");
|
||||
DemoText = "Space - Jump";
|
||||
demo.FreeLook.Eye = new Vector3(10, 0, 10);
|
||||
demo.FreeLook.Target = Vector3.Zero;
|
||||
demo.DemoText = "Space - Jump";
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Character Demo";
|
||||
return new CharacterDemoSimulation();
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
var simulation = demo.Simulation as CharacterDemoSimulation;
|
||||
|
||||
Broadphase = new AxisSweep3(new Vector3(-1000, -1000, -1000), new Vector3(1000, 1000, 1000));
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World.DispatchInfo.AllowedCcdPenetration = 0.0001f;
|
||||
//World.Gravity = Freelook.Up * -10.0f;
|
||||
|
||||
Broadphase.OverlappingPairCache.SetInternalGhostPairCallback(new GhostPairCallback());
|
||||
|
||||
const float characterHeight = 1.75f;
|
||||
const float characterWidth = 1.75f;
|
||||
var capsule = new CapsuleShape(characterWidth, characterHeight);
|
||||
ghostObject = new PairCachingGhostObject()
|
||||
{
|
||||
CollisionShape = capsule,
|
||||
CollisionFlags = CollisionFlags.CharacterObject,
|
||||
WorldTransform = Matrix.Translation(10.210098f, -1.6433364f, 16.453260f)
|
||||
};
|
||||
World.AddCollisionObject(ghostObject, CollisionFilterGroups.CharacterFilter, CollisionFilterGroups.StaticFilter | CollisionFilterGroups.DefaultFilter);
|
||||
|
||||
const float stepHeight = 0.35f;
|
||||
character = new KinematicCharacterController(ghostObject, capsule, stepHeight);
|
||||
World.AddAction(character);
|
||||
|
||||
var bspLoader = new BspLoader();
|
||||
bspLoader.LoadBspFile(Path.Combine("data", "BspDemo.bsp"));
|
||||
var bsp2Bullet = new BspToBulletConverter(this);
|
||||
bsp2Bullet.ConvertBsp(bspLoader, 0.1f);
|
||||
|
||||
convexResultCallback = new ClosestConvexResultCallback();
|
||||
convexResultCallback.CollisionFilterMask = (short)CollisionFilterGroups.StaticFilter;
|
||||
cameraSphere = new SphereShape(0.2f);
|
||||
}
|
||||
|
||||
public override void ClientResetScene()
|
||||
{
|
||||
World.Broadphase.OverlappingPairCache.CleanProxyFromPairs(ghostObject.BroadphaseHandle, World.Dispatcher);
|
||||
|
||||
character.Reset(World);
|
||||
Vector3 warp = new Vector3(10.210001f, -2.0306311f, 16.576973f);
|
||||
character.Warp(ref warp);
|
||||
}
|
||||
|
||||
public override void OnHandleInput()
|
||||
{
|
||||
Matrix transform = ghostObject.WorldTransform;
|
||||
Matrix transform = simulation.GhostObject.WorldTransform;
|
||||
|
||||
Vector3 forwardDir = new Vector3(transform.M31, transform.M32, transform.M33);
|
||||
forwardDir.Normalize();
|
||||
//Console.WriteLine("forwardDir={0}", forwardDir);
|
||||
|
||||
Vector3 upDir = new Vector3(transform.M21, transform.M22, transform.M23);
|
||||
upDir.Normalize();
|
||||
|
||||
Vector3 walkDirection = Vector3.Zero;
|
||||
const float walkVelocity = 1.1f * 4.0f;
|
||||
float walkSpeed = walkVelocity * FrameDelta * 10;// * 0.0001f;
|
||||
float turnSpeed = FrameDelta * 3;
|
||||
float walkSpeed = walkVelocity * demo.FrameDelta * 10;// * 0.0001f;
|
||||
float turnSpeed = demo.FrameDelta * 3;
|
||||
Vector3 position = transform.Origin;
|
||||
|
||||
if (Input.KeysDown.Contains(Keys.Left))
|
||||
var keysDown = demo.Input.KeysDown;
|
||||
if (keysDown.Count > 0)
|
||||
{
|
||||
transform.Origin = Vector3.Zero;
|
||||
transform *= Matrix.RotationAxis(upDir, -turnSpeed);
|
||||
transform.Origin = position;
|
||||
ghostObject.WorldTransform = transform;
|
||||
}
|
||||
if (Input.KeysDown.Contains(Keys.Right))
|
||||
{
|
||||
transform.Origin = Vector3.Zero;
|
||||
transform *= Matrix.RotationAxis(upDir, turnSpeed);
|
||||
transform.Origin = position;
|
||||
ghostObject.WorldTransform = transform;
|
||||
if (keysDown.Contains(Keys.Left))
|
||||
{
|
||||
transform.Origin = Vector3.Zero;
|
||||
transform *= Matrix.RotationAxis(upDir, -turnSpeed);
|
||||
transform.Origin = position;
|
||||
simulation.GhostObject.WorldTransform = transform;
|
||||
}
|
||||
if (keysDown.Contains(Keys.Right))
|
||||
{
|
||||
transform.Origin = Vector3.Zero;
|
||||
transform *= Matrix.RotationAxis(upDir, turnSpeed);
|
||||
transform.Origin = position;
|
||||
simulation.GhostObject.WorldTransform = transform;
|
||||
}
|
||||
if (keysDown.Contains(Keys.Up))
|
||||
{
|
||||
walkDirection += forwardDir;
|
||||
}
|
||||
if (keysDown.Contains(Keys.Down))
|
||||
{
|
||||
walkDirection -= forwardDir;
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.KeysDown.Contains(Keys.Up))
|
||||
simulation.Character.SetWalkDirection(walkDirection * walkSpeed);
|
||||
|
||||
if (demo.Input.KeysPressed.Contains(Keys.Space))
|
||||
{
|
||||
walkDirection += forwardDir;
|
||||
}
|
||||
if (Input.KeysDown.Contains(Keys.Down))
|
||||
{
|
||||
walkDirection -= forwardDir;
|
||||
demo.Input.KeysPressed.Remove(Keys.Space);
|
||||
simulation.Character.Jump();
|
||||
}
|
||||
|
||||
Vector3 cameraPos = position - forwardDir * 12 + upDir * 5;
|
||||
UpdateCamera(demo, simulation, ref position, ref cameraPos);
|
||||
}
|
||||
|
||||
private void UpdateCamera(Demo demo, CharacterDemoSimulation simulation, ref Vector3 position, ref Vector3 cameraPos)
|
||||
{
|
||||
//use the convex sweep test to find a safe position for the camera (not blocked by static geometry)
|
||||
var convexResultCallback = simulation.ConvexResultCallback;
|
||||
convexResultCallback.ConvexFromWorld = position;
|
||||
convexResultCallback.ConvexToWorld = cameraPos;
|
||||
convexResultCallback.ClosestHitFraction = 1.0f;
|
||||
World.ConvexSweepTest(cameraSphere, Matrix.Translation(position), Matrix.Translation(cameraPos), convexResultCallback);
|
||||
simulation.World.ConvexSweepTest(simulation.CameraSphere,
|
||||
Matrix.Translation(position), Matrix.Translation(cameraPos), convexResultCallback);
|
||||
if (convexResultCallback.HasHit)
|
||||
{
|
||||
cameraPos = Vector3.Lerp(position, cameraPos, convexResultCallback.ClosestHitFraction);
|
||||
}
|
||||
Freelook.SetEyeTarget(cameraPos, position);
|
||||
|
||||
character.SetWalkDirection(walkDirection * walkSpeed);
|
||||
|
||||
if (Input.KeysDown.Contains(Keys.Space))
|
||||
{
|
||||
character.Jump();
|
||||
return;
|
||||
}
|
||||
|
||||
base.OnHandleInput();
|
||||
}
|
||||
|
||||
public override void ExitPhysics()
|
||||
{
|
||||
cameraSphere.Dispose();
|
||||
convexResultCallback.Dispose();
|
||||
|
||||
base.ExitPhysics();
|
||||
demo.FreeLook.Eye = cameraPos;
|
||||
demo.FreeLook.Target = position;
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
internal sealed class CharacterDemoSimulation : ISimulation
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
public CharacterDemoSimulation()
|
||||
{
|
||||
using (Demo demo = new CharacterDemo())
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
Broadphase = new AxisSweep3(new Vector3(-1000, -1000, -1000), new Vector3(1000, 1000, 1000));
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
World.DispatchInfo.AllowedCcdPenetration = 0.0001f;
|
||||
|
||||
CreateCharacter();
|
||||
|
||||
var bspLoader = new BspLoader();
|
||||
bspLoader.LoadBspFile(Path.Combine("data", "BspDemo.bsp"));
|
||||
var bsp2Bullet = new BspToBulletConverter(World);
|
||||
bsp2Bullet.ConvertBsp(bspLoader, 0.1f);
|
||||
|
||||
ConvexResultCallback = new ClosestConvexResultCallback();
|
||||
ConvexResultCallback.CollisionFilterMask = (short)CollisionFilterGroups.StaticFilter;
|
||||
CameraSphere = new SphereShape(0.2f);
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public PairCachingGhostObject GhostObject { get; private set; }
|
||||
public ClosestConvexResultCallback ConvexResultCallback { get; }
|
||||
public SphereShape CameraSphere { get; }
|
||||
public KinematicCharacterController Character { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CameraSphere.Dispose();
|
||||
ConvexResultCallback.Dispose();
|
||||
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateCharacter()
|
||||
{
|
||||
Broadphase.OverlappingPairCache.SetInternalGhostPairCallback(new GhostPairCallback());
|
||||
|
||||
const float characterHeight = 1.75f;
|
||||
const float characterWidth = 1.75f;
|
||||
var capsule = new CapsuleShape(characterWidth, characterHeight);
|
||||
GhostObject = new PairCachingGhostObject()
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
CollisionShape = capsule,
|
||||
CollisionFlags = CollisionFlags.CharacterObject,
|
||||
WorldTransform = Matrix.Translation(10.210098f, -1.6433364f, 16.453260f)
|
||||
};
|
||||
World.AddCollisionObject(GhostObject, CollisionFilterGroups.CharacterFilter, CollisionFilterGroups.StaticFilter | CollisionFilterGroups.DefaultFilter);
|
||||
|
||||
const float stepHeight = 0.35f;
|
||||
Character = new KinematicCharacterController(GhostObject, capsule, stepHeight);
|
||||
World.AddAction(Character);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class BspToBulletConverter : BspConverter
|
||||
{
|
||||
private DynamicsWorld _world;
|
||||
|
||||
public BspToBulletConverter(DynamicsWorld world)
|
||||
{
|
||||
_world = world;
|
||||
}
|
||||
|
||||
public override void AddCollider(List<Vector3> vertices)
|
||||
{
|
||||
if (vertices.Count == 0) return;
|
||||
|
||||
var verticesTransformed = vertices.Select(v => new Vector3(0.5f * v.X, 0.375f * v.Z, -0.5f * v.Y));
|
||||
var shape = new ConvexHullShape(verticesTransformed);
|
||||
|
||||
const float mass = 0.0f;
|
||||
Matrix startTransform = Matrix.Translation(0, -10.0f, 0); // shift
|
||||
PhysicsHelper.CreateBody(mass, startTransform, shape, _world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,94 +5,104 @@ using System;
|
|||
|
||||
namespace CollisionInterfaceDemo
|
||||
{
|
||||
class CollisionInterfaceDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(6, 4, 1);
|
||||
Vector3 target = new Vector3(0, 3, 0);
|
||||
|
||||
CollisionObject objectA, objectB;
|
||||
DrawingResult renderCallback;
|
||||
|
||||
Vector3 boxMin = new Vector3(-1, -1, -1);
|
||||
Vector3 boxMax = new Vector3(1, 1, 1);
|
||||
Vector3 white = new Vector3(1, 1, 1);
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
DemoRunner.Run<CollisionInterfaceDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Collision Interface Demo");
|
||||
internal sealed class CollisionInterfaceDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
private Vector3 _white = new Vector3(1, 1, 1);
|
||||
|
||||
IsDebugDrawEnabled = true;
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
demo.FreeLook.Eye = new Vector3(6, 4, 1);
|
||||
demo.FreeLook.Target = new Vector3(0, 3, 0);
|
||||
demo.IsDebugDrawEnabled = true;
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Collision Interface Demo";
|
||||
return new CollisionInterfaceDemoSimulation();
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
var simulation = demo.Simulation as CollisionInterfaceDemoSimulation;
|
||||
CollisionObject movingObject = simulation.MovingObject;
|
||||
|
||||
Matrix transform = movingObject.WorldTransform;
|
||||
Vector3 position = transform.Origin;
|
||||
transform.Origin = Vector3.Zero;
|
||||
transform *= Matrix.RotationYawPitchRoll(0.1f * demo.FrameDelta, 0.05f * demo.FrameDelta, 0);
|
||||
transform.Origin = position;
|
||||
movingObject.WorldTransform = transform;
|
||||
|
||||
if (demo.IsDebugDrawEnabled)
|
||||
{
|
||||
simulation.World.DebugDrawObjectRef(ref transform, movingObject.CollisionShape, ref _white);
|
||||
simulation.World.ContactTest(movingObject, simulation.RenderCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class CollisionInterfaceDemoSimulation : ISimulation
|
||||
{
|
||||
private readonly CollisionShape _staticShape;
|
||||
private readonly CollisionObject _staticObject;
|
||||
|
||||
public CollisionInterfaceDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
Broadphase = new AxisSweep3(
|
||||
new Vector3(-1000, -1000, -1000),
|
||||
new Vector3(1000, 1000, 1000));
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
renderCallback = new DrawingResult(World);
|
||||
RenderCallback = new DrawingResult(World);
|
||||
|
||||
var boxA = new BoxShape(1.0f) { Margin = 0 };
|
||||
var boxB = new BoxShape(0.5f) { Margin = 0 };
|
||||
CollisionShapes.Add(boxA);
|
||||
CollisionShapes.Add(boxB);
|
||||
|
||||
Quaternion rotA = new Quaternion(0.739f, -0.204f, 0.587f, 0.257f);
|
||||
rotA.Normalize();
|
||||
|
||||
objectA = new CollisionObject
|
||||
var movingBox = new BoxShape(1.0f) { Margin = 0 };
|
||||
var rotation = Quaternion.RotationYawPitchRoll((float)Math.PI * 0.6f, (float)Math.PI * 0.2f, 0);
|
||||
MovingObject = new CollisionObject
|
||||
{
|
||||
CollisionShape = boxA,
|
||||
WorldTransform = Matrix.RotationQuaternion(rotA) * Matrix.Translation(0, 3, 0)
|
||||
CollisionShape = movingBox,
|
||||
WorldTransform = Matrix.RotationQuaternion(rotation) * Matrix.Translation(0, 3, 0)
|
||||
};
|
||||
objectB = new CollisionObject
|
||||
|
||||
_staticShape = new BoxShape(0.5f) { Margin = 0 };
|
||||
_staticObject = new CollisionObject
|
||||
{
|
||||
CollisionShape = boxB,
|
||||
CollisionShape = _staticShape,
|
||||
WorldTransform = Matrix.Translation(0, 4.248f, 0)
|
||||
};
|
||||
|
||||
//World.AddCollisionObject(objectA);
|
||||
World.AddCollisionObject(objectB);
|
||||
World.AddCollisionObject(_staticObject);
|
||||
}
|
||||
|
||||
public override void OnUpdate()
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public CollisionObject MovingObject { get; }
|
||||
public DrawingResult RenderCallback { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
base.OnUpdate();
|
||||
RenderCallback.Dispose();
|
||||
_staticObject.Dispose();
|
||||
_staticShape.Dispose();
|
||||
|
||||
Matrix transform = objectA.WorldTransform;
|
||||
Vector3 position = transform.Origin;
|
||||
transform.Origin = Vector3.Zero;
|
||||
transform *= Matrix.RotationYawPitchRoll(0.1f * FrameDelta, 0.05f * FrameDelta, 0);
|
||||
transform.Origin = position;
|
||||
objectA.WorldTransform = transform;
|
||||
|
||||
if (IsDebugDrawEnabled)
|
||||
{
|
||||
World.DebugDrawer.DrawBox(ref boxMin, ref boxMax, ref transform, ref white);
|
||||
World.ContactTest(objectA, renderCallback);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExitPhysics()
|
||||
{
|
||||
renderCallback.Dispose();
|
||||
|
||||
base.ExitPhysics();
|
||||
this.StandardCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
class DrawingResult : ContactResultCallback
|
||||
{
|
||||
private Vector3 _blue = new Vector3(0, 0, 1);
|
||||
private Vector3 _red = new Vector3(1, 0, 0);
|
||||
private DynamicsWorld _world;
|
||||
|
||||
public DrawingResult(DynamicsWorld world)
|
||||
|
@ -106,20 +116,8 @@ namespace CollisionInterfaceDemo
|
|||
{
|
||||
Vector3 ptA = cp.PositionWorldOnA;
|
||||
Vector3 ptB = cp.PositionWorldOnB;
|
||||
_world.DebugDrawer.DrawLine(ref ptA, ref ptB, ref _blue);
|
||||
_world.DebugDrawer.DrawLine(ref ptA, ref ptB, ref _red);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new CollisionInterfaceDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +1,150 @@
|
|||
using BulletSharp.Math;
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using DemoFramework;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using BulletSharp;
|
||||
using DemoFramework;
|
||||
|
||||
namespace ConcaveConvexCastDemo
|
||||
{
|
||||
class ConcaveConvexCastDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(0, 15, 60);
|
||||
Vector3 target = new Vector3(-5, 5, 0);
|
||||
|
||||
const DebugDrawModes debugMode = DebugDrawModes.None;
|
||||
|
||||
const float TriangleSize = 8.0f;
|
||||
const int NumVertsX = 30;
|
||||
const int NumVertsY = 30;
|
||||
const float WaveHeight = 5.0f;
|
||||
static float groundOffset = 0.0f;
|
||||
bool animatedMesh = true;
|
||||
const int NumDynamicBoxesX = 30;
|
||||
const int NumDynamicBoxesY = 30;
|
||||
|
||||
Vector3 worldMin = new Vector3(-1000, -1000, -1000);
|
||||
Vector3 worldMax = new Vector3(1000, 1000, 1000);
|
||||
|
||||
TriangleIndexVertexArray indexVertexArrays;
|
||||
BvhTriangleMeshShape groundShape;
|
||||
ConvexcastBatch convexcastBatch;
|
||||
RigidBody staticBody;
|
||||
ClosestConvexResultCallback callback;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
DemoRunner.Run<ConcaveConvexCastDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Concave Convexcast Demo");
|
||||
internal sealed class ConcaveConvexCastDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
private float _groundOffset = 0;
|
||||
|
||||
IsDebugDrawEnabled = true;
|
||||
DebugDrawMode = debugMode;
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
_groundOffset = 0;
|
||||
demo.FreeLook.Eye = new Vector3(0, 15, 60);
|
||||
demo.FreeLook.Target = new Vector3(-5, 5, 0);
|
||||
demo.IsDebugDrawEnabled = true;
|
||||
demo.DebugDrawMode = DebugDrawModes.None;
|
||||
demo.DemoText = "G - Toggle animation";
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Concave Convexcast Demo";
|
||||
return new ConcaveConvexCastDemoSimulation();
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
var simulation = demo.Simulation as ConcaveConvexCastDemoSimulation;
|
||||
if (demo.Input.KeysPressed.Contains(Keys.G))
|
||||
{
|
||||
simulation.IsGroundAnimated = !simulation.IsGroundAnimated;
|
||||
}
|
||||
|
||||
Broadphase = new AxisSweep3(worldMin, worldMax);
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
if (simulation.IsGroundAnimated)
|
||||
{
|
||||
_groundOffset += demo.FrameDelta;
|
||||
simulation.SetGroundAnimationOffset(_groundOffset);
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
demo.Graphics.MeshFactory.RemoveShape(simulation.GroundShape);
|
||||
}
|
||||
|
||||
if (demo.IsDebugDrawEnabled)
|
||||
{
|
||||
simulation.Convexcast(demo.FrameDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ConcaveConvexCastDemoSimulation : ISimulation
|
||||
{
|
||||
private const float TriangleSize = 8.0f;
|
||||
private const int NumVertsX = 30;
|
||||
private const int NumVertsY = 30;
|
||||
private const float WaveHeight = 3.0f;
|
||||
private const int NumDynamicBoxesX = 30;
|
||||
private const int NumDynamicBoxesY = 30;
|
||||
|
||||
private bool _animatedMesh = true;
|
||||
|
||||
private Vector3 _worldMin = new Vector3(-1000, -1000, -1000);
|
||||
private Vector3 _worldMax = new Vector3(1000, 1000, 1000);
|
||||
|
||||
private TriangleIndexVertexArray _indexVertexArrays;
|
||||
private ConvexcastBatch _convexcastBatch;
|
||||
private RigidBody _groundObject;
|
||||
private ClosestConvexResultCallback _callback;
|
||||
|
||||
public ConcaveConvexCastDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
Broadphase = new AxisSweep3(_worldMin, _worldMax);
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
World.SolverInfo.SplitImpulse = 1;
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
|
||||
convexcastBatch = new ConvexcastBatch(40.0f, 0.0f, -10.0f, 80.0f);
|
||||
callback = new ClosestConvexResultCallback();
|
||||
_convexcastBatch = new ConvexcastBatch(40.0f, 0.0f, -10.0f, 80.0f);
|
||||
_callback = new ClosestConvexResultCallback();
|
||||
|
||||
CreateGround();
|
||||
CreateBoxes();
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public BvhTriangleMeshShape GroundShape { get; private set; }
|
||||
|
||||
public bool IsGroundAnimated
|
||||
{
|
||||
get { return _animatedMesh; }
|
||||
set
|
||||
{
|
||||
_animatedMesh = value;
|
||||
if (value)
|
||||
{
|
||||
_groundObject.CollisionFlags |= CollisionFlags.KinematicObject;
|
||||
_groundObject.ActivationState = ActivationState.DisableDeactivation;
|
||||
}
|
||||
else
|
||||
{
|
||||
_groundObject.CollisionFlags &= ~CollisionFlags.KinematicObject;
|
||||
_groundObject.ActivationState = ActivationState.ActiveTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetGroundAnimationOffset(float offset)
|
||||
{
|
||||
SetVertexPositions(WaveHeight, offset);
|
||||
|
||||
GroundShape.RefitTreeRef(ref _worldMin, ref _worldMax);
|
||||
|
||||
// Clear all contact points involving mesh proxy.
|
||||
// Note: this is a slow/unoptimized operation.
|
||||
Broadphase.OverlappingPairCache.CleanProxyFromPairs(_groundObject.BroadphaseHandle, Dispatcher);
|
||||
}
|
||||
|
||||
public void Convexcast(float frameDelta)
|
||||
{
|
||||
_convexcastBatch.Move(frameDelta);
|
||||
_convexcastBatch.Cast(World, _callback, frameDelta);
|
||||
_convexcastBatch.Draw(World.DebugDrawer);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_callback.Dispose();
|
||||
_indexVertexArrays.IndexedMeshArray[0].Dispose();
|
||||
_indexVertexArrays.Dispose();
|
||||
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
const int totalVerts = NumVertsX * NumVertsY;
|
||||
|
@ -93,63 +175,38 @@ namespace ConcaveConvexCastDemo
|
|||
}
|
||||
}
|
||||
|
||||
indexVertexArrays = new TriangleIndexVertexArray();
|
||||
indexVertexArrays.AddIndexedMesh(mesh);
|
||||
_indexVertexArrays = new TriangleIndexVertexArray();
|
||||
_indexVertexArrays.AddIndexedMesh(mesh);
|
||||
|
||||
SetVertexPositions(WaveHeight, 0.0f);
|
||||
|
||||
const bool useQuantizedAabbCompression = true;
|
||||
groundShape = new BvhTriangleMeshShape(indexVertexArrays, useQuantizedAabbCompression);
|
||||
CollisionShapes.Add(groundShape);
|
||||
GroundShape = new BvhTriangleMeshShape(_indexVertexArrays, useQuantizedAabbCompression);
|
||||
|
||||
staticBody = LocalCreateRigidBody(0.0f, Matrix.Identity, groundShape);
|
||||
staticBody.CollisionFlags |= CollisionFlags.StaticObject;
|
||||
staticBody.UserObject = "Ground";
|
||||
_groundObject = PhysicsHelper.CreateStaticBody(Matrix.Identity, GroundShape, World);
|
||||
_groundObject.CollisionFlags |= CollisionFlags.StaticObject;
|
||||
_groundObject.UserObject = "Ground";
|
||||
}
|
||||
|
||||
private void CreateBoxes()
|
||||
{
|
||||
var colShape = new BoxShape(1);
|
||||
//var colShape = new CapsuleShape(0.5f, 2.0f);//boxShape = new SphereShape(1.0f);
|
||||
CollisionShapes.Add(colShape);
|
||||
var shape = new BoxShape(1);
|
||||
//var shape = new CapsuleShape(0.5f, 2.0f);
|
||||
//var shape = new SphereShape(1.0f);
|
||||
|
||||
for (int j = 0; j < NumDynamicBoxesX; j++)
|
||||
{
|
||||
for (int i = 0; i < NumDynamicBoxesY; i++)
|
||||
{
|
||||
Matrix startTransform = Matrix.Translation(5 * (i - NumDynamicBoxesX / 2), 10, 5 * (j - NumDynamicBoxesY / 2));
|
||||
LocalCreateRigidBody(1.0f, startTransform, colShape);
|
||||
PhysicsHelper.CreateBody(1.0f, startTransform, shape, World);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnUpdate()
|
||||
private void SetVertexPositions(float waveHeight, float offset)
|
||||
{
|
||||
if (animatedMesh)
|
||||
{
|
||||
groundOffset += FrameDelta;
|
||||
SetVertexPositions(WaveHeight, groundOffset);
|
||||
Graphics.MeshFactory.RemoveShape(groundShape);
|
||||
|
||||
groundShape.RefitTreeRef(ref worldMin, ref worldMax);
|
||||
|
||||
//clear all contact points involving mesh proxy. Note: this is a slow/unoptimized operation.
|
||||
Broadphase.OverlappingPairCache.CleanProxyFromPairs(staticBody.BroadphaseHandle, Dispatcher);
|
||||
}
|
||||
|
||||
convexcastBatch.Move(FrameDelta);
|
||||
convexcastBatch.Cast(World, callback, FrameDelta);
|
||||
if (IsDebugDrawEnabled)
|
||||
{
|
||||
convexcastBatch.Draw(World.DebugDrawer);
|
||||
}
|
||||
|
||||
base.OnUpdate();
|
||||
}
|
||||
|
||||
void SetVertexPositions(float waveheight, float offset)
|
||||
{
|
||||
var vertexStream = indexVertexArrays.GetVertexStream();
|
||||
var vertexStream = _indexVertexArrays.GetVertexStream();
|
||||
using (var vertexWriter = new BinaryWriter(vertexStream))
|
||||
{
|
||||
for (int i = 0; i < NumVertsX; i++)
|
||||
|
@ -157,65 +214,43 @@ namespace ConcaveConvexCastDemo
|
|||
for (int j = 0; j < NumVertsY; j++)
|
||||
{
|
||||
vertexWriter.Write((i - NumVertsX * 0.5f) * TriangleSize);
|
||||
vertexWriter.Write(waveheight * (float)Math.Sin(i + offset) * (float)Math.Cos(j + offset));
|
||||
vertexWriter.Write(waveHeight * (float)Math.Sin(i + offset) * (float)Math.Cos(j + offset));
|
||||
vertexWriter.Write((j - NumVertsY * 0.5f) * TriangleSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnHandleInput()
|
||||
{
|
||||
if (Input.KeysPressed.Contains(Keys.G))
|
||||
{
|
||||
animatedMesh = !animatedMesh;
|
||||
if (animatedMesh)
|
||||
{
|
||||
staticBody.CollisionFlags |= CollisionFlags.KinematicObject;
|
||||
staticBody.ActivationState = ActivationState.DisableDeactivation;
|
||||
}
|
||||
else
|
||||
{
|
||||
staticBody.CollisionFlags &= ~CollisionFlags.KinematicObject;
|
||||
staticBody.ActivationState = ActivationState.ActiveTag;
|
||||
}
|
||||
}
|
||||
base.OnHandleInput();
|
||||
}
|
||||
|
||||
public override void ExitPhysics()
|
||||
{
|
||||
callback.Dispose();
|
||||
|
||||
base.ExitPhysics();
|
||||
}
|
||||
}
|
||||
|
||||
// Scrolls back and forth over terrain
|
||||
class ConvexcastBatch
|
||||
internal sealed class ConvexcastBatch
|
||||
{
|
||||
const int NumRays = 100;
|
||||
Ray[] _rays = new Ray[NumRays];
|
||||
private const int NumRays = 100;
|
||||
private Ray[] _rays = new Ray[NumRays];
|
||||
|
||||
int _frameCount;
|
||||
float _time;
|
||||
float _timeMin = float.MaxValue;
|
||||
float _timeMax;
|
||||
float _timeTotal;
|
||||
int _sampleCount;
|
||||
private int _frameCount;
|
||||
private float _time;
|
||||
private float _timeMin = float.MaxValue;
|
||||
private float _timeMax;
|
||||
private float _timeTotal;
|
||||
private int _sampleCount;
|
||||
|
||||
float _dx = 10;
|
||||
float _minX = -40;
|
||||
float _maxX = 20;
|
||||
float _sign = 1;
|
||||
private float _dx = 10;
|
||||
private float _minX = -40;
|
||||
private float _maxX = 20;
|
||||
private float _sign = 1;
|
||||
|
||||
Vector3 _boxBoundMin, _boxBoundMax;
|
||||
BoxShape _boxShape;
|
||||
private Vector3 _boxBoundMin, _boxBoundMax;
|
||||
private BoxShape _boxShape;
|
||||
|
||||
const float NormalScale = 10.0f; // easier to see if this is big
|
||||
private const float NormalScale = 10.0f; // easier to see if this is big
|
||||
|
||||
Matrix _fromRotation = Matrix.Identity; //Matrix.RotationX(0.7f);
|
||||
Matrix _toRotation = Matrix.RotationX(0.7f);
|
||||
private Matrix _fromRotation = Matrix.Identity; //Matrix.RotationX(0.7f);
|
||||
private Matrix _toRotation = Matrix.RotationX(0.7f);
|
||||
|
||||
private static Vector3 _green = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
private static Vector3 _white = new Vector3(1.0f, 1.0f, 1.0f);
|
||||
private static Vector3 _cyan = new Vector3(0.0f, 1.0f, 1.0f);
|
||||
|
||||
public ConvexcastBatch(float rayLength, float z, float minY, float maxY)
|
||||
{
|
||||
|
@ -300,21 +335,6 @@ namespace ConcaveConvexCastDemo
|
|||
}
|
||||
}
|
||||
|
||||
private void PrintStats()
|
||||
{
|
||||
float timeMean = _timeTotal / _sampleCount;
|
||||
Console.WriteLine("{0} rays in {1} s, min {2}, max {3}, mean {4}",
|
||||
NumRays * _frameCount,
|
||||
_time.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
_timeMin.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
_timeMax.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
timeMean.ToString("0.000", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
static Vector3 _green = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
static Vector3 _white = new Vector3(1.0f, 1.0f, 1.0f);
|
||||
static Vector3 _cyan = new Vector3(0.0f, 1.0f, 1.0f);
|
||||
|
||||
public void Draw(IDebugDraw drawer)
|
||||
{
|
||||
foreach (var ray in _rays)
|
||||
|
@ -333,9 +353,20 @@ namespace ConcaveConvexCastDemo
|
|||
drawer.DrawBox(ref _boxBoundMin, ref _boxBoundMax, ref transform, ref _cyan);
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintStats()
|
||||
{
|
||||
float timeMean = _timeTotal / _sampleCount;
|
||||
Console.WriteLine("{0} rays in {1} s, min {2}, max {3}, mean {4}",
|
||||
NumRays * _frameCount,
|
||||
_time.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
_timeMin.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
_timeMax.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
timeMean.ToString("0.000", CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
class Ray
|
||||
internal sealed class Ray
|
||||
{
|
||||
public Vector3 Source;
|
||||
public Vector3 Destination;
|
||||
|
@ -350,16 +381,4 @@ namespace ConcaveConvexCastDemo
|
|||
Destination.X += move;
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new ConcaveConvexCastDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,71 +1,146 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using BulletSharp;
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using DemoFramework;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace ConcaveRaycastDemo
|
||||
{
|
||||
class ConcaveRaycastDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(0, 15, 60);
|
||||
Vector3 target = new Vector3(-5, 5, 0);
|
||||
|
||||
const DebugDrawModes debugMode = DebugDrawModes.None;
|
||||
|
||||
const float TriangleSize = 8.0f;
|
||||
const int NumVertsX = 30;
|
||||
const int NumVertsY = 30;
|
||||
const float waveHeight = 5.0f;
|
||||
static float groundOffset = 0.0f;
|
||||
bool animatedMesh = false;
|
||||
|
||||
Vector3 worldMin = new Vector3(-1000, -1000, -1000);
|
||||
Vector3 worldMax = new Vector3(1000, 1000, 1000);
|
||||
|
||||
TriangleIndexVertexArray indexVertexArrays;
|
||||
BvhTriangleMeshShape groundShape;
|
||||
RaycastBar raycastBar;
|
||||
RigidBody staticBody;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
DemoRunner.Run<ConcaveRaycastDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Concave Raycast Demo");
|
||||
Graphics.SetInfoText("Move using mouse and WASD+shift\n" +
|
||||
"F3 - Toggle debug\n" +
|
||||
//"F11 - Toggle fullscreen\n" +
|
||||
"Space - Shoot box");
|
||||
internal sealed class ConcaveRaycastDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
private float _groundOffset = 0;
|
||||
|
||||
IsDebugDrawEnabled = true;
|
||||
DebugDrawMode = debugMode;
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
_groundOffset = 0;
|
||||
demo.FreeLook.Eye = new Vector3(0, 15, 60);
|
||||
demo.FreeLook.Target = new Vector3(-5, 5, 0);
|
||||
demo.IsDebugDrawEnabled = true;
|
||||
demo.DebugDrawMode = DebugDrawModes.None;
|
||||
demo.DemoText = "G - Toggle animation";
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Concave Raycast Demo";
|
||||
return new ConcaveRaycastDemoSimulation();
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
var simulation = demo.Simulation as ConcaveRaycastDemoSimulation;
|
||||
if (demo.Input.KeysPressed.Contains(Keys.G))
|
||||
{
|
||||
simulation.IsGroundAnimated = !simulation.IsGroundAnimated;
|
||||
}
|
||||
|
||||
Broadphase = new AxisSweep3(worldMin, worldMax);
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
if (simulation.IsGroundAnimated)
|
||||
{
|
||||
_groundOffset += demo.FrameDelta;
|
||||
simulation.SetGroundAnimationOffset(_groundOffset);
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
demo.Graphics.MeshFactory.RemoveShape(simulation.GroundShape);
|
||||
}
|
||||
|
||||
if (demo.IsDebugDrawEnabled)
|
||||
{
|
||||
simulation.Raycast(demo.FrameDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ConcaveRaycastDemoSimulation : ISimulation
|
||||
{
|
||||
private const float TriangleSize = 8.0f;
|
||||
private const int NumVertsX = 30;
|
||||
private const int NumVertsY = 30;
|
||||
private const float WaveHeight = 3.0f;
|
||||
|
||||
private bool _animatedMesh = false;
|
||||
|
||||
private Vector3 _worldMin = new Vector3(-1000, -1000, -1000);
|
||||
private Vector3 _worldMax = new Vector3(1000, 1000, 1000);
|
||||
|
||||
private TriangleIndexVertexArray _indexVertexArrays;
|
||||
private RaycastBar _raycastBar;
|
||||
private RigidBody _groundObject;
|
||||
|
||||
public ConcaveRaycastDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
Broadphase = new AxisSweep3(_worldMin, _worldMax);
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
World.SolverInfo.SplitImpulse = 1;
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
|
||||
raycastBar = new RaycastBar(4000.0f, 0.0f, -1000.0f, 10);
|
||||
//raycastBar = new RaycastBar(true, 40.0f, -50.0f, 50.0f);
|
||||
_raycastBar = new RaycastBar(4000.0f, 0.0f, -1000.0f, 10);
|
||||
//_raycastBar = new RaycastBar(true, 40.0f, -50.0f, 50.0f);
|
||||
|
||||
CreateBoxes();
|
||||
CreateGround();
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public BvhTriangleMeshShape GroundShape { get; private set; }
|
||||
|
||||
public bool IsGroundAnimated
|
||||
{
|
||||
get { return _animatedMesh; }
|
||||
set
|
||||
{
|
||||
_animatedMesh = value;
|
||||
if (value)
|
||||
{
|
||||
_groundObject.CollisionFlags |= CollisionFlags.KinematicObject;
|
||||
_groundObject.ActivationState = ActivationState.DisableDeactivation;
|
||||
}
|
||||
else
|
||||
{
|
||||
_groundObject.CollisionFlags &= ~CollisionFlags.KinematicObject;
|
||||
_groundObject.ActivationState = ActivationState.ActiveTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetGroundAnimationOffset(float offset)
|
||||
{
|
||||
SetVertexPositions(WaveHeight, offset);
|
||||
|
||||
GroundShape.RefitTreeRef(ref _worldMin, ref _worldMax);
|
||||
|
||||
// Clear all contact points involving mesh proxy.
|
||||
// Note: this is a slow/unoptimized operation.
|
||||
Broadphase.OverlappingPairCache.CleanProxyFromPairs(_groundObject.BroadphaseHandle, Dispatcher);
|
||||
}
|
||||
|
||||
public void Raycast(float frameDelta)
|
||||
{
|
||||
_raycastBar.Move(frameDelta);
|
||||
_raycastBar.Cast(World, frameDelta);
|
||||
_raycastBar.Draw(World.DebugDrawer);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_indexVertexArrays.IndexedMeshArray[0].Dispose();
|
||||
_indexVertexArrays.Dispose();
|
||||
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
const int totalVerts = NumVertsX * NumVertsY;
|
||||
|
@ -96,79 +171,35 @@ namespace ConcaveRaycastDemo
|
|||
}
|
||||
}
|
||||
|
||||
indexVertexArrays = new TriangleIndexVertexArray();
|
||||
indexVertexArrays.AddIndexedMesh(mesh);
|
||||
_indexVertexArrays = new TriangleIndexVertexArray();
|
||||
_indexVertexArrays.AddIndexedMesh(mesh);
|
||||
|
||||
SetVertexPositions(waveHeight, 0.0f);
|
||||
SetVertexPositions(WaveHeight, 0.0f);
|
||||
|
||||
const bool useQuantizedAabbCompression = true;
|
||||
groundShape = new BvhTriangleMeshShape(indexVertexArrays, useQuantizedAabbCompression);
|
||||
CollisionShapes.Add(groundShape);
|
||||
GroundShape = new BvhTriangleMeshShape(_indexVertexArrays, useQuantizedAabbCompression);
|
||||
|
||||
staticBody = LocalCreateRigidBody(0.0f, Matrix.Identity, groundShape);
|
||||
staticBody.CollisionFlags |= CollisionFlags.StaticObject;
|
||||
staticBody.UserObject = "Ground";
|
||||
_groundObject = PhysicsHelper.CreateStaticBody(Matrix.Identity, GroundShape, World);
|
||||
_groundObject.CollisionFlags |= CollisionFlags.StaticObject;
|
||||
_groundObject.UserObject = "Ground";
|
||||
}
|
||||
|
||||
private void CreateBoxes()
|
||||
{
|
||||
var colShape = new BoxShape(1);
|
||||
CollisionShapes.Add(colShape);
|
||||
var shape = new BoxShape(1);
|
||||
//var shape = new CapsuleShape(0.5f, 2.0f);
|
||||
//var shape = new SphereShape(1.0f);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
//CollisionShape colShape = new CapsuleShape(0.5f,2.0f);//boxShape = new SphereShape(1.0f);
|
||||
Matrix startTransform = Matrix.Translation(2 * i, 10, 1);
|
||||
LocalCreateRigidBody(1.0f, startTransform, colShape);
|
||||
PhysicsHelper.CreateBody(1.0f, startTransform, shape, World);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnUpdate()
|
||||
private void SetVertexPositions(float waveheight, float offset)
|
||||
{
|
||||
if (animatedMesh)
|
||||
{
|
||||
groundOffset += FrameDelta;
|
||||
SetVertexPositions(waveHeight, groundOffset);
|
||||
Graphics.MeshFactory.RemoveShape(groundShape);
|
||||
|
||||
groundShape.RefitTreeRef(ref worldMin, ref worldMax);
|
||||
|
||||
//clear all contact points involving mesh proxy. Note: this is a slow/unoptimized operation.
|
||||
Broadphase.OverlappingPairCache.CleanProxyFromPairs(staticBody.BroadphaseHandle, Dispatcher);
|
||||
}
|
||||
|
||||
raycastBar.Move(FrameDelta);
|
||||
raycastBar.Cast(World, FrameDelta);
|
||||
if (IsDebugDrawEnabled)
|
||||
{
|
||||
raycastBar.Draw(World.DebugDrawer);
|
||||
}
|
||||
|
||||
base.OnUpdate();
|
||||
}
|
||||
|
||||
public override void OnHandleInput()
|
||||
{
|
||||
if (Input.KeysPressed.Contains(Keys.G))
|
||||
{
|
||||
animatedMesh = !animatedMesh;
|
||||
if (animatedMesh)
|
||||
{
|
||||
staticBody.CollisionFlags |= CollisionFlags.KinematicObject;
|
||||
staticBody.ActivationState = ActivationState.DisableDeactivation;
|
||||
}
|
||||
else
|
||||
{
|
||||
staticBody.CollisionFlags &= ~CollisionFlags.KinematicObject;
|
||||
staticBody.ActivationState = ActivationState.ActiveTag;
|
||||
}
|
||||
}
|
||||
base.OnHandleInput();
|
||||
}
|
||||
|
||||
void SetVertexPositions(float waveheight, float offset)
|
||||
{
|
||||
var vertexStream = indexVertexArrays.GetVertexStream();
|
||||
var vertexStream = _indexVertexArrays.GetVertexStream();
|
||||
using (var vertexWriter = new BinaryWriter(vertexStream))
|
||||
{
|
||||
for (int i = 0; i < NumVertsX; i++)
|
||||
|
@ -185,22 +216,25 @@ namespace ConcaveRaycastDemo
|
|||
}
|
||||
|
||||
// Scrolls back and forth over terrain
|
||||
class RaycastBar
|
||||
internal sealed class RaycastBar
|
||||
{
|
||||
const int NumRays = 100;
|
||||
Ray[] _rays = new Ray[NumRays];
|
||||
private const int NumRays = 100;
|
||||
private Ray[] _rays = new Ray[NumRays];
|
||||
|
||||
int _frameCount;
|
||||
float _time;
|
||||
float _timeMin = float.MaxValue;
|
||||
float _timeMax;
|
||||
float _timeTotal;
|
||||
int _sampleCount;
|
||||
private int _frameCount;
|
||||
private float _time;
|
||||
private float _timeMin = float.MaxValue;
|
||||
private float _timeMax;
|
||||
private float _timeTotal;
|
||||
private int _sampleCount;
|
||||
|
||||
float _dx = 10;
|
||||
float _minX = -40;
|
||||
float _maxX = 20;
|
||||
float _sign = 1;
|
||||
private float _dx = 10;
|
||||
private float _minX = -40;
|
||||
private float _maxX = 20;
|
||||
private float _sign = 1;
|
||||
|
||||
private static Vector3 green = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
private static Vector3 white = new Vector3(1.0f, 1.0f, 1.0f);
|
||||
|
||||
public RaycastBar(float rayLength, float z, float minY, float maxY)
|
||||
{
|
||||
|
@ -294,20 +328,6 @@ namespace ConcaveRaycastDemo
|
|||
#endif
|
||||
}
|
||||
|
||||
private void PrintStats()
|
||||
{
|
||||
float timeMean = _timeTotal / _sampleCount;
|
||||
Console.WriteLine("{0} rays in {1} s, min {2}, max {3}, mean {4}",
|
||||
NumRays * _frameCount,
|
||||
_time.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
_timeMin.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
_timeMax.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
timeMean.ToString("0.000", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
static Vector3 green = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
static Vector3 white = new Vector3(1.0f, 1.0f, 1.0f);
|
||||
|
||||
public void Draw(IDebugDraw drawer)
|
||||
{
|
||||
foreach (var ray in _rays)
|
||||
|
@ -318,6 +338,17 @@ namespace ConcaveRaycastDemo
|
|||
drawer.DrawLine(ref ray.HitPoint, ref to, ref white);
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintStats()
|
||||
{
|
||||
float timeMean = _timeTotal / _sampleCount;
|
||||
Console.WriteLine("{0} rays in {1} s, min {2}, max {3}, mean {4}",
|
||||
NumRays * _frameCount,
|
||||
_time.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
_timeMin.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
_timeMax.ToString("0.000", CultureInfo.InvariantCulture),
|
||||
timeMean.ToString("0.000", CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
class Ray
|
||||
|
@ -333,16 +364,4 @@ namespace ConcaveRaycastDemo
|
|||
Destination.X += move;
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new ConcaveRaycastDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,34 +5,43 @@ using System;
|
|||
|
||||
namespace ConstraintDemo
|
||||
{
|
||||
class ConstraintDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(35, 10, 35);
|
||||
Vector3 target = new Vector3(0, 5, 0);
|
||||
|
||||
const DebugDrawModes debugMode = DebugDrawModes.DrawConstraints | DebugDrawModes.DrawConstraintLimits;
|
||||
|
||||
private const float CubeHalfExtent = 1.0f;
|
||||
BoxShape cubeShape;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Constraints Demo");
|
||||
|
||||
IsDebugDrawEnabled = true;
|
||||
DebugDrawMode = debugMode;
|
||||
DemoRunner.Run<ConstraintDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
internal sealed class ConstraintDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
SetupDynamicsWorld();
|
||||
demo.FreeLook.Eye = new Vector3(35, 10, 35);
|
||||
demo.FreeLook.Target = new Vector3(0, 5, 0);
|
||||
demo.IsDebugDrawEnabled = true;
|
||||
demo.DebugDrawMode = DebugDrawModes.DrawConstraints | DebugDrawModes.DrawConstraintLimits;
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Constraints Demo";
|
||||
return new ConstraintDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ConstraintDemoSimulation : ISimulation
|
||||
{
|
||||
private const float CubeHalfExtent = 1.0f;
|
||||
private BoxShape _cubeShape;
|
||||
|
||||
public ConstraintDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Broadphase = new DbvtBroadphase();
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
CreateGround();
|
||||
|
||||
cubeShape = new BoxShape(CubeHalfExtent);
|
||||
CollisionShapes.Add(cubeShape);
|
||||
_cubeShape = new BoxShape(CubeHalfExtent);
|
||||
|
||||
CreateGears();
|
||||
CreateHingedBoxes();
|
||||
|
@ -49,22 +58,21 @@ namespace ConstraintDemo
|
|||
CreateHinge2();
|
||||
}
|
||||
|
||||
void SetupDynamicsWorld()
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
Broadphase = new DbvtBroadphase();
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
var groundShape = new BoxShape(50, 1, 50);
|
||||
//var groundShape = new StaticPlaneShape(Vector3.UnitY, 1);
|
||||
CollisionShapes.Add(groundShape);
|
||||
RigidBody body = LocalCreateRigidBody(0, Matrix.Translation(0, -16, 0), groundShape);
|
||||
RigidBody body = PhysicsHelper.CreateStaticBody(Matrix.Translation(0, -16, 0), groundShape, World);
|
||||
body.UserObject = "Ground";
|
||||
}
|
||||
|
||||
|
@ -106,11 +114,8 @@ namespace ConstraintDemo
|
|||
var wheel = new CylinderShape(radius, 0.025f, radius);
|
||||
shape.AddChildShape(Matrix.Identity, axle);
|
||||
shape.AddChildShape(Matrix.Identity, wheel);
|
||||
CollisionShapes.Add(shape);
|
||||
CollisionShapes.Add(axle);
|
||||
CollisionShapes.Add(wheel);
|
||||
|
||||
RigidBody body = LocalCreateRigidBody(mass, transform, shape);
|
||||
RigidBody body = PhysicsHelper.CreateBody(mass, transform, shape, World);
|
||||
body.LinearFactor = Vector3.Zero;
|
||||
return body;
|
||||
}
|
||||
|
@ -119,8 +124,8 @@ namespace ConstraintDemo
|
|||
{
|
||||
const float mass = 1.0f;
|
||||
|
||||
RigidBody body0 = LocalCreateRigidBody(mass, Matrix.Translation(0, 24, 0), cubeShape);
|
||||
RigidBody body1 = LocalCreateRigidBody(mass, Matrix.Translation(2 * CubeHalfExtent, 24, 0), cubeShape);
|
||||
RigidBody body0 = PhysicsHelper.CreateBody(mass, Matrix.Translation(0, 24, 0), _cubeShape, World);
|
||||
RigidBody body1 = PhysicsHelper.CreateBody(mass, Matrix.Translation(2 * CubeHalfExtent, 24, 0), _cubeShape, World);
|
||||
|
||||
Vector3 pivotInA = new Vector3(CubeHalfExtent, -CubeHalfExtent, -CubeHalfExtent);
|
||||
Vector3 axisInA = new Vector3(0, 0, 1);
|
||||
|
@ -143,7 +148,7 @@ namespace ConstraintDemo
|
|||
private void CreateMotorHinge()
|
||||
{
|
||||
const float mass = 1.0f;
|
||||
RigidBody body = LocalCreateRigidBody(mass, Matrix.Translation(0, 20, 0), cubeShape);
|
||||
RigidBody body = PhysicsHelper.CreateBody(mass, Matrix.Translation(0, 20, 0), _cubeShape, World);
|
||||
|
||||
Vector3 pivotInA = new Vector3(CubeHalfExtent, -CubeHalfExtent, -CubeHalfExtent);
|
||||
Vector3 axisInA = new Vector3(0, 0, 1);
|
||||
|
@ -162,7 +167,7 @@ namespace ConstraintDemo
|
|||
|
||||
private void CreateMotorHinge2()
|
||||
{
|
||||
RigidBody body = LocalCreateRigidBody(1.0f, Matrix.Identity, cubeShape);
|
||||
RigidBody body = PhysicsHelper.CreateBody(1.0f, Matrix.Identity, _cubeShape, World);
|
||||
body.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
Vector3 pivotInA = new Vector3(10.0f, 0.0f, 0.0f);
|
||||
|
@ -178,14 +183,14 @@ namespace ConstraintDemo
|
|||
|
||||
private void CreateSlider()
|
||||
{
|
||||
float mass = 1.0f;
|
||||
const float mass = 1.0f;
|
||||
|
||||
RigidBody bodyA = LocalCreateRigidBody(mass, Matrix.Translation(-20, 0, 15), cubeShape);
|
||||
RigidBody bodyA = PhysicsHelper.CreateBody(mass, Matrix.Translation(-20, 0, 15), _cubeShape, World);
|
||||
bodyA.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
// add dynamic rigid body B1
|
||||
RigidBody bodyB = LocalCreateRigidBody(0, Matrix.Translation(-30, 0, 15), cubeShape);
|
||||
//RigidBody bodyB = LocalCreateRigidBody(mass, Matrix.Translation(-20, 0, 15), cubeShape);
|
||||
RigidBody bodyB = PhysicsHelper.CreateBody(0, Matrix.Translation(-30, 0, 15), _cubeShape, World);
|
||||
//RigidBody bodyB = PhysicsHelper.CreateBody(mass, Matrix.Translation(-20, 0, 15), cubeShape, World);
|
||||
bodyB.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
// create slider constraint between A1 and B1 and add it to world
|
||||
|
@ -210,11 +215,10 @@ namespace ConstraintDemo
|
|||
Vector3 sliderAxis = Vector3.UnitX;
|
||||
const float angle = (float)Math.PI / 4;
|
||||
Matrix trans = Matrix.RotationAxis(sliderAxis, angle) * Matrix.Translation(0, 10, 0);
|
||||
RigidBody body = LocalCreateRigidBody(mass, trans, cubeShape);
|
||||
RigidBody body = PhysicsHelper.CreateBody(mass, trans, _cubeShape, World);
|
||||
body.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
RigidBody fixedBody = LocalCreateRigidBody(0, trans, null);
|
||||
World.AddRigidBody(fixedBody);
|
||||
RigidBody fixedBody = PhysicsHelper.CreateStaticBody(trans, null, World);
|
||||
|
||||
Matrix frameInA = Matrix.Translation(0, 5, 0);
|
||||
Matrix frameInB = Matrix.Translation(0, 5, 0);
|
||||
|
@ -222,8 +226,8 @@ namespace ConstraintDemo
|
|||
Vector3 lowerSliderLimit = new Vector3(-10, 0, 0);
|
||||
Vector3 hiSliderLimit = new Vector3(10, 0, 0);
|
||||
|
||||
//const bool useLinearReferenceFrameA = false; //use fixed frame B for linear llimits
|
||||
const bool useLinearReferenceFrameA = true; //use fixed frame A for linear llimits
|
||||
//const bool useLinearReferenceFrameA = false; //use fixed frame B for linear limits
|
||||
const bool useLinearReferenceFrameA = true; //use fixed frame A for linear limits
|
||||
var slider = new Generic6DofConstraint(fixedBody, body, frameInA, frameInB, useLinearReferenceFrameA)
|
||||
{
|
||||
LinearLowerLimit = lowerSliderLimit,
|
||||
|
@ -252,8 +256,7 @@ namespace ConstraintDemo
|
|||
const float mass = 1.0f;
|
||||
|
||||
var doorShape = new BoxShape(2.0f, 5.0f, 0.2f);
|
||||
CollisionShapes.Add(doorShape);
|
||||
RigidBody doorBody = LocalCreateRigidBody(mass, Matrix.Translation(-5.0f, -2.0f, 0.0f), doorShape);
|
||||
RigidBody doorBody = PhysicsHelper.CreateBody(mass, Matrix.Translation(-5.0f, -2.0f, 0.0f), doorShape, World);
|
||||
doorBody.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
var pivotA = new Vector3(10.0f + 2.1f, -2.0f, 0.0f); // right next to the door slightly outside
|
||||
|
@ -278,10 +281,10 @@ namespace ConstraintDemo
|
|||
{
|
||||
const float mass = 1.0f;
|
||||
|
||||
RigidBody fixedBody = LocalCreateRigidBody(0, Matrix.Translation(10, 6, 0), cubeShape);
|
||||
RigidBody fixedBody = PhysicsHelper.CreateBody(0, Matrix.Translation(10, 6, 0), _cubeShape, World);
|
||||
fixedBody.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
RigidBody dynamicbody = LocalCreateRigidBody(mass, Matrix.Translation(0, 6, 0), cubeShape);
|
||||
RigidBody dynamicbody = PhysicsHelper.CreateBody(mass, Matrix.Translation(0, 6, 0), _cubeShape, World);
|
||||
dynamicbody.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
Matrix frameInA = Matrix.Translation(-5, 0, 0);
|
||||
|
@ -326,12 +329,12 @@ namespace ConstraintDemo
|
|||
|
||||
private void CreateConeTwist()
|
||||
{
|
||||
RigidBody bodyA = LocalCreateRigidBody(1.0f, Matrix.Translation(-10, 5, 0), cubeShape);
|
||||
//bodyA = LocalCreateRigidBody(0, Matrix.Translation(-10, 5, 0), cubeShape);
|
||||
RigidBody bodyA = PhysicsHelper.CreateBody(1.0f, Matrix.Translation(-10, 5, 0), _cubeShape, World);
|
||||
//bodyA = PhysicsHelper.CreateStaticBody(Matrix.Translation(-10, 5, 0), cubeShape, World);
|
||||
bodyA.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
RigidBody bodyB = LocalCreateRigidBody(0, Matrix.Translation(-10, -5, 0), cubeShape);
|
||||
//bodyB = LocalCreateRigidBody(1.0f, Matrix.Translation(-10, -5, 0), cubeShape);
|
||||
RigidBody bodyB = PhysicsHelper.CreateStaticBody(Matrix.Translation(-10, -5, 0), _cubeShape, World);
|
||||
//bodyB = PhysicsHelper.CreateBody(1.0f, Matrix.Translation(-10, -5, 0), cubeShape, World);
|
||||
|
||||
Matrix frameInA = Matrix.RotationYawPitchRoll(0, 0, (float)Math.PI / 2);
|
||||
frameInA *= Matrix.Translation(0, -5, 0);
|
||||
|
@ -350,10 +353,10 @@ namespace ConstraintDemo
|
|||
{
|
||||
// create two rigid bodies
|
||||
// static body A (parent) on top:
|
||||
RigidBody bodyA = LocalCreateRigidBody(0, Matrix.Translation(20, 4, 0), cubeShape);
|
||||
RigidBody bodyA = PhysicsHelper.CreateStaticBody(Matrix.Translation(20, 4, 0), _cubeShape, World);
|
||||
bodyA.ActivationState = ActivationState.DisableDeactivation;
|
||||
// dynamic bodyB (child) below it :
|
||||
RigidBody bodyB = LocalCreateRigidBody(1.0f, Matrix.Translation(20, 0, 0), cubeShape);
|
||||
RigidBody bodyB = PhysicsHelper.CreateBody(1.0f, Matrix.Translation(20, 0, 0), _cubeShape, World);
|
||||
bodyB.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
// add some (arbitrary) data to build constraint frames
|
||||
|
@ -373,10 +376,10 @@ namespace ConstraintDemo
|
|||
|
||||
private void CreateGeneric6DofSpringConstraint()
|
||||
{
|
||||
RigidBody bodyA = LocalCreateRigidBody(0, Matrix.Translation(-20, 16, 0), cubeShape);
|
||||
RigidBody bodyA = PhysicsHelper.CreateStaticBody(Matrix.Translation(-20, 16, 0), _cubeShape, World);
|
||||
bodyA.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
RigidBody bodyB = LocalCreateRigidBody(1.0f, Matrix.Translation(-10, 16, 0), cubeShape);
|
||||
RigidBody bodyB = PhysicsHelper.CreateBody(1.0f, Matrix.Translation(-10, 16, 0), _cubeShape, World);
|
||||
bodyB.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
Matrix frameInA = Matrix.Translation(10, 0, 0);
|
||||
|
@ -406,10 +409,10 @@ namespace ConstraintDemo
|
|||
private void CreateHinge()
|
||||
{
|
||||
// static body (parent) on top
|
||||
RigidBody bodyA = LocalCreateRigidBody(1.0f, Matrix.Translation(-20, -2, 0), cubeShape);
|
||||
RigidBody bodyA = PhysicsHelper.CreateBody(1.0f, Matrix.Translation(-20, -2, 0), _cubeShape, World);
|
||||
bodyA.ActivationState = ActivationState.DisableDeactivation;
|
||||
// dynamic body
|
||||
RigidBody bodyB = LocalCreateRigidBody(10.0f, Matrix.Translation(-30, -2, 0), cubeShape);
|
||||
RigidBody bodyB = PhysicsHelper.CreateBody(10.0f, Matrix.Translation(-30, -2, 0), _cubeShape, World);
|
||||
bodyB.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
// add some data to build constraint frames
|
||||
|
@ -429,10 +432,10 @@ namespace ConstraintDemo
|
|||
private void CreateHinge2()
|
||||
{
|
||||
// static bodyA (parent) on top
|
||||
RigidBody bodyA = LocalCreateRigidBody(0, Matrix.Translation(-20, 4, 0), cubeShape);
|
||||
RigidBody bodyA = PhysicsHelper.CreateStaticBody(Matrix.Translation(-20, 4, 0), _cubeShape, World);
|
||||
bodyA.ActivationState = ActivationState.DisableDeactivation;
|
||||
// dynamic bodyB (child) below it
|
||||
RigidBody bodyB = LocalCreateRigidBody(1.0f, Matrix.Translation(-20, 0, 0), cubeShape);
|
||||
RigidBody bodyB = PhysicsHelper.CreateBody(1.0f, Matrix.Translation(-20, 0, 0), _cubeShape, World);
|
||||
bodyB.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
// add some data to build constraint frames
|
||||
|
@ -450,16 +453,4 @@ namespace ConstraintDemo
|
|||
World.AddConstraint(hinge2, true);
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new ConstraintDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +1,31 @@
|
|||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace ConvexDecompositionDemo
|
||||
{
|
||||
class ConvexDecomposition
|
||||
internal sealed class ConvexDecomposition
|
||||
{
|
||||
StreamWriter _output;
|
||||
CultureInfo floatFormat = new CultureInfo("en-US");
|
||||
int baseIndex = 0;
|
||||
private WavefrontWriter _wavefrontWriter;
|
||||
|
||||
public List<ConvexHullShape> convexShapes = new List<ConvexHullShape>();
|
||||
public List<Vector3> convexCentroids = new List<Vector3>();
|
||||
public ConvexDecomposition(WavefrontWriter wavefrontWriter = null)
|
||||
{
|
||||
_wavefrontWriter = wavefrontWriter;
|
||||
}
|
||||
|
||||
public List<ConvexHullShape> ConvexShapes { get; } = new List<ConvexHullShape>();
|
||||
public List<Vector3> ConvexCentroids { get; } = new List<Vector3>();
|
||||
|
||||
public Vector3 LocalScaling { get; set; } = new Vector3(1, 1, 1);
|
||||
|
||||
public ConvexDecomposition(StreamWriter output)
|
||||
public void Result(Vector3[] hullVertices, long[] hullIndices)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
public void Result(Vector3[] hullVertices, int[] hullIndices)
|
||||
{
|
||||
OutputResult(hullVertices, hullIndices);
|
||||
_wavefrontWriter.OutputObject(hullVertices, hullIndices);
|
||||
|
||||
// Calculate centroid, to shift vertices around center of mass
|
||||
Vector3 centroid = CalculateCentroid(hullVertices);
|
||||
convexCentroids.Add(centroid);
|
||||
ConvexCentroids.Add(centroid);
|
||||
|
||||
List<Vector3> outVertices = hullVertices.Select(v => v * LocalScaling - centroid).ToList();
|
||||
|
||||
|
@ -41,33 +37,7 @@ namespace ConvexDecompositionDemo
|
|||
|
||||
var convexShape = new ConvexHullShape(outVertices);
|
||||
convexShape.Margin = 0.01f;
|
||||
convexShapes.Add(convexShape);
|
||||
}
|
||||
|
||||
private void OutputResult(Vector3[] hullVertices, int[] hullIndices)
|
||||
{
|
||||
if (_output == null)
|
||||
return;
|
||||
|
||||
_output.WriteLine("## Hull Piece {0} with {1} vertices and {2} triangles.", convexShapes.Count, hullVertices.Length, hullIndices.Length / 3);
|
||||
|
||||
_output.WriteLine("usemtl Material{0}", baseIndex);
|
||||
_output.WriteLine("o Object{0}", baseIndex);
|
||||
|
||||
foreach (Vector3 p in hullVertices)
|
||||
{
|
||||
_output.WriteLine(string.Format(floatFormat, "v {0:F9} {1:F9} {2:F9}", p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
for (int i = 0; i < hullIndices.Length; i += 3)
|
||||
{
|
||||
int index0 = baseIndex + hullIndices[i];
|
||||
int index1 = baseIndex + hullIndices[i + 1];
|
||||
int index2 = baseIndex + hullIndices[i + 2];
|
||||
|
||||
_output.WriteLine("f {0} {1} {2}", index0 + 1, index1 + 1, index2 + 1);
|
||||
}
|
||||
baseIndex += hullVertices.Length;
|
||||
ConvexShapes.Add(convexShape);
|
||||
}
|
||||
|
||||
private Vector3 CalculateCentroid(ICollection<Vector3> vertices)
|
||||
|
|
|
@ -9,28 +9,121 @@ using System.Windows.Forms;
|
|||
|
||||
namespace ConvexDecompositionDemo
|
||||
{
|
||||
class ConvexDecompositionDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(35, 10, 35);
|
||||
Vector3 target = new Vector3(0, 5, 0);
|
||||
|
||||
TriangleMesh triangleMesh;
|
||||
bool enableSat = false;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
DemoRunner.Run<ConvexDecompositionDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Convex Decomposition Demo");
|
||||
internal sealed class ConvexDecompositionDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
private bool _enableSat = false;
|
||||
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
demo.FreeLook.Eye = new Vector3(35, 10, 35);
|
||||
demo.FreeLook.Target = new Vector3(0, 5, 0);
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Hierarchical Approximate Convex Decomposition Demo";
|
||||
return new ConvexDecompositionDemoSimulation(_enableSat);
|
||||
}
|
||||
|
||||
bool MyCompoundChildShapeCallback(CollisionShape shape0, CollisionShape shape1)
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
if (demo.Input.KeysPressed.Contains(Keys.T))
|
||||
{
|
||||
_enableSat = !_enableSat;
|
||||
demo.ResetScene();
|
||||
if (_enableSat)
|
||||
{
|
||||
Console.WriteLine("SAT enabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("SAT disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ConvexDecompositionDemoSimulation : ISimulation
|
||||
{
|
||||
private TriangleMesh _triangleMesh;
|
||||
private readonly bool _enableSat;
|
||||
|
||||
public ConvexDecompositionDemoSimulation(bool enableSat)
|
||||
{
|
||||
_enableSat = enableSat;
|
||||
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Broadphase = new AxisSweep3(new Vector3(-10000, -10000, -10000), new Vector3(10000, 10000, 10000));
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
CreateGround();
|
||||
|
||||
ManifoldPoint.ContactAdded += MyContactCallback;
|
||||
//CompoundCollisionAlgorithm.CompoundChildShapePairCallback = MyCompoundChildShapeCallback;
|
||||
|
||||
var wavefrontModel = WavefrontObj.Load("data/file.obj");
|
||||
if (wavefrontModel.Indices.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var localScaling = new Vector3(6, 6, 6);
|
||||
_triangleMesh = CreateTriangleMesh(wavefrontModel.Indices, wavefrontModel.Vertices, localScaling);
|
||||
|
||||
// Convex hull approximation
|
||||
ConvexHullShape convexShape = CreateHullApproximation(_triangleMesh);
|
||||
float mass = 1.0f;
|
||||
PhysicsHelper.CreateBody(mass, Matrix.Translation(0, 2, 14), convexShape, World);
|
||||
|
||||
// Non-moving body
|
||||
var objectOffset = new Vector3(10, 0, 0);
|
||||
const bool useQuantization = true;
|
||||
var concaveShape = new BvhTriangleMeshShape(_triangleMesh, useQuantization);
|
||||
PhysicsHelper.CreateStaticBody(Matrix.Translation(objectOffset), concaveShape, World);
|
||||
|
||||
|
||||
Hacd hacd = ComputeHacd(wavefrontModel);
|
||||
hacd.Save("output.wrl", false);
|
||||
|
||||
var compoundShape = CreateCompoundShape(hacd, localScaling);
|
||||
|
||||
mass = 10.0f;
|
||||
objectOffset = new Vector3(-10, 0, -6);
|
||||
var body2 = PhysicsHelper.CreateBody(mass, Matrix.Translation(objectOffset), compoundShape, World);
|
||||
body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback;
|
||||
|
||||
objectOffset.Z += 6;
|
||||
body2 = PhysicsHelper.CreateBody(mass, Matrix.Translation(objectOffset), compoundShape, World);
|
||||
body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback;
|
||||
|
||||
objectOffset.Z += 6;
|
||||
body2 = PhysicsHelper.CreateBody(mass, Matrix.Translation(objectOffset), compoundShape, World);
|
||||
body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback;
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_triangleMesh.Dispose();
|
||||
}
|
||||
|
||||
private bool MyCompoundChildShapeCallback(CollisionShape shape0, CollisionShape shape1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// MyContactCallback is just an example to show how to get access to the child shape that collided
|
||||
void MyContactCallback(ManifoldPoint cp, CollisionObjectWrapper colObj0Wrap, int partId0, int index0, CollisionObjectWrapper colObj1Wrap, int partId1, int index1)
|
||||
private void MyContactCallback(ManifoldPoint cp, CollisionObjectWrapper colObj0Wrap, int partId0, int index0, CollisionObjectWrapper colObj1Wrap, int partId1, int index1)
|
||||
{
|
||||
if (colObj0Wrap.CollisionObject.CollisionShape.ShapeType == BroadphaseNativeType.CompoundShape)
|
||||
{
|
||||
|
@ -45,146 +138,10 @@ namespace ConvexDecompositionDemo
|
|||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
{
|
||||
ManifoldPoint.ContactAdded += MyContactCallback;
|
||||
|
||||
SetupEmptyDynamicsWorld();
|
||||
CreateGround();
|
||||
|
||||
//CompoundCollisionAlgorithm.CompoundChildShapePairCallback = MyCompoundChildShapeCallback;
|
||||
|
||||
var wo = WavefrontObj.Load("data/file.obj");
|
||||
if (wo.Indices.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var localScaling = new Vector3(6, 6, 6);
|
||||
triangleMesh = CreateTriangleMesh(wo.Indices, wo.Vertices, localScaling);
|
||||
|
||||
// Convex hull approximation
|
||||
ConvexHullShape convexShape = CreateHullApproximation(triangleMesh);
|
||||
CollisionShapes.Add(convexShape);
|
||||
float mass = 1.0f;
|
||||
LocalCreateRigidBody(mass, Matrix.Translation(0, 2, 14), convexShape);
|
||||
|
||||
// Non-moving body
|
||||
Vector3 convexDecompositionObjectOffset = new Vector3(10, 0, 0);
|
||||
const bool useQuantization = true;
|
||||
var concaveShape = new BvhTriangleMeshShape(triangleMesh, useQuantization);
|
||||
CollisionShapes.Add(concaveShape);
|
||||
LocalCreateRigidBody(0, Matrix.Translation(convexDecompositionObjectOffset), concaveShape);
|
||||
|
||||
|
||||
var hacd = new Hacd()
|
||||
{
|
||||
VerticesPerConvexHull = 100,
|
||||
CompacityWeight = 0.1,
|
||||
VolumeWeight = 0,
|
||||
|
||||
// Recommended HACD parameters
|
||||
NClusters = 2,
|
||||
Concavity = 100,
|
||||
AddExtraDistPoints = false,
|
||||
AddFacesPoints = false,
|
||||
AddNeighboursDistPoints = false
|
||||
};
|
||||
hacd.SetPoints(wo.Vertices);
|
||||
hacd.SetTriangles(wo.Indices);
|
||||
|
||||
hacd.Compute();
|
||||
hacd.Save("output.wrl", false);
|
||||
|
||||
|
||||
// Generate convex result
|
||||
var outputFile = new FileStream("file_convex.obj", FileMode.Create, FileAccess.Write);
|
||||
var writer = new StreamWriter(outputFile);
|
||||
var convexDecomposition = new ConvexDecomposition(writer) { LocalScaling = localScaling };
|
||||
|
||||
for (int c = 0; c < hacd.NClusters; c++)
|
||||
{
|
||||
int nVertices = hacd.GetNPointsCH(c);
|
||||
int trianglesLen = hacd.GetNTrianglesCH(c) * 3;
|
||||
double[] points = new double[nVertices * 3];
|
||||
long[] triangles = new long[trianglesLen];
|
||||
hacd.GetCH(c, points, triangles);
|
||||
|
||||
if (trianglesLen == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3[] verticesArray = new Vector3[nVertices];
|
||||
int vi3 = 0;
|
||||
for (int vi = 0; vi < nVertices; vi++)
|
||||
{
|
||||
verticesArray[vi] = new Vector3(
|
||||
(float)points[vi3], (float)points[vi3 + 1], (float)points[vi3 + 2]);
|
||||
vi3 += 3;
|
||||
}
|
||||
|
||||
int[] trianglesInt = new int[trianglesLen];
|
||||
for (int ti = 0; ti < trianglesLen; ti++)
|
||||
{
|
||||
trianglesInt[ti] = (int)triangles[ti];
|
||||
}
|
||||
|
||||
convexDecomposition.Result(verticesArray, trianglesInt);
|
||||
}
|
||||
|
||||
writer.Dispose();
|
||||
outputFile.Dispose();
|
||||
|
||||
|
||||
// Combine convex shapes into a compound shape
|
||||
var compound = new CompoundShape();
|
||||
for (int i = 0; i < convexDecomposition.convexShapes.Count; i++)
|
||||
{
|
||||
Vector3 centroid = convexDecomposition.convexCentroids[i];
|
||||
var convexShape2 = convexDecomposition.convexShapes[i];
|
||||
Matrix trans = Matrix.Translation(centroid);
|
||||
if (enableSat)
|
||||
{
|
||||
convexShape2.InitializePolyhedralFeatures();
|
||||
}
|
||||
CollisionShapes.Add(convexShape2);
|
||||
compound.AddChildShape(trans, convexShape2);
|
||||
|
||||
LocalCreateRigidBody(1.0f, trans, convexShape2);
|
||||
}
|
||||
CollisionShapes.Add(compound);
|
||||
|
||||
#if true
|
||||
mass = 10.0f;
|
||||
var body2 = LocalCreateRigidBody(mass, Matrix.Translation(-convexDecompositionObjectOffset), compound);
|
||||
body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback;
|
||||
|
||||
convexDecompositionObjectOffset.Z = 6;
|
||||
body2 = LocalCreateRigidBody(mass, Matrix.Translation(-convexDecompositionObjectOffset), compound);
|
||||
body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback;
|
||||
|
||||
convexDecompositionObjectOffset.Z = -6;
|
||||
body2 = LocalCreateRigidBody(mass, Matrix.Translation(-convexDecompositionObjectOffset), compound);
|
||||
body2.CollisionFlags |= CollisionFlags.CustomMaterialCallback;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SetupEmptyDynamicsWorld()
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
Broadphase = new AxisSweep3(new Vector3(-10000, -10000, -10000), new Vector3(10000, 10000, 10000));
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
var groundShape = new BoxShape(30, 2, 30);
|
||||
CollisionShapes.Add(groundShape);
|
||||
CollisionObject ground = LocalCreateRigidBody(0, Matrix.Translation(0, -4.5f, 0), groundShape);
|
||||
CollisionObject ground = PhysicsHelper.CreateStaticBody(Matrix.Translation(0, -4.5f, 0), groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
}
|
||||
|
||||
|
@ -217,7 +174,7 @@ namespace ConvexDecompositionDemo
|
|||
{
|
||||
hull.BuildHull(tmpConvexShape.Margin);
|
||||
var convexShape = new ConvexHullShape(hull.Vertices);
|
||||
if (enableSat)
|
||||
if (_enableSat)
|
||||
{
|
||||
convexShape.InitializePolyhedralFeatures();
|
||||
}
|
||||
|
@ -226,41 +183,81 @@ namespace ConvexDecompositionDemo
|
|||
}
|
||||
}
|
||||
|
||||
public override void OnHandleInput()
|
||||
private Hacd ComputeHacd(WavefrontObj model)
|
||||
{
|
||||
base.OnHandleInput();
|
||||
|
||||
if (Input.KeysPressed.Contains(Keys.T))
|
||||
var hacd = new Hacd()
|
||||
{
|
||||
enableSat = !enableSat;
|
||||
if (enableSat)
|
||||
{
|
||||
Console.WriteLine("SAT enabled after the next restart of the demo");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("SAT disabled after the next restart of the demo");
|
||||
}
|
||||
}
|
||||
VerticesPerConvexHull = 100,
|
||||
CompacityWeight = 0.1,
|
||||
VolumeWeight = 0,
|
||||
|
||||
// Recommended HACD parameters
|
||||
NClusters = 2,
|
||||
Concavity = 100,
|
||||
AddExtraDistPoints = false,
|
||||
AddFacesPoints = false,
|
||||
AddNeighboursDistPoints = false
|
||||
};
|
||||
hacd.SetPoints(model.Vertices);
|
||||
hacd.SetTriangles(model.Indices);
|
||||
|
||||
hacd.Compute();
|
||||
return hacd;
|
||||
}
|
||||
|
||||
public override void ExitPhysics()
|
||||
private CompoundShape CreateCompoundShape(Hacd hacd, Vector3 localScaling)
|
||||
{
|
||||
base.ExitPhysics();
|
||||
|
||||
triangleMesh.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new ConvexDecompositionDemo())
|
||||
var wavefrontWriter = new WavefrontWriter("file_convex.obj");
|
||||
var convexDecomposition = new ConvexDecomposition(wavefrontWriter)
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
LocalScaling = localScaling
|
||||
};
|
||||
|
||||
for (int c = 0; c < hacd.NClusters; c++)
|
||||
{
|
||||
int trianglesLen = hacd.GetNTrianglesCH(c) * 3;
|
||||
if (trianglesLen == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var triangles = new long[trianglesLen];
|
||||
|
||||
int nVertices = hacd.GetNPointsCH(c);
|
||||
var points = new double[nVertices * 3];
|
||||
|
||||
hacd.GetCH(c, points, triangles);
|
||||
|
||||
var verticesArray = new Vector3[nVertices];
|
||||
int vi3 = 0;
|
||||
for (int vi = 0; vi < nVertices; vi++)
|
||||
{
|
||||
verticesArray[vi] = new Vector3(
|
||||
(float)points[vi3], (float)points[vi3 + 1], (float)points[vi3 + 2]);
|
||||
vi3 += 3;
|
||||
}
|
||||
|
||||
convexDecomposition.Result(verticesArray, triangles);
|
||||
}
|
||||
|
||||
wavefrontWriter.Dispose();
|
||||
|
||||
// Combine convex shapes into a compound shape
|
||||
var compoundShape = new CompoundShape();
|
||||
for (int i = 0; i < convexDecomposition.ConvexShapes.Count; i++)
|
||||
{
|
||||
Vector3 centroid = convexDecomposition.ConvexCentroids[i];
|
||||
var convexShape = convexDecomposition.ConvexShapes[i];
|
||||
Matrix trans = Matrix.Translation(centroid);
|
||||
if (_enableSat)
|
||||
{
|
||||
convexShape.InitializePolyhedralFeatures();
|
||||
}
|
||||
compoundShape.AddChildShape(trans, convexShape);
|
||||
|
||||
PhysicsHelper.CreateBody(1.0f, trans, convexShape, World);
|
||||
}
|
||||
|
||||
return compoundShape;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="ConvexDecomposition.cs" />
|
||||
<Compile Include="ConvexDecompositionDemo.cs" />
|
||||
<Compile Include="WavefrontWriter.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
using BulletSharp.Math;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace ConvexDecompositionDemo
|
||||
{
|
||||
internal sealed class WavefrontWriter : IDisposable
|
||||
{
|
||||
private FileStream _outputFile;
|
||||
private StreamWriter _outputStream;
|
||||
private CultureInfo _floatFormat = new CultureInfo("en-US");
|
||||
|
||||
private long _baseIndex = 0;
|
||||
private int _objectCount = 0;
|
||||
|
||||
public WavefrontWriter(string filename)
|
||||
{
|
||||
var _outputFile = new FileStream(filename, FileMode.Create, FileAccess.Write);
|
||||
_outputStream = new StreamWriter(_outputFile);
|
||||
}
|
||||
|
||||
public void OutputObject(Vector3[] hullVertices, long[] hullIndices)
|
||||
{
|
||||
_outputStream.WriteLine("## Object {0} with {1} vertices and {2} triangles.", _objectCount, hullVertices.Length, hullIndices.Length / 3);
|
||||
|
||||
_outputStream.WriteLine("usemtl Material{0}", _baseIndex);
|
||||
_outputStream.WriteLine("o Object{0}", _baseIndex);
|
||||
|
||||
foreach (Vector3 p in hullVertices)
|
||||
{
|
||||
_outputStream.WriteLine(string.Format(_floatFormat, "v {0:F9} {1:F9} {2:F9}", p.X, p.Y, p.Z));
|
||||
}
|
||||
|
||||
for (int i = 0; i < hullIndices.Length; i += 3)
|
||||
{
|
||||
long index0 = _baseIndex + hullIndices[i];
|
||||
long index1 = _baseIndex + hullIndices[i + 1];
|
||||
long index2 = _baseIndex + hullIndices[i + 2];
|
||||
|
||||
_outputStream.WriteLine("f {0} {1} {2}", index0 + 1, index1 + 1, index2 + 1);
|
||||
}
|
||||
_baseIndex += hullVertices.Length;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_outputStream != null)
|
||||
{
|
||||
_outputStream.Dispose();
|
||||
_outputStream = null;
|
||||
}
|
||||
|
||||
if (_outputFile != null)
|
||||
{
|
||||
_outputFile.Dispose();
|
||||
_outputFile = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,79 +4,106 @@ using System.Windows.Forms;
|
|||
|
||||
namespace DemoFramework
|
||||
{
|
||||
public class FreeLook
|
||||
public sealed class FreeLook
|
||||
{
|
||||
public Vector3 Eye { get; private set; }
|
||||
public Vector3 Target { get; private set; }
|
||||
public Vector3 Up { get; set; }
|
||||
|
||||
Input input;
|
||||
MouseController mouseController;
|
||||
bool doUpdate;
|
||||
private Input _input;
|
||||
private MouseController _mouseController;
|
||||
private bool _doUpdate;
|
||||
private Matrix _yToUpTransform, _upToYTransform;
|
||||
private Vector3 _eye, _target, _up;
|
||||
|
||||
public FreeLook(Input input)
|
||||
{
|
||||
_input = input;
|
||||
_mouseController = new MouseController(input);
|
||||
Target = Vector3.UnitX;
|
||||
Up = Vector3.UnitY;
|
||||
this.input = input;
|
||||
mouseController = new MouseController(input);
|
||||
}
|
||||
|
||||
public void SetEyeTarget(Vector3 eye, Vector3 target)
|
||||
public Vector3 Eye
|
||||
{
|
||||
Eye = eye;
|
||||
Target = target;
|
||||
get { return _eye; }
|
||||
set
|
||||
{
|
||||
_eye = value;
|
||||
UpdateMouseController();
|
||||
}
|
||||
}
|
||||
|
||||
// Convert direction vector to Y-up for MouseController
|
||||
Matrix swapAxis = Matrix.RotationAxis(Vector3.Cross(Up, Vector3.UnitY), Angle(Up, Vector3.UnitY));
|
||||
mouseController.Vector = Vector3.TransformCoordinate(Vector3.Normalize(eye - target), swapAxis);
|
||||
public Vector3 Target
|
||||
{
|
||||
get { return _target; }
|
||||
set
|
||||
{
|
||||
_target = value;
|
||||
UpdateMouseController();
|
||||
}
|
||||
}
|
||||
|
||||
doUpdate = true;
|
||||
public Vector3 Up
|
||||
{
|
||||
get { return _up; }
|
||||
set
|
||||
{
|
||||
_up = value;
|
||||
|
||||
// MouseController uses UnitY as the up-vector,
|
||||
// create transforms for converting between UnitY-up and Up-up
|
||||
_yToUpTransform = Matrix.RotationAxis(Vector3.Cross(Vector3.UnitY, _up), Angle(_up, Vector3.UnitY));
|
||||
Matrix.Invert(ref _yToUpTransform, out _upToYTransform);
|
||||
UpdateMouseController();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Update(float frameDelta)
|
||||
{
|
||||
if (mouseController.Update() == false && input.KeysDown.Count == 0)
|
||||
if (!_mouseController.Update() && _input.KeysDown.Count == 0)
|
||||
{
|
||||
if (!doUpdate)
|
||||
if (!_doUpdate)
|
||||
return false;
|
||||
doUpdate = false;
|
||||
_doUpdate = false;
|
||||
}
|
||||
|
||||
// MouseController is Y-up, convert to Up-up
|
||||
Matrix swapAxis = Matrix.RotationAxis(Vector3.Cross(Vector3.UnitY, Up), Angle(Vector3.UnitY, Up));
|
||||
Vector3 direction = Vector3.TransformCoordinate(-mouseController.Vector, swapAxis);
|
||||
Vector3 direction = Vector3.TransformCoordinate(-_mouseController.Vector, _yToUpTransform);
|
||||
|
||||
if (input.KeysDown.Count != 0)
|
||||
if (_input.KeysDown.Count != 0)
|
||||
{
|
||||
Vector3 relDirection = frameDelta * direction;
|
||||
float flySpeed = input.KeysDown.Contains(Keys.ShiftKey) ? 15 : 5;
|
||||
float flySpeed = _input.KeysDown.Contains(Keys.ShiftKey) ? 15 : 5;
|
||||
|
||||
if (input.KeysDown.Contains(Keys.W))
|
||||
if (_input.KeysDown.Contains(Keys.W))
|
||||
{
|
||||
Eye += flySpeed * relDirection;
|
||||
_eye += flySpeed * relDirection;
|
||||
}
|
||||
if (input.KeysDown.Contains(Keys.S))
|
||||
if (_input.KeysDown.Contains(Keys.S))
|
||||
{
|
||||
Eye -= flySpeed * relDirection;
|
||||
_eye -= flySpeed * relDirection;
|
||||
}
|
||||
|
||||
if (input.KeysDown.Contains(Keys.A))
|
||||
if (_input.KeysDown.Contains(Keys.A))
|
||||
{
|
||||
Eye += Vector3.Cross(relDirection, Up);
|
||||
_eye += Vector3.Cross(relDirection, _up);
|
||||
}
|
||||
if (input.KeysDown.Contains(Keys.D))
|
||||
if (_input.KeysDown.Contains(Keys.D))
|
||||
{
|
||||
Eye -= Vector3.Cross(relDirection, Up);
|
||||
_eye -= Vector3.Cross(relDirection, _up);
|
||||
}
|
||||
}
|
||||
Target = Eye + (Eye - Target).Length * direction;
|
||||
_target = _eye + (_eye - _target).Length * direction;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateMouseController()
|
||||
{
|
||||
Vector3 direction = _eye - _target;
|
||||
direction.Normalize();
|
||||
_mouseController.Vector = Vector3.TransformCoordinate(direction, _upToYTransform);
|
||||
_doUpdate = true;
|
||||
}
|
||||
|
||||
// vertices must be normalized
|
||||
float Angle(Vector3 v1, Vector3 v2)
|
||||
private static float Angle(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
return (float)Math.Acos(Vector3.Dot(v1, v2));
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Windows.Forms;
|
|||
|
||||
namespace DemoFramework
|
||||
{
|
||||
public class Input
|
||||
public sealed class Input
|
||||
{
|
||||
List<Keys> _keysPressed;
|
||||
List<Keys> _keysReleased;
|
||||
|
|
|
@ -33,11 +33,11 @@ namespace DemoFramework
|
|||
|
||||
public bool Update()
|
||||
{
|
||||
if ((input.MouseDown & MouseButtons.Left) != MouseButtons.Left)
|
||||
if ((input.MouseDown & MouseButtons.Left) == 0)
|
||||
return false;
|
||||
|
||||
// When mouse button is clicked, store cursor position and angles
|
||||
if ((input.MousePressed & MouseButtons.Left) == MouseButtons.Left)
|
||||
if ((input.MousePressed & MouseButtons.Left) != 0)
|
||||
{
|
||||
mouseOrigin = input.MousePoint;
|
||||
|
||||
|
|
|
@ -1,23 +1,29 @@
|
|||
using System;
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
|
||||
namespace DemoFramework
|
||||
{
|
||||
public abstract class Demo : IDisposable
|
||||
public sealed class Demo
|
||||
{
|
||||
protected Graphics Graphics { get; set; }
|
||||
public FreeLook Freelook { get; set; }
|
||||
public Input Input { get; set; }
|
||||
private IDemoConfiguration _configuration;
|
||||
private IUpdateReceiver _updateReceiver;
|
||||
|
||||
public ISimulation Simulation { get; private set; }
|
||||
|
||||
public Graphics Graphics { get; private set; }
|
||||
public FreeLook FreeLook { get; private set; }
|
||||
public Input Input { get; private set; }
|
||||
|
||||
// Info text
|
||||
CultureInfo _culture = CultureInfo.InvariantCulture;
|
||||
string _demoText = "";
|
||||
protected string DemoText
|
||||
public string DemoText
|
||||
{
|
||||
get { return _demoText; }
|
||||
set
|
||||
|
@ -35,22 +41,14 @@ namespace DemoFramework
|
|||
float _frameAccumulator;
|
||||
|
||||
// Physics
|
||||
public DynamicsWorld World { get; protected set; }
|
||||
|
||||
protected CollisionConfiguration CollisionConf;
|
||||
protected CollisionDispatcher Dispatcher;
|
||||
protected BroadphaseInterface Broadphase;
|
||||
protected ConstraintSolver Solver;
|
||||
public List<CollisionShape> CollisionShapes { get; private set; }
|
||||
|
||||
protected BoxShape shootBoxShape;
|
||||
protected float shootBoxInitialSpeed = 40;
|
||||
RigidBody pickedBody;
|
||||
protected TypedConstraint pickConstraint;
|
||||
TypedConstraint pickConstraint;
|
||||
float oldPickingDist;
|
||||
bool prevCanSleep;
|
||||
MultiBodyPoint2Point pickingMultiBodyPoint2Point;
|
||||
|
||||
private BoxShooter _boxShooter;
|
||||
|
||||
// Debug drawing
|
||||
bool _isDebugDrawEnabled;
|
||||
DebugDrawModes _debugDrawMode = DebugDrawModes.DrawWireframe;
|
||||
|
@ -58,193 +56,143 @@ namespace DemoFramework
|
|||
|
||||
public DebugDrawModes DebugDrawMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _debugDrawMode;
|
||||
}
|
||||
get { return _debugDrawMode; }
|
||||
set
|
||||
{
|
||||
_debugDrawMode = value;
|
||||
if (_debugDrawer != null)
|
||||
{
|
||||
_debugDrawer.DebugMode = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDebugDrawEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isDebugDrawEnabled;
|
||||
}
|
||||
get { return _isDebugDrawEnabled; }
|
||||
set
|
||||
{
|
||||
_isDebugDrawEnabled = value;
|
||||
if (value)
|
||||
{
|
||||
if (_debugDrawer == null)
|
||||
{
|
||||
_debugDrawer = Graphics.GetPhysicsDebugDrawer();
|
||||
_debugDrawer.DebugMode = _debugDrawMode;
|
||||
if (World != null)
|
||||
{
|
||||
World.DebugDrawer = _debugDrawer;
|
||||
}
|
||||
}
|
||||
InitializeDebugDrawer();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_debugDrawer != null)
|
||||
{
|
||||
if (World != null)
|
||||
{
|
||||
World.DebugDrawer = null;
|
||||
}
|
||||
if (_debugDrawer is IDisposable)
|
||||
{
|
||||
(_debugDrawer as IDisposable).Dispose();
|
||||
}
|
||||
_debugDrawer = null;
|
||||
}
|
||||
UninitializeDebugDrawer();
|
||||
}
|
||||
_isDebugDrawEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool isCullingEnabled = true;
|
||||
public bool CullingEnabled
|
||||
public Demo(IDemoConfiguration configuration = null)
|
||||
{
|
||||
get
|
||||
{
|
||||
return isCullingEnabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
Graphics.CullingEnabled = value;
|
||||
isCullingEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Demo()
|
||||
{
|
||||
CollisionShapes = new List<CollisionShape>();
|
||||
_configuration = configuration;
|
||||
_updateReceiver = configuration as IUpdateReceiver;
|
||||
Clock = new Clock();
|
||||
}
|
||||
|
||||
private void VerifySimulation()
|
||||
{
|
||||
if (Simulation == null)
|
||||
{
|
||||
throw new NullReferenceException("Simulation not initialized");
|
||||
}
|
||||
if (Simulation.CollisionConfiguration == null)
|
||||
{
|
||||
throw new NullReferenceException("CollisionConfiguration not initialized");
|
||||
}
|
||||
if (Simulation.Broadphase == null)
|
||||
{
|
||||
throw new NullReferenceException("Broadphase not initialized");
|
||||
}
|
||||
if (Simulation.Dispatcher == null)
|
||||
{
|
||||
throw new NullReferenceException("Dispatcher not initialized");
|
||||
}
|
||||
if (Simulation.World == null)
|
||||
{
|
||||
throw new NullReferenceException("DynamicsWorld not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeDebugDrawer()
|
||||
{
|
||||
if (_debugDrawer == null)
|
||||
{
|
||||
_debugDrawer = Graphics.GetPhysicsDebugDrawer();
|
||||
_debugDrawer.DebugMode = DebugDrawMode;
|
||||
}
|
||||
if (Simulation != null)
|
||||
{
|
||||
Simulation.World.DebugDrawer = _debugDrawer;
|
||||
}
|
||||
}
|
||||
|
||||
private void UninitializeDebugDrawer()
|
||||
{
|
||||
if (_debugDrawer != null)
|
||||
{
|
||||
Simulation.World.DebugDrawer = null;
|
||||
if (_debugDrawer is IDisposable)
|
||||
{
|
||||
(_debugDrawer as IDisposable).Dispose();
|
||||
}
|
||||
_debugDrawer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializePhysics()
|
||||
{
|
||||
Simulation = _configuration.CreateSimulation(this);
|
||||
VerifySimulation();
|
||||
_boxShooter = new BoxShooter(Simulation.World);
|
||||
if (_debugDrawer != null)
|
||||
{
|
||||
Simulation.World.DebugDrawer = _debugDrawer;
|
||||
}
|
||||
}
|
||||
|
||||
private void UninitializePhysics()
|
||||
{
|
||||
RemovePickingConstraint();
|
||||
Simulation.Dispose();
|
||||
_boxShooter.Dispose();
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
using (Graphics = GraphicsLibraryManager.GetGraphics(this))
|
||||
{
|
||||
Input = new Input(Graphics.Form);
|
||||
Freelook = new FreeLook(Input);
|
||||
|
||||
Graphics.Initialize();
|
||||
Graphics.CullingEnabled = isCullingEnabled;
|
||||
OnInitialize();
|
||||
if (World == null)
|
||||
{
|
||||
OnInitializePhysics();
|
||||
}
|
||||
Graphics.CullingEnabled = true;
|
||||
|
||||
Input = new Input(Graphics.Form);
|
||||
FreeLook = new FreeLook(Input);
|
||||
|
||||
InitializePhysics();
|
||||
if (_isDebugDrawEnabled)
|
||||
{
|
||||
if (_debugDrawer == null)
|
||||
{
|
||||
_debugDrawer = Graphics.GetPhysicsDebugDrawer();
|
||||
_debugDrawer.DebugMode = DebugDrawMode;
|
||||
}
|
||||
if (World != null)
|
||||
{
|
||||
World.DebugDrawer = _debugDrawer;
|
||||
}
|
||||
InitializeDebugDrawer();
|
||||
}
|
||||
|
||||
Graphics.UpdateView();
|
||||
SetInfoText();
|
||||
|
||||
Graphics.Run();
|
||||
|
||||
if (_debugDrawer != null)
|
||||
{
|
||||
if (World != null)
|
||||
{
|
||||
World.DebugDrawer = null;
|
||||
}
|
||||
if (_debugDrawer is IDisposable)
|
||||
{
|
||||
(_debugDrawer as IDisposable).Dispose();
|
||||
}
|
||||
_debugDrawer = null;
|
||||
}
|
||||
}
|
||||
Graphics = null;
|
||||
|
||||
UninitializeDebugDrawer();
|
||||
UninitializePhysics();
|
||||
}
|
||||
|
||||
protected virtual void OnInitialize()
|
||||
public void ResetScene()
|
||||
{
|
||||
UninitializePhysics();
|
||||
InitializePhysics();
|
||||
}
|
||||
|
||||
protected abstract void OnInitializePhysics();
|
||||
|
||||
public virtual void ClientResetScene()
|
||||
{
|
||||
RemovePickingConstraint();
|
||||
ExitPhysics();
|
||||
OnInitializePhysics();
|
||||
if (World != null && _debugDrawer != null)
|
||||
{
|
||||
World.DebugDrawer = _debugDrawer;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ExitPhysics()
|
||||
{
|
||||
if (World != null)
|
||||
{
|
||||
//remove/dispose constraints
|
||||
int i;
|
||||
for (i = World.NumConstraints - 1; i >= 0; i--)
|
||||
{
|
||||
TypedConstraint constraint = World.GetConstraint(i);
|
||||
World.RemoveConstraint(constraint);
|
||||
constraint.Dispose();
|
||||
}
|
||||
|
||||
//remove the rigidbodies from the dynamics world and delete them
|
||||
for (i = World.NumCollisionObjects - 1; i >= 0; i--)
|
||||
{
|
||||
CollisionObject obj = World.CollisionObjectArray[i];
|
||||
RigidBody body = obj as RigidBody;
|
||||
if (body != null && body.MotionState != null)
|
||||
{
|
||||
body.MotionState.Dispose();
|
||||
}
|
||||
World.RemoveCollisionObject(obj);
|
||||
obj.Dispose();
|
||||
}
|
||||
|
||||
//delete collision shapes
|
||||
foreach (CollisionShape shape in CollisionShapes)
|
||||
shape.Dispose();
|
||||
CollisionShapes.Clear();
|
||||
|
||||
World.Dispose();
|
||||
Broadphase.Dispose();
|
||||
Dispatcher.Dispose();
|
||||
CollisionConf.Dispose();
|
||||
}
|
||||
|
||||
if (Broadphase != null)
|
||||
{
|
||||
Broadphase.Dispose();
|
||||
}
|
||||
if (Dispatcher != null)
|
||||
{
|
||||
Dispatcher.Dispose();
|
||||
}
|
||||
if (CollisionConf != null)
|
||||
{
|
||||
CollisionConf.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void SetInfoText()
|
||||
private void SetInfoText()
|
||||
{
|
||||
Graphics.SetInfoText(
|
||||
string.Format("Physics: {0} ms\n" +
|
||||
|
@ -258,7 +206,7 @@ namespace DemoFramework
|
|||
);
|
||||
}
|
||||
|
||||
public virtual void OnUpdate()
|
||||
public void OnUpdate()
|
||||
{
|
||||
FrameDelta = Clock.GetFrameDelta();
|
||||
_frameAccumulator += FrameDelta;
|
||||
|
@ -271,186 +219,115 @@ namespace DemoFramework
|
|||
Clock.Reset();
|
||||
}
|
||||
|
||||
if (World != null)
|
||||
if (_updateReceiver != null)
|
||||
{
|
||||
Clock.StartPhysics();
|
||||
World.StepSimulation(FrameDelta);
|
||||
Clock.StopPhysics();
|
||||
_updateReceiver.Update(this);
|
||||
}
|
||||
HandleKeyboardInput();
|
||||
HandleMouseInput();
|
||||
|
||||
if (Freelook.Update(FrameDelta))
|
||||
Clock.StartPhysics();
|
||||
Simulation.World.StepSimulation(FrameDelta);
|
||||
Clock.StopPhysics();
|
||||
|
||||
if (FreeLook.Update(FrameDelta))
|
||||
Graphics.UpdateView();
|
||||
|
||||
Input.ClearKeyCache();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
private void HandleMouseInput()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
ExitPhysics();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnHandleInput()
|
||||
{
|
||||
if (Input.KeysPressed.Count != 0)
|
||||
{
|
||||
switch (Input.KeysPressed[0])
|
||||
{
|
||||
case Keys.Escape:
|
||||
case Keys.Q:
|
||||
Graphics.Form.Close();
|
||||
return;
|
||||
case Keys.F1:
|
||||
MessageBox.Show(
|
||||
"Move using WASD + shift\n" +
|
||||
"Left click - point camera\n" +
|
||||
"Right click - pick up an object using a Point2PointConstraint\n" +
|
||||
"Right click + shift - pick up an object using a fixed Generic6DofConstraint\n" +
|
||||
"Space - shoot box\n" +
|
||||
"Q - quit\n\n" +
|
||||
Graphics.InfoText,
|
||||
"Help");
|
||||
// Key release won't be captured
|
||||
Input.KeysDown.Remove(Keys.F1);
|
||||
break;
|
||||
case Keys.F3:
|
||||
IsDebugDrawEnabled = !IsDebugDrawEnabled;
|
||||
break;
|
||||
case Keys.F8:
|
||||
Input.ClearKeyCache();
|
||||
GraphicsLibraryManager.ExitWithReload = true;
|
||||
Graphics.Form.Close();
|
||||
break;
|
||||
case Keys.F11:
|
||||
Graphics.IsFullScreen = !Graphics.IsFullScreen;
|
||||
break;
|
||||
case (Keys.Control | Keys.F):
|
||||
const int maxSerializeBufferSize = 1024 * 1024 * 5;
|
||||
using (var serializer = new DefaultSerializer(maxSerializeBufferSize))
|
||||
{
|
||||
World.Serialize(serializer);
|
||||
byte[] dataBytes = new byte[serializer.CurrentBufferSize];
|
||||
System.Runtime.InteropServices.Marshal.Copy(serializer.BufferPointer, dataBytes, 0,
|
||||
dataBytes.Length);
|
||||
using (var file = new System.IO.FileStream("world.bullet", System.IO.FileMode.Create))
|
||||
{
|
||||
file.Write(dataBytes, 0, dataBytes.Length);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Keys.G:
|
||||
//shadowsEnabled = !shadowsEnabled;
|
||||
break;
|
||||
case Keys.Space:
|
||||
ShootBox(Freelook.Eye, GetRayTo(Input.MousePoint, Freelook.Eye, Freelook.Target, Graphics.FieldOfView));
|
||||
break;
|
||||
case Keys.Return:
|
||||
ClientResetScene();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.MousePressed != MouseButtons.None)
|
||||
{
|
||||
Vector3 rayTo = GetRayTo(Input.MousePoint, Freelook.Eye, Freelook.Target, Graphics.FieldOfView);
|
||||
Vector3 rayTo = GetRayTo(Input.MousePoint, FreeLook.Eye, FreeLook.Target, Graphics.FieldOfView);
|
||||
|
||||
if (Input.MousePressed == MouseButtons.Right)
|
||||
{
|
||||
if (World != null)
|
||||
Vector3 rayFrom = FreeLook.Eye;
|
||||
|
||||
var rayCallback = new ClosestRayResultCallback(ref rayFrom, ref rayTo);
|
||||
Simulation.World.RayTestRef(ref rayFrom, ref rayTo, rayCallback);
|
||||
if (rayCallback.HasHit)
|
||||
{
|
||||
Vector3 rayFrom = Freelook.Eye;
|
||||
|
||||
ClosestRayResultCallback rayCallback = new ClosestRayResultCallback(ref rayFrom, ref rayTo);
|
||||
World.RayTestRef(ref rayFrom, ref rayTo, rayCallback);
|
||||
if (rayCallback.HasHit)
|
||||
Vector3 pickPos = rayCallback.HitPointWorld;
|
||||
RigidBody body = rayCallback.CollisionObject as RigidBody;
|
||||
if (body != null)
|
||||
{
|
||||
Vector3 pickPos = rayCallback.HitPointWorld;
|
||||
RigidBody body = rayCallback.CollisionObject as RigidBody;
|
||||
if (body != null)
|
||||
if (!(body.IsStaticObject || body.IsKinematicObject))
|
||||
{
|
||||
if (!(body.IsStaticObject || body.IsKinematicObject))
|
||||
pickedBody = body;
|
||||
pickedBody.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
Vector3 localPivot = Vector3.TransformCoordinate(pickPos, Matrix.Invert(body.CenterOfMassTransform));
|
||||
|
||||
if (Input.KeysDown.Contains(Keys.ShiftKey))
|
||||
{
|
||||
pickedBody = body;
|
||||
pickedBody.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
Vector3 localPivot = Vector3.TransformCoordinate(pickPos, Matrix.Invert(body.CenterOfMassTransform));
|
||||
|
||||
if (Input.KeysDown.Contains(Keys.ShiftKey))
|
||||
Generic6DofConstraint dof6 = new Generic6DofConstraint(body, Matrix.Translation(localPivot), false)
|
||||
{
|
||||
Generic6DofConstraint dof6 = new Generic6DofConstraint(body, Matrix.Translation(localPivot), false)
|
||||
{
|
||||
LinearLowerLimit = Vector3.Zero,
|
||||
LinearUpperLimit = Vector3.Zero,
|
||||
AngularLowerLimit = Vector3.Zero,
|
||||
AngularUpperLimit = Vector3.Zero
|
||||
};
|
||||
LinearLowerLimit = Vector3.Zero,
|
||||
LinearUpperLimit = Vector3.Zero,
|
||||
AngularLowerLimit = Vector3.Zero,
|
||||
AngularUpperLimit = Vector3.Zero
|
||||
};
|
||||
|
||||
World.AddConstraint(dof6);
|
||||
pickConstraint = dof6;
|
||||
Simulation.World.AddConstraint(dof6);
|
||||
pickConstraint = dof6;
|
||||
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 0);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 1);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 2);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 3);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 4);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 5);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 0);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 1);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 2);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 3);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 4);
|
||||
dof6.SetParam(ConstraintParam.StopCfm, 0.8f, 5);
|
||||
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 0);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 1);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 2);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 3);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 4);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
Point2PointConstraint p2p = new Point2PointConstraint(body, localPivot);
|
||||
World.AddConstraint(p2p);
|
||||
pickConstraint = p2p;
|
||||
p2p.Setting.ImpulseClamp = 30;
|
||||
//very weak constraint for picking
|
||||
p2p.Setting.Tau = 0.001f;
|
||||
/*
|
||||
p2p.SetParam(ConstraintParams.Cfm, 0.8f, 0);
|
||||
p2p.SetParam(ConstraintParams.Cfm, 0.8f, 1);
|
||||
p2p.SetParam(ConstraintParams.Cfm, 0.8f, 2);
|
||||
p2p.SetParam(ConstraintParams.Erp, 0.1f, 0);
|
||||
p2p.SetParam(ConstraintParams.Erp, 0.1f, 1);
|
||||
p2p.SetParam(ConstraintParams.Erp, 0.1f, 2);
|
||||
*/
|
||||
}
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 0);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 1);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 2);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 3);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 4);
|
||||
dof6.SetParam(ConstraintParam.StopErp, 0.1f, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
Point2PointConstraint p2p = new Point2PointConstraint(body, localPivot);
|
||||
Simulation.World.AddConstraint(p2p);
|
||||
pickConstraint = p2p;
|
||||
p2p.Setting.ImpulseClamp = 30;
|
||||
//very weak constraint for picking
|
||||
p2p.Setting.Tau = 0.001f;
|
||||
/*
|
||||
p2p.SetParam(ConstraintParams.Cfm, 0.8f, 0);
|
||||
p2p.SetParam(ConstraintParams.Cfm, 0.8f, 1);
|
||||
p2p.SetParam(ConstraintParams.Cfm, 0.8f, 2);
|
||||
p2p.SetParam(ConstraintParams.Erp, 0.1f, 0);
|
||||
p2p.SetParam(ConstraintParams.Erp, 0.1f, 1);
|
||||
p2p.SetParam(ConstraintParams.Erp, 0.1f, 2);
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MultiBodyLinkCollider multiCol = rayCallback.CollisionObject as MultiBodyLinkCollider;
|
||||
if (multiCol != null && multiCol.MultiBody != null)
|
||||
{
|
||||
MultiBody mb = multiCol.MultiBody;
|
||||
|
||||
prevCanSleep = mb.CanSleep;
|
||||
mb.CanSleep = false;
|
||||
Vector3 pivotInA = mb.WorldPosToLocal(multiCol.Link, pickPos);
|
||||
|
||||
MultiBodyPoint2Point p2p = new MultiBodyPoint2Point(mb, multiCol.Link, null, pivotInA, pickPos);
|
||||
p2p.MaxAppliedImpulse = 2;
|
||||
|
||||
(World as MultiBodyDynamicsWorld).AddMultiBodyConstraint(p2p);
|
||||
pickingMultiBodyPoint2Point = p2p;
|
||||
}
|
||||
}
|
||||
oldPickingDist = (pickPos - rayFrom).Length;
|
||||
}
|
||||
rayCallback.Dispose();
|
||||
else
|
||||
{
|
||||
var multiCol = rayCallback.CollisionObject as MultiBodyLinkCollider;
|
||||
if (multiCol != null && multiCol.MultiBody != null)
|
||||
{
|
||||
MultiBody mb = multiCol.MultiBody;
|
||||
|
||||
prevCanSleep = mb.CanSleep;
|
||||
mb.CanSleep = false;
|
||||
Vector3 pivotInA = mb.WorldPosToLocal(multiCol.Link, pickPos);
|
||||
|
||||
var p2p = new MultiBodyPoint2Point(mb, multiCol.Link, null, pivotInA, pickPos);
|
||||
p2p.MaxAppliedImpulse = 2;
|
||||
|
||||
(Simulation.World as MultiBodyDynamicsWorld).AddMultiBodyConstraint(p2p);
|
||||
pickingMultiBodyPoint2Point = p2p;
|
||||
}
|
||||
}
|
||||
oldPickingDist = (pickPos - rayFrom).Length;
|
||||
}
|
||||
rayCallback.Dispose();
|
||||
}
|
||||
}
|
||||
else if (Input.MouseReleased == MouseButtons.Right)
|
||||
|
@ -465,12 +342,77 @@ namespace DemoFramework
|
|||
}
|
||||
}
|
||||
|
||||
void MovePickedBody()
|
||||
private void HandleKeyboardInput()
|
||||
{
|
||||
if (Input.KeysPressed.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Input.KeysPressed[0])
|
||||
{
|
||||
case Keys.Escape:
|
||||
case Keys.Q:
|
||||
Graphics.Form.Close();
|
||||
return;
|
||||
case Keys.F1:
|
||||
MessageBox.Show(
|
||||
"WASD + Shift\tMove\n" +
|
||||
"Left click\t\tPoint camera\n" +
|
||||
"Right click\t\tPick up an object using a Point2PointConstraint\n" +
|
||||
"Shift + Right click\tPick up an object using a fixed Generic6DofConstraint\n" +
|
||||
"Space\t\tShoot box\n" +
|
||||
"Return\t\tReset\n" +
|
||||
"F11\t\tFullscreen\n" +
|
||||
"Q\t\tQuit\n\n",
|
||||
"Help");
|
||||
// Key release won't be captured
|
||||
Input.KeysDown.Remove(Keys.F1);
|
||||
break;
|
||||
case Keys.F3:
|
||||
IsDebugDrawEnabled = !IsDebugDrawEnabled;
|
||||
break;
|
||||
case Keys.F8:
|
||||
Input.ClearKeyCache();
|
||||
GraphicsLibraryManager.ExitWithReload = true;
|
||||
Graphics.Form.Close();
|
||||
break;
|
||||
case Keys.F11:
|
||||
Graphics.IsFullScreen = !Graphics.IsFullScreen;
|
||||
break;
|
||||
case (Keys.Control | Keys.F):
|
||||
const int maxSerializeBufferSize = 1024 * 1024 * 5;
|
||||
using (var serializer = new DefaultSerializer(maxSerializeBufferSize))
|
||||
{
|
||||
Simulation.World.Serialize(serializer);
|
||||
var dataBytes = new byte[serializer.CurrentBufferSize];
|
||||
Marshal.Copy(serializer.BufferPointer, dataBytes, 0,
|
||||
dataBytes.Length);
|
||||
using (var file = new System.IO.FileStream("world.bullet", System.IO.FileMode.Create))
|
||||
{
|
||||
file.Write(dataBytes, 0, dataBytes.Length);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Keys.G:
|
||||
//shadowsEnabled = !shadowsEnabled;
|
||||
break;
|
||||
case Keys.Space:
|
||||
Vector3 destination = GetRayTo(Input.MousePoint, FreeLook.Eye, FreeLook.Target, Graphics.FieldOfView);
|
||||
_boxShooter.Shoot(FreeLook.Eye, destination);
|
||||
break;
|
||||
case Keys.Return:
|
||||
ResetScene();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void MovePickedBody()
|
||||
{
|
||||
if (pickConstraint != null)
|
||||
{
|
||||
Vector3 rayFrom = Freelook.Eye;
|
||||
Vector3 newRayTo = GetRayTo(Input.MousePoint, rayFrom, Freelook.Target, Graphics.FieldOfView);
|
||||
Vector3 rayFrom = FreeLook.Eye;
|
||||
Vector3 newRayTo = GetRayTo(Input.MousePoint, rayFrom, FreeLook.Target, Graphics.FieldOfView);
|
||||
|
||||
//keep it at the same picking distance
|
||||
Vector3 dir = newRayTo - rayFrom;
|
||||
|
@ -479,7 +421,7 @@ namespace DemoFramework
|
|||
|
||||
if (pickConstraint.ConstraintType == TypedConstraintType.D6)
|
||||
{
|
||||
Generic6DofConstraint pickCon = pickConstraint as Generic6DofConstraint;
|
||||
var pickCon = pickConstraint as Generic6DofConstraint;
|
||||
|
||||
//keep it at the same picking distance
|
||||
Matrix tempFrameOffsetA = pickCon.FrameOffsetA;
|
||||
|
@ -488,7 +430,7 @@ namespace DemoFramework
|
|||
}
|
||||
else
|
||||
{
|
||||
Point2PointConstraint pickCon = pickConstraint as Point2PointConstraint;
|
||||
var pickCon = pickConstraint as Point2PointConstraint;
|
||||
|
||||
//keep it at the same picking distance
|
||||
pickCon.PivotInB = rayFrom + dir;
|
||||
|
@ -496,8 +438,8 @@ namespace DemoFramework
|
|||
}
|
||||
else if (pickingMultiBodyPoint2Point != null)
|
||||
{
|
||||
Vector3 rayFrom = Freelook.Eye;
|
||||
Vector3 newRayTo = GetRayTo(Input.MousePoint, Freelook.Eye, Freelook.Target, Graphics.FieldOfView);
|
||||
Vector3 rayFrom = FreeLook.Eye;
|
||||
Vector3 newRayTo = GetRayTo(Input.MousePoint, FreeLook.Eye, FreeLook.Target, Graphics.FieldOfView);
|
||||
|
||||
Vector3 dir = (newRayTo - rayFrom);
|
||||
dir.Normalize();
|
||||
|
@ -506,11 +448,11 @@ namespace DemoFramework
|
|||
}
|
||||
}
|
||||
|
||||
void RemovePickingConstraint()
|
||||
private void RemovePickingConstraint()
|
||||
{
|
||||
if (pickConstraint != null && World != null)
|
||||
if (pickConstraint != null)
|
||||
{
|
||||
World.RemoveConstraint(pickConstraint);
|
||||
Simulation.World.RemoveConstraint(pickConstraint);
|
||||
pickConstraint.Dispose();
|
||||
pickConstraint = null;
|
||||
pickedBody.ForceActivationState(ActivationState.ActiveTag);
|
||||
|
@ -521,98 +463,48 @@ namespace DemoFramework
|
|||
if (pickingMultiBodyPoint2Point != null)
|
||||
{
|
||||
pickingMultiBodyPoint2Point.MultiBodyA.CanSleep = prevCanSleep;
|
||||
(World as MultiBodyDynamicsWorld).RemoveMultiBodyConstraint(pickingMultiBodyPoint2Point);
|
||||
(Simulation.World as MultiBodyDynamicsWorld).RemoveMultiBodyConstraint(pickingMultiBodyPoint2Point);
|
||||
pickingMultiBodyPoint2Point.Dispose();
|
||||
pickingMultiBodyPoint2Point = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected Vector3 GetRayTo(Point point, Vector3 eye, Vector3 target, float fov)
|
||||
public Vector3 GetRayTo(Point point, Vector3 eye, Vector3 target, float fieldOfView)
|
||||
{
|
||||
float aspect;
|
||||
|
||||
Vector3 rayForward = target - eye;
|
||||
rayForward.Normalize();
|
||||
const float farPlane = 10000.0f;
|
||||
rayForward *= farPlane;
|
||||
|
||||
Vector3 vertical = Freelook.Up;
|
||||
|
||||
Vector3 hor = Vector3.Cross(rayForward, vertical);
|
||||
hor.Normalize();
|
||||
vertical = Vector3.Cross(hor, rayForward);
|
||||
Vector3 horizontal = Vector3.Cross(rayForward, FreeLook.Up);
|
||||
horizontal.Normalize();
|
||||
Vector3 vertical = Vector3.Cross(horizontal, rayForward);
|
||||
vertical.Normalize();
|
||||
|
||||
float tanFov = (float)Math.Tan(fov / 2);
|
||||
hor *= 2.0f * farPlane * tanFov;
|
||||
float tanFov = (float)Math.Tan(fieldOfView / 2);
|
||||
horizontal *= 2.0f * farPlane * tanFov;
|
||||
vertical *= 2.0f * farPlane * tanFov;
|
||||
|
||||
Size clientSize = Graphics.Form.ClientSize;
|
||||
if (clientSize.Width > clientSize.Height)
|
||||
{
|
||||
aspect = (float)clientSize.Width / (float)clientSize.Height;
|
||||
hor *= aspect;
|
||||
float aspect = (float)clientSize.Width / (float)clientSize.Height;
|
||||
horizontal *= aspect;
|
||||
}
|
||||
else
|
||||
{
|
||||
aspect = (float)clientSize.Height / (float)clientSize.Width;
|
||||
float aspect = (float)clientSize.Height / (float)clientSize.Width;
|
||||
vertical *= aspect;
|
||||
}
|
||||
|
||||
Vector3 rayToCenter = eye + rayForward;
|
||||
Vector3 dHor = hor / (float)clientSize.Width;
|
||||
Vector3 dHor = horizontal / (float)clientSize.Width;
|
||||
Vector3 dVert = vertical / (float)clientSize.Height;
|
||||
|
||||
Vector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical;
|
||||
Vector3 rayTo = rayToCenter - 0.5f * horizontal + 0.5f * vertical;
|
||||
rayTo += (clientSize.Width - point.X) * dHor;
|
||||
rayTo -= point.Y * dVert;
|
||||
return rayTo;
|
||||
}
|
||||
|
||||
public virtual void ShootBox(Vector3 camPos, Vector3 destination)
|
||||
{
|
||||
if (World == null)
|
||||
return;
|
||||
|
||||
const float mass = 1.0f;
|
||||
|
||||
if (shootBoxShape == null)
|
||||
{
|
||||
shootBoxShape = new BoxShape(1.0f);
|
||||
//shootBoxShape.InitializePolyhedralFeatures();
|
||||
}
|
||||
|
||||
RigidBody body = LocalCreateRigidBody(mass, Matrix.Translation(camPos), shootBoxShape);
|
||||
body.LinearFactor = new Vector3(1, 1, 1);
|
||||
//body.Restitution = 1;
|
||||
|
||||
Vector3 linVel = destination - camPos;
|
||||
linVel.Normalize();
|
||||
|
||||
body.LinearVelocity = linVel * shootBoxInitialSpeed;
|
||||
body.CcdMotionThreshold = 0.5f;
|
||||
body.CcdSweptSphereRadius = 0.9f;
|
||||
}
|
||||
|
||||
public virtual RigidBody LocalCreateRigidBody(float mass, Matrix startTransform, CollisionShape shape)
|
||||
{
|
||||
//rigidbody is dynamic if and only if mass is non zero, otherwise static
|
||||
bool isDynamic = (mass != 0.0f);
|
||||
|
||||
Vector3 localInertia = Vector3.Zero;
|
||||
if (isDynamic)
|
||||
shape.CalculateLocalInertia(mass, out localInertia);
|
||||
|
||||
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
|
||||
DefaultMotionState myMotionState = new DefaultMotionState(startTransform);
|
||||
|
||||
RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(mass, myMotionState, shape, localInertia);
|
||||
RigidBody body = new RigidBody(rbInfo);
|
||||
rbInfo.Dispose();
|
||||
|
||||
World.AddRigidBody(body);
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,14 +60,17 @@
|
|||
<Reference Include="System.XML" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="IUpdateReceiver.cs" />
|
||||
<Compile Include="Simulation\BoxShooter.cs" />
|
||||
<Compile Include="Clock.cs" />
|
||||
<Compile Include="Controller\FreeLook.cs" />
|
||||
<Compile Include="Controller\Input.cs" />
|
||||
<Compile Include="Controller\MouseController.cs" />
|
||||
<Compile Include="Demo.cs" />
|
||||
<Compile Include="DemoRunner.cs" />
|
||||
<Compile Include="FileLoaders\BspConverter.cs" />
|
||||
<Compile Include="FileLoaders\BspLoader.cs" />
|
||||
<Compile Include="FileLoaders\Wavefront.cs" />
|
||||
<Compile Include="FileLoaders\WavefrontObj.cs" />
|
||||
<Compile Include="Graphics\BufferedDebugDraw.cs" />
|
||||
<Compile Include="Graphics\GraphicsLibraryManager.cs" />
|
||||
<Compile Include="Graphics\LibrarySelection.cs">
|
||||
|
@ -78,10 +81,14 @@
|
|||
</Compile>
|
||||
<Compile Include="Graphics\Graphics.cs" />
|
||||
<Compile Include="Graphics\MeshFactory.cs" />
|
||||
<Compile Include="Simulation\ISimulation.cs" />
|
||||
<Compile Include="IDemoConfiguration.cs" />
|
||||
<Compile Include="Simulation\PhysicsHelper.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Meshes\Bunny.cs" />
|
||||
<Compile Include="Meshes\Taru.cs" />
|
||||
<Compile Include="Meshes\Torus.cs" />
|
||||
<Compile Include="Simulation\SimulationExtensions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Graphics\LibrarySelection.resx">
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace DemoFramework
|
||||
{
|
||||
public class DemoRunner
|
||||
{
|
||||
public static void Run<T>() where T : IDemoConfiguration, new()
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
|
||||
TryLoadBulletSharp();
|
||||
|
||||
T configuration = new T();
|
||||
Demo demo = new Demo(configuration);
|
||||
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
|
||||
private static bool TryLoadBulletSharp()
|
||||
{
|
||||
try
|
||||
{
|
||||
Assembly.Load("BulletSharp");
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.ToString(), "Error loading BulletSharp");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,80 +1,58 @@
|
|||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace DemoFramework.FileLoaders
|
||||
{
|
||||
public abstract class BspConverter
|
||||
{
|
||||
public abstract void AddCollider(List<Vector3> vertices);
|
||||
|
||||
public void ConvertBsp(BspLoader bspLoader, float scaling)
|
||||
{
|
||||
Vector3 playerStart = GetPlayerPosition(bspLoader);
|
||||
playerStart.Z += 20.0f; //start a bit higher
|
||||
playerStart *= scaling;
|
||||
|
||||
foreach (BspLeaf leaf in bspLoader.Leaves)
|
||||
{
|
||||
bool isValidBrush = false;
|
||||
|
||||
for (int b = 0; b < leaf.NumLeafBrushes; b++)
|
||||
foreach (int brushId in bspLoader.LeafBrushes
|
||||
.Skip(leaf.FirstLeafBrush)
|
||||
.Take(leaf.NumLeafBrushes)
|
||||
.Where(brushId => IsBrushSolid(bspLoader, brushId)))
|
||||
{
|
||||
int brushID = bspLoader.LeafBrushes[leaf.FirstLeafBrush + b];
|
||||
BspBrush brush = bspLoader.Brushes[brushID];
|
||||
|
||||
if (brush.ShaderNum == -1) continue;
|
||||
|
||||
ContentFlags flags = bspLoader.IsVbsp
|
||||
? (ContentFlags)brush.ShaderNum
|
||||
: bspLoader.Shaders[brush.ShaderNum].ContentFlags;
|
||||
|
||||
if ((flags & ContentFlags.Solid) == 0) continue;
|
||||
|
||||
var planeEquations = new List<Vector4>();
|
||||
brush.ShaderNum = -1;
|
||||
|
||||
for (int p = 0; p < brush.NumSides; p++)
|
||||
{
|
||||
int sideId = brush.FirstSide + p;
|
||||
|
||||
BspBrushSide brushside = bspLoader.BrushSides[sideId];
|
||||
BspPlane plane = bspLoader.Planes[brushside.PlaneNum];
|
||||
Vector4 planeEquation = new Vector4(plane.Normal, scaling * -plane.Distance);
|
||||
planeEquations.Add(planeEquation);
|
||||
isValidBrush = true;
|
||||
}
|
||||
if (isValidBrush)
|
||||
{
|
||||
List<Vector3> vertices = GeometryUtil.GetVerticesFromPlaneEquations(planeEquations);
|
||||
const bool isEntity = false;
|
||||
Vector3 entityTarget = Vector3.Zero;
|
||||
AddConvexVerticesCollider(vertices, isEntity, entityTarget);
|
||||
}
|
||||
bspLoader.Brushes[brushId].ShaderNum = -1;
|
||||
OutputBrushAsCollider(bspLoader, scaling, brushId);
|
||||
}
|
||||
}
|
||||
/*
|
||||
foreach (BspEntity entity in bspLoader.Entities)
|
||||
{
|
||||
if (entity.ClassName == "trigger_push")
|
||||
{
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private Vector3 GetPlayerPosition(BspLoader bspLoader)
|
||||
private bool IsBrushSolid(BspLoader bspLoader, int brushId)
|
||||
{
|
||||
BspEntity player;
|
||||
if (bspLoader.Entities.TryGetValue("info_player_start", out player))
|
||||
{
|
||||
return player.Origin;
|
||||
}
|
||||
else if (bspLoader.Entities.TryGetValue("info_player_deathmatch", out player))
|
||||
{
|
||||
return player.Origin;
|
||||
}
|
||||
return new Vector3(0, 0, 100);
|
||||
BspBrush brush = bspLoader.Brushes[brushId];
|
||||
if (brush.ShaderNum == -1) return false;
|
||||
|
||||
ContentFlags flags = bspLoader.IsVbsp
|
||||
? (ContentFlags)brush.ShaderNum
|
||||
: bspLoader.Shaders[brush.ShaderNum].ContentFlags;
|
||||
return (flags & ContentFlags.Solid) != 0;
|
||||
}
|
||||
|
||||
public abstract void AddConvexVerticesCollider(List<Vector3> vertices, bool isEntity, Vector3 entityTargetLocation);
|
||||
private void OutputBrushAsCollider(BspLoader bspLoader, float scaling, int brushId)
|
||||
{
|
||||
BspBrush brush = bspLoader.Brushes[brushId];
|
||||
var sides = bspLoader.BrushSides
|
||||
.Skip(brush.FirstSide)
|
||||
.Take(brush.NumSides);
|
||||
|
||||
var planeEquations = sides.Select(side =>
|
||||
{
|
||||
BspPlane plane = bspLoader.Planes[side.PlaneNum];
|
||||
return new Vector4(plane.Normal, scaling * -plane.Distance);
|
||||
}).ToList();
|
||||
|
||||
if (planeEquations.Count != 0)
|
||||
{
|
||||
List<Vector3> vertices = GeometryUtil.GetVerticesFromPlaneEquations(planeEquations);
|
||||
AddCollider(vertices);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ namespace DemoFramework.FileLoaders
|
|||
public BspLeaf[] Leaves { get; set; }
|
||||
public int[] LeafBrushes { get; set; }
|
||||
public BspPlane[] Planes { get; set; }
|
||||
public List<BspShader> Shaders { get; set; }
|
||||
public BspShader[] Shaders { get; set; }
|
||||
public bool IsVbsp { get; private set; }
|
||||
|
||||
public bool LoadBspFile(string filename)
|
||||
|
@ -206,7 +206,7 @@ namespace DemoFramework.FileLoaders
|
|||
IsVbsp = true;
|
||||
}
|
||||
|
||||
BspLump[] lumps = new BspLump[nHeaderLumps];
|
||||
var lumps = new BspLump[nHeaderLumps];
|
||||
for (int i = 0; i < lumps.Length; i++)
|
||||
{
|
||||
lumps[i].Offset = reader.ReadInt32();
|
||||
|
@ -417,19 +417,19 @@ namespace DemoFramework.FileLoaders
|
|||
if (!IsVbsp)
|
||||
{
|
||||
// read shaders
|
||||
Shaders = new List<BspShader>();
|
||||
buffer.Position = lumps[(int)IBspLumpType.Shaders].Offset;
|
||||
length = lumps[(int)IBspLumpType.Shaders].Length / (64 + 2 * sizeof(int));
|
||||
|
||||
Shaders = new BspShader[length];
|
||||
byte[] shaderBytes = new byte[64];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
BspShader shader = new BspShader();
|
||||
var shader = new BspShader();
|
||||
reader.Read(shaderBytes, 0, 64);
|
||||
shader.Shader = Encoding.ASCII.GetString(shaderBytes, 0, Array.IndexOf(shaderBytes, (byte)0));
|
||||
shader.SurfaceFlags = reader.ReadInt32();
|
||||
shader.ContentFlags = (ContentFlags)reader.ReadInt32();
|
||||
Shaders.Add(shader);
|
||||
Shaders[i] = shader;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ using System.IO;
|
|||
|
||||
namespace DemoFramework.FileLoaders
|
||||
{
|
||||
public class WavefrontObj
|
||||
public sealed class WavefrontObj
|
||||
{
|
||||
private readonly char[] _faceSplitSchars = { '/' };
|
||||
private readonly char[] _lineSplitChars = { ' ' };
|
|
@ -7,7 +7,7 @@ namespace DemoFramework
|
|||
{
|
||||
public abstract class Graphics : IDisposable
|
||||
{
|
||||
public Demo Demo { get; protected set; }
|
||||
public Demo Demo { get; }
|
||||
public Form Form { get; protected set; }
|
||||
|
||||
public virtual float FarPlane { get; set; }
|
||||
|
@ -25,8 +25,6 @@ namespace DemoFramework
|
|||
public virtual bool IsFullScreen { get; set; }
|
||||
public virtual bool CullingEnabled { get; set; }
|
||||
|
||||
public string InfoText { get; private set; }
|
||||
|
||||
public MeshFactory MeshFactory;
|
||||
|
||||
public abstract IDebugDraw GetPhysicsDebugDrawer();
|
||||
|
@ -36,7 +34,6 @@ namespace DemoFramework
|
|||
Demo = demo;
|
||||
FarPlane = 400.0f;
|
||||
FieldOfView = (float)Math.PI / 4;
|
||||
InfoText = "";
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
|
@ -56,9 +53,10 @@ namespace DemoFramework
|
|||
public abstract void Run();
|
||||
public abstract void UpdateView();
|
||||
|
||||
public virtual void SetFormText(string text)
|
||||
public string WindowTitle
|
||||
{
|
||||
Form.Text = text;
|
||||
get { return Form.Text; }
|
||||
set { Form.Text = value; }
|
||||
}
|
||||
|
||||
public virtual void SetInfoText(string text)
|
||||
|
|
|
@ -8,9 +8,7 @@ namespace DemoFramework
|
|||
{
|
||||
public class GraphicsLibraryManager
|
||||
{
|
||||
static LibrarySelection librarySelection;
|
||||
|
||||
const string SettingsFilename = "settings.xml";
|
||||
private const string SettingsFilename = "settings.xml";
|
||||
|
||||
public static string GraphicsLibraryName { get; set; }
|
||||
|
||||
|
@ -114,23 +112,8 @@ namespace DemoFramework
|
|||
return root;
|
||||
}
|
||||
|
||||
public static void Run(Demo demo)
|
||||
private static void LoadSettings()
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
|
||||
// Check if BulletSharp exists
|
||||
try
|
||||
{
|
||||
Assembly.Load("BulletSharp");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.ToString(), "BulletSharp Error!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Load settings
|
||||
XmlElement root = GetSettingsDocumentRoot();
|
||||
|
||||
XmlNodeList l = root.GetElementsByTagName("graphicsframework");
|
||||
|
@ -147,6 +130,11 @@ namespace DemoFramework
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Run(Demo demo)
|
||||
{
|
||||
LoadSettings();
|
||||
|
||||
demo.Run();
|
||||
while (ExitWithReload)
|
||||
|
@ -162,10 +150,10 @@ namespace DemoFramework
|
|||
|
||||
public static bool SelectLibrary()
|
||||
{
|
||||
librarySelection = new LibrarySelection();
|
||||
librarySelection.ShowDialog();
|
||||
librarySelection.Dispose();
|
||||
librarySelection = null;
|
||||
using (var librarySelection = new LibrarySelection())
|
||||
{
|
||||
librarySelection.ShowDialog();
|
||||
}
|
||||
return GraphicsLibraryName != null;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,8 @@ namespace DemoFramework
|
|||
return CreateSphere(shape as SphereShape, out indices);
|
||||
case BroadphaseNativeType.StaticPlaneShape:
|
||||
return CreateStaticPlane(shape as StaticPlaneShape, out indices);
|
||||
case BroadphaseNativeType.TerrainShape:
|
||||
return CreateHeightFieldTerrainShape(shape as HeightfieldTerrainShape, out indices);
|
||||
case BroadphaseNativeType.TriangleMeshShape:
|
||||
indices = null;
|
||||
return CreateTriangleMesh((shape as TriangleMeshShape).MeshInterface);
|
||||
|
@ -798,6 +800,13 @@ namespace DemoFramework
|
|||
return vertices;
|
||||
}
|
||||
|
||||
private static Vector3[] CreateHeightFieldTerrainShape(HeightfieldTerrainShape heightfieldTerrainShape, out uint[] indices)
|
||||
{
|
||||
// HeightfieldTerrainShape does not expose its data
|
||||
indices = null;
|
||||
return new Vector3[1];
|
||||
}
|
||||
|
||||
/*
|
||||
public void UpdateSoftBody(SoftBody softBody, ShapeData shapeData)
|
||||
{
|
||||
|
|
|
@ -129,7 +129,7 @@ namespace DemoFramework.OpenTK
|
|||
|
||||
GL.BindTexture(TextureTarget.Texture2D, texture);
|
||||
|
||||
GL.Begin(PrimitiveType.Quads);
|
||||
GL.Begin(BeginMode.Quads);
|
||||
GL.TexCoord2(0.0f, 1.0f); GL.Vertex2(0, 0);
|
||||
GL.TexCoord2(0.0f, 0.0f); GL.Vertex2(0, height);
|
||||
GL.TexCoord2(1.0f, 0.0f); GL.Vertex2(width, height);
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace DemoFramework.OpenTK
|
|||
public int NormalBufferID;
|
||||
public int ElementBufferID;
|
||||
public DrawElementsType ElementsType;
|
||||
public PrimitiveType PrimitiveType = PrimitiveType.Triangles;
|
||||
public BeginMode PrimitiveType = BeginMode.Triangles;
|
||||
|
||||
public List<InstanceData> Instances = new List<InstanceData>();
|
||||
public Vector3[] SoftBodyVertices;
|
||||
|
@ -338,7 +338,7 @@ namespace DemoFramework.OpenTK
|
|||
s.Instances.Clear();
|
||||
|
||||
// Gather instance data
|
||||
foreach (var colObj in _demo.World.CollisionObjectArray)
|
||||
foreach (var colObj in _demo.Simulation.World.CollisionObjectArray)
|
||||
{
|
||||
var shape = colObj.CollisionShape;
|
||||
|
||||
|
@ -474,7 +474,7 @@ namespace DemoFramework.OpenTK
|
|||
else
|
||||
{
|
||||
shapeData.SetDynamicNormalBuffer(new Vector3[shapeData.VertexCount]); // hack, should use a different shader that doesn't process normals
|
||||
shapeData.PrimitiveType = PrimitiveType.Lines;
|
||||
shapeData.PrimitiveType = BeginMode.Lines;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\bin\Release\BulletSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\packages\OpenTK.2.0.0\lib\net20\OpenTK.dll</HintPath>
|
||||
<Reference Include="OpenTK, Version=1.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\packages\OpenTK.1.1.2349.61993\lib\NET40\OpenTK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK.GLControl, Version=1.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
|
@ -103,7 +103,6 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="OpenTK.dll.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<configuration>
|
||||
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
|
||||
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
|
||||
<dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
|
||||
<dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
|
||||
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
|
||||
<dllmap os="linux" dll="libX11" target="libX11.so.6"/>
|
||||
<dllmap os="linux" dll="libXi" target="libXi.so.6"/>
|
||||
<dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
|
||||
<dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
|
||||
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
|
||||
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
|
||||
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
<dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
<dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
|
||||
<dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
|
||||
<!-- XQuartz compatibility (X11 on Mac) -->
|
||||
<dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
|
||||
<dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
|
||||
<dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
|
||||
<dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
|
||||
<dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
|
||||
<dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
|
||||
</configuration>
|
|
@ -33,7 +33,7 @@ namespace DemoFramework.OpenTK
|
|||
set
|
||||
{
|
||||
base.FarPlane = value;
|
||||
if (Demo.Freelook != null)
|
||||
if (Demo.FreeLook != null)
|
||||
{
|
||||
UpdateView();
|
||||
}
|
||||
|
@ -205,7 +205,6 @@ namespace DemoFramework.OpenTK
|
|||
|
||||
public void Paint()
|
||||
{
|
||||
Demo.OnHandleInput();
|
||||
Demo.OnUpdate();
|
||||
|
||||
Demo.Clock.StartRender();
|
||||
|
@ -223,7 +222,7 @@ namespace DemoFramework.OpenTK
|
|||
{
|
||||
GL.Viewport(0, 0, glControl.Width, glControl.Height);
|
||||
|
||||
FreeLook freelook = Demo.Freelook;
|
||||
FreeLook freelook = Demo.FreeLook;
|
||||
lookat = Matrix4.LookAt(MathHelper.Convert(freelook.Eye), MathHelper.Convert(freelook.Target), MathHelper.Convert(freelook.Up));
|
||||
GL.UniformMatrix4(viewMatrixLocation, false, ref lookat);
|
||||
|
||||
|
@ -247,11 +246,8 @@ namespace DemoFramework.OpenTK
|
|||
viewChanged = false;
|
||||
}
|
||||
|
||||
if (Demo.World != null)
|
||||
{
|
||||
_meshFactory.InitInstancedRender();
|
||||
_meshFactory.RenderInstanced();
|
||||
}
|
||||
_meshFactory.InitInstancedRender();
|
||||
_meshFactory.RenderInstanced();
|
||||
|
||||
GL.UseProgram(0);
|
||||
if (Demo.IsDebugDrawEnabled)
|
||||
|
@ -260,7 +256,7 @@ namespace DemoFramework.OpenTK
|
|||
GL.LoadMatrix(ref lookat);
|
||||
GL.MatrixMode(MatrixMode.Projection);
|
||||
GL.LoadMatrix(ref perspective);
|
||||
(Demo.World.DebugDrawer as PhysicsDebugDraw).DrawDebugWorld(Demo.World);
|
||||
(Demo.Simulation.World.DebugDrawer as PhysicsDebugDraw).DrawDebugWorld((BulletSharp.DynamicsWorld)Demo.Simulation.World);
|
||||
}
|
||||
|
||||
info.OnRender();
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace DemoFramework.OpenTK
|
|||
|
||||
GL.VertexPointer(3, VertexPointerType.Float, 0, positionArray);
|
||||
GL.ColorPointer(3, ColorPointerType.UnsignedByte, sizeof(int), colorArray);
|
||||
GL.DrawArrays(PrimitiveType.Lines, 0, positionArray.Length);
|
||||
GL.DrawArrays(BeginMode.Lines, 0, positionArray.Length);
|
||||
|
||||
GL.DisableClientState(ArrayCap.ColorArray);
|
||||
GL.DisableClientState(ArrayCap.VertexArray);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="OpenTK" version="2.0.0" targetFramework="net40-client" />
|
||||
<package id="OpenTK" version="1.1.2349.61993" targetFramework="net40-client" />
|
||||
<package id="OpenTK.GLControl" version="1.1.2349.61993" targetFramework="net40-client" />
|
||||
</packages>
|
|
@ -307,7 +307,7 @@ namespace DemoFramework.SharpDX11
|
|||
}
|
||||
|
||||
// Gather instance data
|
||||
foreach (var colObj in demo.World.CollisionObjectArray)
|
||||
foreach (var colObj in demo.Simulation.World.CollisionObjectArray)
|
||||
{
|
||||
var shape = colObj.CollisionShape;
|
||||
|
||||
|
|
|
@ -639,7 +639,7 @@ namespace DemoFramework.SharpDX11
|
|||
|
||||
void SetSceneConstants()
|
||||
{
|
||||
FreeLook freelook = Demo.Freelook;
|
||||
FreeLook freelook = Demo.FreeLook;
|
||||
Vector3 up = MathHelper.Convert(freelook.Up);
|
||||
Vector3 eye = MathHelper.Convert(freelook.Eye);
|
||||
Vector4 eyePosition = new Vector4(eye, 1);
|
||||
|
@ -695,16 +695,15 @@ namespace DemoFramework.SharpDX11
|
|||
|
||||
public override void Run()
|
||||
{
|
||||
RenderLoop.Run(Form, () =>
|
||||
RenderLoop.Run(Form, (RenderLoop.RenderCallback)(() =>
|
||||
{
|
||||
Demo.OnHandleInput();
|
||||
Demo.OnUpdate();
|
||||
if (Form.WindowState == FormWindowState.Minimized)
|
||||
return;
|
||||
Demo.Clock.StartRender();
|
||||
Render();
|
||||
Demo.Clock.StopRender();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
protected virtual void OnInitialize()
|
||||
|
@ -763,7 +762,7 @@ namespace DemoFramework.SharpDX11
|
|||
if (Demo.IsDebugDrawEnabled)
|
||||
{
|
||||
debugDrawPass.Apply(_immediateContext);
|
||||
(Demo.World.DebugDrawer as PhysicsDebugDraw).DrawDebugWorld(Demo.World);
|
||||
(Demo.Simulation.World.DebugDrawer as PhysicsDebugDraw).DrawDebugWorld((DynamicsWorld)Demo.Simulation.World);
|
||||
}
|
||||
|
||||
// Light accumulation
|
||||
|
@ -797,7 +796,7 @@ namespace DemoFramework.SharpDX11
|
|||
{
|
||||
float radius = light.Radius;
|
||||
float bias = radius * 2;
|
||||
if ((light.Position - MathHelper.Convert(Demo.Freelook.Eye)).LengthSquared() >= (radius * radius) + bias)
|
||||
if ((light.Position - MathHelper.Convert(Demo.FreeLook.Eye)).LengthSquared() >= (radius * radius) + bias)
|
||||
{
|
||||
RenderLight(light);
|
||||
}
|
||||
|
@ -809,7 +808,7 @@ namespace DemoFramework.SharpDX11
|
|||
foreach (var light in lights)
|
||||
{
|
||||
float bias = light.Radius * 2;
|
||||
if ((light.Position - MathHelper.Convert(Demo.Freelook.Eye)).LengthSquared() < (light.Radius * light.Radius) + bias)
|
||||
if ((light.Position - MathHelper.Convert(Demo.FreeLook.Eye)).LengthSquared() < (light.Radius * light.Radius) + bias)
|
||||
{
|
||||
RenderLight(light);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace DemoFramework.SlimDX
|
|||
set
|
||||
{
|
||||
base.FarPlane = value;
|
||||
if (Context9 != null && Demo.Freelook != null)
|
||||
if (Context9 != null && Demo.FreeLook != null)
|
||||
{
|
||||
UpdateView();
|
||||
}
|
||||
|
@ -257,7 +257,7 @@ namespace DemoFramework.SlimDX
|
|||
Device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.LightGray, 1.0f, 0);
|
||||
Device.BeginScene();
|
||||
|
||||
foreach (CollisionObject colObj in Demo.World.CollisionObjectArray)
|
||||
foreach (CollisionObject colObj in Demo.Simulation.World.CollisionObjectArray)
|
||||
{
|
||||
if (colObj is SoftBody)
|
||||
{
|
||||
|
@ -281,8 +281,8 @@ namespace DemoFramework.SlimDX
|
|||
}
|
||||
|
||||
if (Demo.IsDebugDrawEnabled)
|
||||
(Demo.World.DebugDrawer as PhysicsDebugDraw).DrawDebugWorld(Demo.World);
|
||||
Info.OnRender(Demo.FramesPerSecond);
|
||||
(Demo.Simulation.World.DebugDrawer as PhysicsDebugDraw).DrawDebugWorld((DynamicsWorld)Demo.Simulation.World);
|
||||
Info.OnRender((float)Demo.FramesPerSecond);
|
||||
|
||||
Device.EndScene();
|
||||
Device.Present();
|
||||
|
@ -303,7 +303,7 @@ namespace DemoFramework.SlimDX
|
|||
|
||||
public override void UpdateView()
|
||||
{
|
||||
FreeLook freelook = Demo.Freelook;
|
||||
FreeLook freelook = Demo.FreeLook;
|
||||
Device.SetTransform(TransformState.View, Matrix.LookAtLH(MathHelper.Convert(freelook.Eye), MathHelper.Convert(freelook.Target), MathHelper.Convert(freelook.Up)));
|
||||
}
|
||||
|
||||
|
@ -316,7 +316,6 @@ namespace DemoFramework.SlimDX
|
|||
|
||||
MessagePump.Run(Form, () =>
|
||||
{
|
||||
Demo.OnHandleInput();
|
||||
Demo.OnUpdate();
|
||||
|
||||
if (isFormClosed)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
namespace DemoFramework
|
||||
{
|
||||
public interface IDemoConfiguration
|
||||
{
|
||||
ISimulation CreateSimulation(Demo demo);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace DemoFramework
|
||||
{
|
||||
public interface IUpdateReceiver
|
||||
{
|
||||
void Update(Demo demo);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace DemoFramework
|
||||
{
|
||||
public sealed class BoxShooter : IDisposable
|
||||
{
|
||||
private readonly DynamicsWorld _world;
|
||||
|
||||
private BoxShape _shootBoxShape;
|
||||
private const float ShootBoxInitialSpeed = 40;
|
||||
private const float BoxHalfExtent = 1.0f;
|
||||
|
||||
public BoxShooter(DynamicsWorld world)
|
||||
{
|
||||
_world = world;
|
||||
}
|
||||
|
||||
public void Shoot(Vector3 eyePosition, Vector3 destination)
|
||||
{
|
||||
const float mass = 1.0f;
|
||||
|
||||
if (_shootBoxShape == null)
|
||||
{
|
||||
_shootBoxShape = new BoxShape(BoxHalfExtent);
|
||||
//shootBoxShape.InitializePolyhedralFeatures();
|
||||
}
|
||||
|
||||
RigidBody body = PhysicsHelper.CreateBody(mass, Matrix.Translation(eyePosition), _shootBoxShape, _world);
|
||||
body.LinearFactor = new Vector3(1, 1, 1);
|
||||
//body.Restitution = 1;
|
||||
|
||||
Vector3 linVel = destination - eyePosition;
|
||||
linVel.Normalize();
|
||||
body.LinearVelocity = linVel * ShootBoxInitialSpeed;
|
||||
body.CcdMotionThreshold = 0.5f;
|
||||
body.CcdSweptSphereRadius = 0.9f;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_shootBoxShape != null)
|
||||
{
|
||||
var objects = _world.CollisionObjectArray
|
||||
.Where(o => o.CollisionShape == _shootBoxShape);
|
||||
foreach (var obj in objects)
|
||||
{
|
||||
_world.RemoveCollisionObject(obj);
|
||||
obj.Dispose();
|
||||
}
|
||||
|
||||
_shootBoxShape.Dispose();
|
||||
_shootBoxShape = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using BulletSharp;
|
||||
using System;
|
||||
|
||||
namespace DemoFramework
|
||||
{
|
||||
public interface ISimulation : IDisposable
|
||||
{
|
||||
CollisionConfiguration CollisionConfiguration { get; }
|
||||
CollisionDispatcher Dispatcher { get; }
|
||||
BroadphaseInterface Broadphase { get; }
|
||||
DiscreteDynamicsWorld World { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
|
||||
namespace DemoFramework
|
||||
{
|
||||
public static class PhysicsHelper
|
||||
{
|
||||
public static RigidBody CreateBody(float mass, Matrix startTransform, CollisionShape shape, DynamicsWorld world)
|
||||
{
|
||||
// A body with zero mass is considered static
|
||||
if (mass == 0)
|
||||
{
|
||||
return CreateStaticBody(startTransform, shape, world);
|
||||
}
|
||||
|
||||
// Using a motion state is recommended,
|
||||
// it provides interpolation capabilities and only synchronizes "active" objects
|
||||
var myMotionState = new DefaultMotionState(startTransform);
|
||||
|
||||
Vector3 localInertia = shape.CalculateLocalInertia(mass);
|
||||
|
||||
RigidBody body;
|
||||
using (var rbInfo = new RigidBodyConstructionInfo(mass, myMotionState, shape, localInertia))
|
||||
{
|
||||
body = new RigidBody(rbInfo);
|
||||
}
|
||||
|
||||
if (world != null)
|
||||
{
|
||||
world.AddRigidBody(body);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
public static RigidBody CreateStaticBody(Matrix startTransform, CollisionShape shape, DynamicsWorld world)
|
||||
{
|
||||
const float staticMass = 0;
|
||||
|
||||
RigidBody body;
|
||||
using (var rbInfo = new RigidBodyConstructionInfo(staticMass, null, shape)
|
||||
{
|
||||
StartWorldTransform = startTransform
|
||||
})
|
||||
{
|
||||
body = new RigidBody(rbInfo);
|
||||
}
|
||||
|
||||
if (world != null)
|
||||
{
|
||||
world.AddRigidBody(body);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
using BulletSharp;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace DemoFramework
|
||||
{
|
||||
public static class SimulationExtensions
|
||||
{
|
||||
public static void StandardCleanup(this ISimulation simulation)
|
||||
{
|
||||
CleanupConstraints(simulation.World);
|
||||
CleanupBodiesAndShapes(simulation.World);
|
||||
|
||||
var multiBodyWorld = simulation.World as MultiBodyDynamicsWorld;
|
||||
if (multiBodyWorld != null)
|
||||
{
|
||||
CleanupMultiBodyWorld(multiBodyWorld);
|
||||
}
|
||||
|
||||
simulation.World.Dispose();
|
||||
simulation.Broadphase.Dispose();
|
||||
simulation.Dispatcher.Dispose();
|
||||
simulation.CollisionConfiguration.Dispose();
|
||||
}
|
||||
|
||||
private static void CleanupConstraints(DynamicsWorld world)
|
||||
{
|
||||
for (int i = world.NumConstraints - 1; i >= 0; i--)
|
||||
{
|
||||
TypedConstraint constraint = world.GetConstraint(i);
|
||||
world.RemoveConstraint(constraint);
|
||||
constraint.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CleanupBodiesAndShapes(DynamicsWorld world)
|
||||
{
|
||||
var shapes = new HashSet<CollisionShape>();
|
||||
|
||||
for (int i = world.NumCollisionObjects - 1; i >= 0; i--)
|
||||
{
|
||||
CollisionObject obj = world.CollisionObjectArray[i];
|
||||
var body = obj as RigidBody;
|
||||
if (body != null && body.MotionState != null)
|
||||
{
|
||||
body.MotionState.Dispose();
|
||||
}
|
||||
world.RemoveCollisionObject(obj);
|
||||
GetShapeWithChildShapes(obj.CollisionShape, shapes);
|
||||
|
||||
obj.Dispose();
|
||||
}
|
||||
|
||||
foreach (var shape in shapes)
|
||||
{
|
||||
shape.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CleanupMultiBodyWorld(MultiBodyDynamicsWorld world)
|
||||
{
|
||||
for (int i = world.NumMultiBodyConstraints - 1; i >= 0; i--)
|
||||
{
|
||||
MultiBodyConstraint multiBodyConstraint = world.GetMultiBodyConstraint(i);
|
||||
world.RemoveMultiBodyConstraint(multiBodyConstraint);
|
||||
multiBodyConstraint.Dispose();
|
||||
}
|
||||
|
||||
for (int i = world.NumMultibodies - 1; i >= 0; i--)
|
||||
{
|
||||
MultiBody multiBody = world.GetMultiBody(i);
|
||||
world.RemoveMultiBody(multiBody);
|
||||
multiBody.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetShapeWithChildShapes(CollisionShape shape, HashSet<CollisionShape> shapes)
|
||||
{
|
||||
shapes.Add(shape);
|
||||
|
||||
var convex2DShape = shape as Convex2DShape;
|
||||
if (convex2DShape != null)
|
||||
{
|
||||
GetShapeWithChildShapes(convex2DShape.ChildShape, shapes);
|
||||
return;
|
||||
}
|
||||
|
||||
var compoundShape = shape as CompoundShape;
|
||||
if (compoundShape != null)
|
||||
{
|
||||
foreach (var childShape in compoundShape.ChildList)
|
||||
{
|
||||
GetShapeWithChildShapes(childShape.ChildShape, shapes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,85 +6,100 @@ using System.Drawing;
|
|||
|
||||
namespace DistanceDemo
|
||||
{
|
||||
class DistanceDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(30, 20, 10);
|
||||
Vector3 target = new Vector3(0, 5, -4);
|
||||
|
||||
Vector3 distanceFrom, distanceTo;
|
||||
float distance;
|
||||
|
||||
Matrix rotBodyPosition = Matrix.Translation(0, 10, 0);
|
||||
Matrix body2Position = Matrix.Translation(0, 5, 0);
|
||||
RigidBody rotBody, body2;
|
||||
ConvexShape colShape0, colShape1;
|
||||
|
||||
VoronoiSimplexSolver sGjkSimplexSolver = new VoronoiSimplexSolver();
|
||||
|
||||
float rotation = 0;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
DemoRunner.Run<DistanceDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Distance Demo");
|
||||
internal sealed class DistanceDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
private float _rotation = 0;
|
||||
|
||||
IsDebugDrawEnabled = true;
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
_rotation = 0;
|
||||
demo.FreeLook.Eye = new Vector3(30, 20, 10);
|
||||
demo.FreeLook.Target = new Vector3(0, 5, -4);
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Distance Demo";
|
||||
demo.IsDebugDrawEnabled = true;
|
||||
return new DistanceDemoSimulation();
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
var simulation = demo.Simulation as DistanceDemoSimulation;
|
||||
|
||||
_rotation += demo.FrameDelta;
|
||||
simulation.SetRotation(_rotation);
|
||||
|
||||
if (demo.IsDebugDrawEnabled)
|
||||
{
|
||||
simulation.DrawDistance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DistanceDemoSimulation : ISimulation
|
||||
{
|
||||
private readonly Matrix _rotBodyPosition = Matrix.Translation(0, 10, 0);
|
||||
private RigidBody _rotatingBody, _staticBody;
|
||||
private ConvexShape _rotatingShape, _staticShape;
|
||||
|
||||
private VoronoiSimplexSolver _gjkSimplexSolver = new VoronoiSimplexSolver();
|
||||
|
||||
private static Vector3 _red = new Vector3(1.0f, 0.0f, 0.0f);
|
||||
|
||||
public DistanceDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Broadphase = new DbvtBroadphase();
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
CreateGround();
|
||||
|
||||
// ground
|
||||
CollisionShape groundShape = new BoxShape(50, 1, 50);
|
||||
CollisionShapes.Add(groundShape);
|
||||
CollisionObject ground = LocalCreateRigidBody(0, Matrix.Identity, groundShape);
|
||||
ground.UserObject = "Ground";
|
||||
|
||||
// Objects
|
||||
//colShape = new BoxShape(1);
|
||||
Vector3[] points0 = {
|
||||
Vector3[] rotatingPoints = {
|
||||
new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1)
|
||||
};
|
||||
Vector3[] points1 = {
|
||||
_rotatingShape = new ConvexHullShape(rotatingPoints);
|
||||
_rotatingBody = PhysicsHelper.CreateStaticBody(_rotBodyPosition, _rotatingShape, World);
|
||||
_rotatingBody.CollisionFlags |= CollisionFlags.KinematicObject;
|
||||
_rotatingBody.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
Vector3[] staticPoints = {
|
||||
new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1), new Vector3(0,0,-1), new Vector3(-1,-1,0)
|
||||
};
|
||||
colShape0 = new ConvexHullShape(points0);
|
||||
colShape1 = new ConvexHullShape(points1);
|
||||
CollisionShapes.Add(colShape0);
|
||||
CollisionShapes.Add(colShape1);
|
||||
|
||||
body2 = LocalCreateRigidBody(0, body2Position, colShape1);
|
||||
|
||||
rotBody = LocalCreateRigidBody(0, rotBodyPosition, colShape0);
|
||||
rotBody.CollisionFlags |= CollisionFlags.KinematicObject;
|
||||
rotBody.ActivationState = ActivationState.DisableDeactivation;
|
||||
_staticShape = new ConvexHullShape(staticPoints);
|
||||
Matrix staticBodyPosition = Matrix.Translation(0, 5, 0);
|
||||
_staticBody = PhysicsHelper.CreateStaticBody(staticBodyPosition, _staticShape, World);
|
||||
}
|
||||
|
||||
static Vector3 red = new Vector3(1.0f, 0.0f, 0.0f);
|
||||
public override void OnUpdate()
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
internal void SetRotation(float rotation)
|
||||
{
|
||||
base.OnUpdate();
|
||||
|
||||
rotation += FrameDelta;
|
||||
rotBody.CenterOfMassTransform = Matrix.RotationX(rotation) * rotBodyPosition;
|
||||
_rotatingBody.CenterOfMassTransform = Matrix.RotationX(rotation) * _rotBodyPosition;
|
||||
_rotatingBody.WorldTransform = _rotatingBody.CenterOfMassTransform;
|
||||
}
|
||||
|
||||
public void DrawDistance()
|
||||
{
|
||||
var input = new DiscreteCollisionDetectorInterface.ClosestPointInput
|
||||
{
|
||||
TransformA = rotBody.CenterOfMassTransform,
|
||||
TransformB = body2Position
|
||||
TransformA = _rotatingBody.CenterOfMassTransform,
|
||||
TransformB = _staticBody.CenterOfMassTransform
|
||||
};
|
||||
|
||||
using (var result = new PointCollector())
|
||||
{
|
||||
using (var detector = new GjkPairDetector(colShape0, colShape1, sGjkSimplexSolver, null))
|
||||
using (var detector = new GjkPairDetector(_rotatingShape, _staticShape, _gjkSimplexSolver, null))
|
||||
{
|
||||
detector.CachedSeparatingAxis = new Vector3(0.00000000f, 0.059727669f, 0.29259586f);
|
||||
detector.GetClosestPoints(input, result, null);
|
||||
|
@ -92,24 +107,25 @@ namespace DistanceDemo
|
|||
|
||||
if (result.HasResult)
|
||||
{
|
||||
distanceFrom = result.PointInWorld;
|
||||
distanceTo = result.PointInWorld + result.NormalOnBInWorld * result.Distance;
|
||||
distance = result.Distance;
|
||||
World.DebugDrawer.DrawLine(ref distanceFrom, ref distanceTo, ref red);
|
||||
Vector3 distanceFrom = result.PointInWorld;
|
||||
Vector3 distanceTo = result.PointInWorld + result.NormalOnBInWorld * result.Distance;
|
||||
World.DebugDrawer.DrawLine(ref distanceFrom, ref distanceTo, ref _red);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
public void Dispose()
|
||||
{
|
||||
using (Demo demo = new DistanceDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
_gjkSimplexSolver.Dispose();
|
||||
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
var groundShape = new BoxShape(50, 1, 50);
|
||||
CollisionObject ground = PhysicsHelper.CreateStaticBody(Matrix.Identity, groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,74 +5,63 @@ using System;
|
|||
|
||||
namespace FeatherStoneDemo
|
||||
{
|
||||
class FeatherStoneDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(0, 5, 10);
|
||||
Vector3 target = new Vector3(0, 0, 0);
|
||||
|
||||
// create 125 (5x5x5) dynamic objects
|
||||
const int ArraySizeX = 5, ArraySizeY = 5, ArraySizeZ = 5;
|
||||
|
||||
// scaling of the objects (0.1 = 20 centimeter boxes )
|
||||
const float StartPosX = -5;
|
||||
const float StartPosY = 2;
|
||||
const float StartPosZ = -3;
|
||||
|
||||
const float Friction = 1.0f;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - FeatherStone Demo");
|
||||
DemoRunner.Run<FeatherStoneDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
internal sealed class FeatherStoneDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
demo.FreeLook.Eye = new Vector3(0, 5, 10);
|
||||
demo.FreeLook.Target = Vector3.Zero;
|
||||
demo.Graphics.WindowTitle = "BulletSharp - FeatherStone Demo";
|
||||
return new FeatherStoneDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class FeatherStoneDemoSimulation : ISimulation
|
||||
{
|
||||
private const int NumBoxesX = 5, NumBoxesY = 5, NumBoxesZ = 5;
|
||||
private Vector3 _startPosition = new Vector3(-5, 2, -3);
|
||||
|
||||
private const float Friction = 1.0f;
|
||||
|
||||
private MultiBodyConstraintSolver _solver;
|
||||
|
||||
public FeatherStoneDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Broadphase = new DbvtBroadphase();
|
||||
Solver = new MultiBodyConstraintSolver();
|
||||
|
||||
World = new MultiBodyDynamicsWorld(Dispatcher, Broadphase, Solver as MultiBodyConstraintSolver, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
|
||||
// create a few basic rigid bodies
|
||||
BoxShape groundShape = new BoxShape(50, 50, 50);
|
||||
//groundShape.InitializePolyhedralFeatures();
|
||||
//CollisionShape groundShape = new StaticPlaneShape(new Vector3(0,1,0), 50);
|
||||
|
||||
CollisionShapes.Add(groundShape);
|
||||
CollisionObject ground = LocalCreateRigidBody(0, Matrix.Translation(0, -51.55f, 0), groundShape);
|
||||
ground.UserObject = "Ground";
|
||||
_solver = new MultiBodyConstraintSolver();
|
||||
MultiBodyWorld = new MultiBodyDynamicsWorld(Dispatcher, Broadphase, _solver, CollisionConfiguration);
|
||||
|
||||
CreateGround();
|
||||
|
||||
int numLinks = 5;
|
||||
bool spherical = true;
|
||||
bool floatingBase = false;
|
||||
Vector3 basePosition = new Vector3(-0.4f, 3.0f, 0.0f);
|
||||
Vector3 baseHalfExtents = new Vector3(0.05f, 0.37f, 0.1f);
|
||||
Vector3 linkHalfExtents = new Vector3(0.05f, 0.37f, 0.1f);
|
||||
var mb = CreateFeatherstoneMultiBody(World as MultiBodyDynamicsWorld, numLinks, basePosition, baseHalfExtents, linkHalfExtents, spherical, floatingBase);
|
||||
|
||||
floatingBase = !floatingBase;
|
||||
|
||||
mb.CanSleep = true;
|
||||
mb.HasSelfCollision = false;
|
||||
mb.UseGyroTerm = true;
|
||||
var basePosition = new Vector3(-0.4f, 3.0f, 0.0f);
|
||||
var baseHalfExtents = new Vector3(0.05f, 0.37f, 0.1f);
|
||||
var linkHalfExtents = new Vector3(0.05f, 0.37f, 0.1f);
|
||||
var multiBody = CreateFeatherstoneMultiBody(MultiBodyWorld, numLinks, basePosition, baseHalfExtents, linkHalfExtents, spherical, floatingBase);
|
||||
|
||||
bool damping = true;
|
||||
if (damping)
|
||||
{
|
||||
mb.LinearDamping = 0.1f;
|
||||
mb.AngularDamping = 0.9f;
|
||||
multiBody.LinearDamping = 0.1f;
|
||||
multiBody.AngularDamping = 0.9f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mb.LinearDamping = 0;
|
||||
mb.AngularDamping = 0;
|
||||
multiBody.LinearDamping = 0;
|
||||
multiBody.AngularDamping = 0;
|
||||
}
|
||||
|
||||
if (numLinks > 0)
|
||||
|
@ -82,20 +71,43 @@ namespace FeatherStoneDemo
|
|||
{
|
||||
Quaternion quat0 = Quaternion.RotationAxis(Vector3.Normalize(new Vector3(1, 1, 0)), q0);
|
||||
quat0.Normalize();
|
||||
mb.SetJointPosMultiDof(0, new float[] { quat0.X, quat0.Y, quat0.Z, quat0.W });
|
||||
multiBody.SetJointPosMultiDof(0, new float[] { quat0.X, quat0.Y, quat0.Z, quat0.W });
|
||||
}
|
||||
else
|
||||
{
|
||||
mb.SetJointPosMultiDof(0, new float[] { q0 });
|
||||
multiBody.SetJointPosMultiDof(0, new float[] { q0 });
|
||||
}
|
||||
}
|
||||
AddColliders(mb, baseHalfExtents, linkHalfExtents);
|
||||
CreateColliders(multiBody, baseHalfExtents, linkHalfExtents);
|
||||
|
||||
|
||||
LocalCreateRigidBody(1, Matrix.Translation(0, -0.95f, 0), new BoxShape(0.5f, 0.5f, 0.5f));
|
||||
CreateRigidBody(1, Matrix.Translation(0, -0.95f, 0), new BoxShape(0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
|
||||
MultiBody CreateFeatherstoneMultiBody(MultiBodyDynamicsWorld world, int numLinks,
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World => MultiBodyWorld;
|
||||
private MultiBodyDynamicsWorld MultiBodyWorld { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_solver.Dispose();
|
||||
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
var groundShape = new BoxShape(50, 50, 50);
|
||||
//groundShape.InitializePolyhedralFeatures();
|
||||
//var groundShape = new StaticPlaneShape(new Vector3(0, 1, 0), 50);
|
||||
|
||||
CollisionObject ground = CreateRigidBody(0, Matrix.Translation(0, -51.55f, 0), groundShape);
|
||||
ground.UserObject = "Ground";
|
||||
}
|
||||
|
||||
private MultiBody CreateFeatherstoneMultiBody(MultiBodyDynamicsWorld world, int numLinks,
|
||||
Vector3 basePosition, Vector3 baseHalfExtents, Vector3 linkHalfExtents, bool spherical, bool floating)
|
||||
{
|
||||
float mass = 1;
|
||||
|
@ -108,13 +120,17 @@ namespace FeatherStoneDemo
|
|||
}
|
||||
}
|
||||
|
||||
var mb = new MultiBody(numLinks, mass, inertia, !floating, false);
|
||||
//body.HasSelfCollision = false;
|
||||
var multiBody = new MultiBody(numLinks, mass, inertia, !floating, false)
|
||||
{
|
||||
HasSelfCollision = false,
|
||||
CanSleep = true,
|
||||
UseGyroTerm = true,
|
||||
BasePosition = basePosition
|
||||
};
|
||||
|
||||
//body.BaseVelocity = Vector3.Zero;
|
||||
mb.BasePosition = basePosition;
|
||||
//body.WorldToBaseRot = new Quaternion(0, 0, 1, -0.125f * (float)Math.PI);
|
||||
mb.WorldToBaseRot = Quaternion.Identity;
|
||||
//multiBody.BaseVelocity = Vector3.Zero;
|
||||
//multiBody.WorldToBaseRot = new Quaternion(0, 0, 1, -0.125f * (float)Math.PI);
|
||||
multiBody.WorldToBaseRot = Quaternion.Identity;
|
||||
|
||||
float linkMass = 1;
|
||||
Vector3 linkInertia = Vector3.Zero;
|
||||
|
@ -135,63 +151,54 @@ namespace FeatherStoneDemo
|
|||
{
|
||||
if (spherical)
|
||||
{
|
||||
mb.SetupSpherical(i, linkMass, linkInertia, i - 1,
|
||||
multiBody.SetupSpherical(i, linkMass, linkInertia, i - 1,
|
||||
Quaternion.Identity, parentComToCurrentPivot, currentPivotToCurrentCom, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 hingeJointAxis = new Vector3(1, 0, 0);
|
||||
mb.SetupRevolute(i, linkMass, linkInertia, i - 1,
|
||||
multiBody.SetupRevolute(i, linkMass, linkInertia, i - 1,
|
||||
Quaternion.Identity, hingeJointAxis, parentComToCurrentPivot, currentPivotToCurrentCom, false);
|
||||
}
|
||||
}
|
||||
|
||||
mb.FinalizeMultiDof();
|
||||
multiBody.FinalizeMultiDof();
|
||||
|
||||
(World as MultiBodyDynamicsWorld).AddMultiBody(mb);
|
||||
MultiBodyWorld.AddMultiBody(multiBody);
|
||||
|
||||
return mb;
|
||||
return multiBody;
|
||||
}
|
||||
|
||||
void AddBoxes()
|
||||
private void CreateBoxes()
|
||||
{
|
||||
// create a few dynamic rigidbodies
|
||||
const float mass = 1.0f;
|
||||
|
||||
BoxShape colShape = new BoxShape(1);
|
||||
CollisionShapes.Add(colShape);
|
||||
Vector3 localInertia = colShape.CalculateLocalInertia(mass);
|
||||
BoxShape shape = new BoxShape(1);
|
||||
Vector3 localInertia = shape.CalculateLocalInertia(mass);
|
||||
|
||||
const float startX = StartPosX - ArraySizeX / 2;
|
||||
const float startY = StartPosY;
|
||||
const float startZ = StartPosZ - ArraySizeZ / 2;
|
||||
var rbInfo = new RigidBodyConstructionInfo(mass, null, shape, localInertia);
|
||||
|
||||
for (int k = 0; k < ArraySizeY; k++)
|
||||
for (int y = 0; y < NumBoxesY; y++)
|
||||
{
|
||||
for (int i = 0; i < ArraySizeX; i++)
|
||||
for (int x = 0; x < NumBoxesX; x++)
|
||||
{
|
||||
for (int j = 0; j < ArraySizeZ; j++)
|
||||
for (int z = 0; z < NumBoxesZ; z++)
|
||||
{
|
||||
Matrix startTransform = Matrix.Translation(
|
||||
3 * i + startX,
|
||||
3 * k + startY,
|
||||
3 * j + startZ
|
||||
);
|
||||
Vector3 position = _startPosition + 3 * new Vector3(x, y, z);
|
||||
|
||||
// using motionstate is recommended, it provides interpolation capabilities
|
||||
// and only synchronizes 'active' objects
|
||||
DefaultMotionState myMotionState = new DefaultMotionState(startTransform);
|
||||
using (var rbInfo = new RigidBodyConstructionInfo(mass, myMotionState, colShape, localInertia))
|
||||
{
|
||||
var body = new RigidBody(rbInfo);
|
||||
World.AddRigidBody(body);
|
||||
}
|
||||
rbInfo.MotionState = new DefaultMotionState(Matrix.Translation(position));
|
||||
var body = new RigidBody(rbInfo);
|
||||
World.AddRigidBody(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rbInfo.Dispose();
|
||||
}
|
||||
|
||||
void AddColliders(MultiBody multiBody, Vector3 baseHalfExtents, Vector3 linkHalfExtents)
|
||||
private void CreateColliders(MultiBody multiBody, Vector3 baseHalfExtents, Vector3 linkHalfExtents)
|
||||
{
|
||||
// Add a collider for the base
|
||||
Quaternion[] worldToLocal = new Quaternion[multiBody.NumLinks + 1];
|
||||
|
@ -236,7 +243,7 @@ namespace FeatherStoneDemo
|
|||
}
|
||||
}
|
||||
|
||||
public override RigidBody LocalCreateRigidBody(float mass, Matrix startTransform, CollisionShape shape)
|
||||
private RigidBody CreateRigidBody(float mass, Matrix startTransform, CollisionShape shape)
|
||||
{
|
||||
//rigidbody is dynamic if and only if mass is non zero, otherwise static
|
||||
bool isDynamic = (mass != 0.0f);
|
||||
|
@ -260,16 +267,4 @@ namespace FeatherStoneDemo
|
|||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new FeatherStoneDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
#define TEST_GIMPACT_TORUS
|
||||
//#define BULLET_TRIANGLE_COLLISION
|
||||
#define BULLET_GIMPACT
|
||||
//#define BULLET_GIMPACT_CONVEX_DECOMPOSITION
|
||||
|
||||
using BulletSharp;
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using DemoFramework;
|
||||
using DemoFramework.Meshes;
|
||||
|
@ -12,277 +7,180 @@ using System.Windows.Forms;
|
|||
|
||||
namespace GImpactTestDemo
|
||||
{
|
||||
class GImpactTestDemo : Demo
|
||||
{
|
||||
Vector3 eye = new Vector3(0, 10, 50);
|
||||
Vector3 target = new Vector3(0, 10, -4);
|
||||
|
||||
CollisionShape trimeshShape;
|
||||
CollisionShape trimeshShape2;
|
||||
|
||||
TriangleIndexVertexArray indexVertexArrays;
|
||||
TriangleIndexVertexArray indexVertexArrays2;
|
||||
|
||||
Vector3 kinTorusTran;
|
||||
Quaternion kinTorusRot;
|
||||
RigidBody kinematicTorus;
|
||||
|
||||
const float ShootBoxInitialSpeed = 40.0f;
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - GImpact Test Demo");
|
||||
DemoText = ". - Shoot Bunny";
|
||||
|
||||
Graphics.FarPlane = 400.0f;
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
|
||||
//Broadphase = new SimpleBroadphase();
|
||||
Broadphase = new AxisSweep3_32Bit(new Vector3(-10000, -10000, -10000), new Vector3(10000, 10000, 10000), 1024);
|
||||
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
|
||||
|
||||
// create trimesh model and shape
|
||||
InitGImpactCollision();
|
||||
|
||||
// Create Scene
|
||||
float mass = 0.0f;
|
||||
|
||||
CollisionShape staticboxShape1 = new BoxShape(200, 1, 200);//floor
|
||||
CollisionShapes.Add(staticboxShape1);
|
||||
LocalCreateRigidBody(mass, Matrix.Translation(0, -10, 0), staticboxShape1);
|
||||
|
||||
CollisionShape staticboxShape2 = new BoxShape(1, 50, 200);//left wall
|
||||
CollisionShapes.Add(staticboxShape2);
|
||||
LocalCreateRigidBody(mass, Matrix.Translation(-200, 15, 0), staticboxShape2);
|
||||
|
||||
CollisionShape staticboxShape3 = new BoxShape(1, 50, 200);//right wall
|
||||
CollisionShapes.Add(staticboxShape3);
|
||||
LocalCreateRigidBody(mass, Matrix.Translation(200, 15, 0), staticboxShape3);
|
||||
|
||||
CollisionShape staticboxShape4 = new BoxShape(200, 50, 1);//front wall
|
||||
CollisionShapes.Add(staticboxShape4);
|
||||
LocalCreateRigidBody(mass, Matrix.Translation(0, 15, 200), staticboxShape4);
|
||||
|
||||
CollisionShape staticboxShape5 = new BoxShape(200, 50, 1);//back wall
|
||||
CollisionShapes.Add(staticboxShape5);
|
||||
LocalCreateRigidBody(mass, Matrix.Translation(0, 15, -200), staticboxShape5);
|
||||
|
||||
|
||||
//static plane
|
||||
|
||||
Vector3 normal = new Vector3(-0.5f, 0.5f, 0.0f);
|
||||
normal.Normalize();
|
||||
CollisionShape staticplaneShape6 = new StaticPlaneShape(normal, 0.5f);// A plane
|
||||
CollisionShapes.Add(staticplaneShape6);
|
||||
RigidBody staticBody2 = LocalCreateRigidBody(mass, Matrix.Translation(0, -9, 0), staticplaneShape6);
|
||||
|
||||
|
||||
//another static plane
|
||||
|
||||
normal = new Vector3(0.5f, 0.7f, 0.0f);
|
||||
//normal.Normalize();
|
||||
CollisionShape staticplaneShape7 = new StaticPlaneShape(normal, 0.0f);// A plane
|
||||
CollisionShapes.Add(staticplaneShape7);
|
||||
staticBody2 = LocalCreateRigidBody(mass, Matrix.Translation(0, -10, 0), staticplaneShape7);
|
||||
|
||||
|
||||
// Create Static Torus
|
||||
float height = 28;
|
||||
const float step = 2.5f;
|
||||
const float massT = 1.0f;
|
||||
|
||||
Matrix startTransform =
|
||||
Matrix.RotationQuaternion(Quaternion.RotationYawPitchRoll((float)Math.PI * 0.5f, 0, (float)Math.PI * 0.5f)) *
|
||||
Matrix.Translation(0, height, -5);
|
||||
|
||||
#if BULLET_GIMPACT
|
||||
kinematicTorus = LocalCreateRigidBody(0, startTransform, trimeshShape);
|
||||
#else
|
||||
//kinematicTorus = LocalCreateRigidBody(0, startTransform, CreateTorusShape());
|
||||
#endif
|
||||
|
||||
//kinematicTorus.CollisionFlags = kinematicTorus.CollisionFlags | CollisionFlags.StaticObject;
|
||||
//kinematicTorus.ActivationState = ActivationState.IslandSleeping;
|
||||
|
||||
kinematicTorus.CollisionFlags = kinematicTorus.CollisionFlags | CollisionFlags.KinematicObject;
|
||||
kinematicTorus.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
// Kinematic
|
||||
kinTorusTran = new Vector3(-0.1f, 0, 0);
|
||||
kinTorusRot = Quaternion.RotationYawPitchRoll(0, (float)Math.PI * 0.01f, 0);
|
||||
|
||||
|
||||
#if TEST_GIMPACT_TORUS
|
||||
|
||||
#if BULLET_GIMPACT
|
||||
// Create dynamic Torus
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
height -= step;
|
||||
startTransform =
|
||||
Matrix.RotationQuaternion(Quaternion.RotationYawPitchRoll(0, 0, (float)Math.PI * 0.5f)) *
|
||||
Matrix.Translation(0, height, -5);
|
||||
RigidBody bodyA = LocalCreateRigidBody(massT, startTransform, trimeshShape);
|
||||
|
||||
height -= step;
|
||||
startTransform =
|
||||
Matrix.RotationQuaternion(Quaternion.RotationYawPitchRoll((float)Math.PI * 0.5f, 0, (float)Math.PI * 0.5f)) *
|
||||
Matrix.Translation(0, height, -5);
|
||||
RigidBody bodyB = LocalCreateRigidBody(massT, startTransform, trimeshShape);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
// Create dynamic Torus
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
height -= step;
|
||||
startTransform.setOrigin(btVector3(0, height, -5));
|
||||
startTransform.setRotation(btQuaternion(0, 0, 3.14159265 * 0.5));
|
||||
|
||||
btRigidBody* bodyA = localCreateRigidBody(massT, startTransform, createTorusShape());
|
||||
|
||||
height -= step;
|
||||
startTransform.setOrigin(btVector3(0, height, -5));
|
||||
startTransform.setRotation(btQuaternion(3.14159265 * 0.5, 0, 3.14159265 * 0.5));
|
||||
btRigidBody* bodyB = localCreateRigidBody(massT, startTransform, createTorusShape());
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Create Dynamic Boxes
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
CollisionShape boxShape = new BoxShape(new Vector3(1, 1, 1));
|
||||
CollisionShapes.Add(boxShape);
|
||||
LocalCreateRigidBody(1, Matrix.Translation(2 * i - 5, 2, -3), boxShape);
|
||||
}
|
||||
}
|
||||
|
||||
void InitGImpactCollision()
|
||||
{
|
||||
// Create Torus Shape
|
||||
|
||||
indexVertexArrays = new TriangleIndexVertexArray(Torus.Indices, Torus.Vertices);
|
||||
|
||||
#if BULLET_GIMPACT
|
||||
#if BULLET_GIMPACT_CONVEX_DECOMPOSITION
|
||||
//GImpactConvexDecompositionShape trimesh =
|
||||
// new GImpactConvexDecompositionShape(indexVertexArrays, new Vector3(1), 0.01f);
|
||||
//trimesh.Margin = 0.07f;
|
||||
//trimesh.UpdateBound();
|
||||
#else
|
||||
GImpactMeshShape trimesh = new GImpactMeshShape(indexVertexArrays);
|
||||
trimesh.LocalScaling = new Vector3(1);
|
||||
#if BULLET_TRIANGLE_COLLISION
|
||||
trimesh.Margin = 0.07f; //?????
|
||||
#else
|
||||
trimesh.Margin = 0;
|
||||
#endif
|
||||
trimesh.UpdateBound();
|
||||
#endif
|
||||
trimeshShape = trimesh;
|
||||
#else
|
||||
//trimeshShape = new GImpactMeshData(indexVertexArrays);
|
||||
#endif
|
||||
CollisionShapes.Add(trimeshShape);
|
||||
|
||||
|
||||
// Create Bunny Shape
|
||||
indexVertexArrays2 = new TriangleIndexVertexArray(Bunny.Indices, Bunny.Vertices);
|
||||
|
||||
#if BULLET_GIMPACT
|
||||
#if BULLET_GIMPACT_CONVEX_DECOMPOSITION
|
||||
//GImpactConvexDecompositionShape trimesh2 =
|
||||
// new GImpactConvexDecompositionShape(indexVertexArrays, new Vector3(1), 0.01f);
|
||||
//trimesh.Margin = 0.07f;
|
||||
//trimesh.UpdateBound();
|
||||
//trimeshShape = trimesh2;
|
||||
#else
|
||||
GImpactMeshShape trimesh2 = new GImpactMeshShape(indexVertexArrays2);
|
||||
trimesh2.LocalScaling = new Vector3(1);
|
||||
#if BULLET_TRIANGLE_COLLISION
|
||||
trimesh2.Margin = 0.07f; //?????
|
||||
#else
|
||||
trimesh2.Margin = 0;
|
||||
#endif
|
||||
trimesh2.UpdateBound();
|
||||
trimeshShape2 = trimesh2;
|
||||
#endif
|
||||
#else
|
||||
//trimeshShape2 = new GImpactMeshData(indexVertexArrays2);
|
||||
#endif
|
||||
CollisionShapes.Add(trimeshShape2);
|
||||
|
||||
//register GIMPACT algorithm
|
||||
#if BULLET_GIMPACT
|
||||
GImpactCollisionAlgorithm.RegisterAlgorithm(Dispatcher);
|
||||
#else
|
||||
//ConcaveConcaveCollisionAlgorithm.RegisterAlgorithm(Dispatcher);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ShootTrimesh(Vector3 camPos, Vector3 destination)
|
||||
{
|
||||
if (World != null)
|
||||
{
|
||||
const float mass = 4.0f;
|
||||
Matrix startTransform = Matrix.Translation(camPos);
|
||||
#if BULLET_GIMPACT
|
||||
RigidBody body = LocalCreateRigidBody(mass, startTransform, trimeshShape2);
|
||||
#else
|
||||
RigidBody body = LocalCreateRigidBody(mass, startTransform, CreateBunnyShape());
|
||||
#endif
|
||||
Vector3 linVel = new Vector3(destination[0] - camPos[0], destination[1] - camPos[1], destination[2] - camPos[2]);
|
||||
linVel.Normalize();
|
||||
linVel *= ShootBoxInitialSpeed * 0.25f;
|
||||
|
||||
body.WorldTransform = startTransform;
|
||||
body.LinearVelocity = linVel;
|
||||
body.AngularVelocity = new Vector3(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnHandleInput()
|
||||
{
|
||||
if (Input.KeysPressed.Contains(Keys.OemPeriod))
|
||||
{
|
||||
ShootTrimesh(Freelook.Eye, Freelook.Target);
|
||||
}
|
||||
|
||||
base.OnHandleInput();
|
||||
}
|
||||
|
||||
public override void ExitPhysics()
|
||||
{
|
||||
base.ExitPhysics();
|
||||
|
||||
indexVertexArrays.Dispose();
|
||||
indexVertexArrays2.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
internal static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new GImpactTestDemo())
|
||||
DemoRunner.Run<GImpactTestDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GImpactTestDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
demo.FreeLook.Eye = new Vector3(0, 10, 50);
|
||||
demo.FreeLook.Target = new Vector3(0, 10, -4);
|
||||
demo.DemoText = ". - Shoot Bunny";
|
||||
demo.Graphics.FarPlane = 400.0f;
|
||||
demo.Graphics.WindowTitle = "BulletSharp - GImpact Demo";
|
||||
return new GImpactTestDemoSimulation();
|
||||
}
|
||||
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
if (demo.Input.KeysPressed.Contains(Keys.OemPeriod))
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
var simulation = demo.Simulation as GImpactTestDemoSimulation;
|
||||
simulation.ShootTrimesh(demo.FreeLook.Eye, demo.FreeLook.Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GImpactTestDemoSimulation : ISimulation
|
||||
{
|
||||
private const float ShootBoxInitialSpeed = 10.0f;
|
||||
|
||||
private GImpactMeshShape _torusShape;
|
||||
private GImpactMeshShape _bunnyShape;
|
||||
|
||||
private TriangleIndexVertexArray _torusShapeData;
|
||||
private TriangleIndexVertexArray _bunnyShapeData;
|
||||
|
||||
public GImpactTestDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
//Broadphase = new SimpleBroadphase();
|
||||
Broadphase = new AxisSweep3_32Bit(new Vector3(-10000, -10000, -10000), new Vector3(10000, 10000, 10000), 1024);
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
GImpactCollisionAlgorithm.RegisterAlgorithm(Dispatcher);
|
||||
|
||||
_torusShapeData = new TriangleIndexVertexArray(Torus.Indices, Torus.Vertices);
|
||||
_torusShape = CreateGImpactShape(_torusShapeData);
|
||||
|
||||
_bunnyShapeData = new TriangleIndexVertexArray(Bunny.Indices, Bunny.Vertices);
|
||||
_bunnyShape = CreateGImpactShape(_bunnyShapeData);
|
||||
|
||||
CreateStaticScene();
|
||||
CreateTorusChain();
|
||||
CreateBoxes();
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void ShootTrimesh(Vector3 cameraPosition, Vector3 destination)
|
||||
{
|
||||
const float mass = 4.0f;
|
||||
Matrix startTransform = Matrix.Translation(cameraPosition);
|
||||
RigidBody body = PhysicsHelper.CreateBody(mass, startTransform, _bunnyShape, World);
|
||||
|
||||
Vector3 linearVelocity = destination - cameraPosition;
|
||||
linearVelocity.Normalize();
|
||||
linearVelocity *= ShootBoxInitialSpeed;
|
||||
body.LinearVelocity = linearVelocity;
|
||||
|
||||
body.AngularVelocity = Vector3.Zero;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_torusShapeData.Dispose();
|
||||
_bunnyShapeData.Dispose();
|
||||
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private GImpactMeshShape CreateGImpactShape(TriangleIndexVertexArray shapeData)
|
||||
{
|
||||
var shape = new GImpactMeshShape(shapeData);
|
||||
shape.Margin = 0;
|
||||
shape.UpdateBound();
|
||||
return shape;
|
||||
}
|
||||
|
||||
private GImpactMeshShape CreateGImpactConvexDecompositionShape(TriangleIndexVertexArray shapeData)
|
||||
{
|
||||
//GImpactConvexDecompositionShape shape =
|
||||
// new GImpactConvexDecompositionShape(indexVertexArrays, new Vector3(1), 0.01f);
|
||||
//shape.Margin = 0.07f;
|
||||
//shape.UpdateBound();
|
||||
//return shape;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void CreateStaticScene()
|
||||
{
|
||||
var boxShape1 = new BoxShape(200, 1, 200); //floor
|
||||
PhysicsHelper.CreateStaticBody(Matrix.Translation(0, -10, 0), boxShape1, World);
|
||||
|
||||
var boxShape2 = new BoxShape(1, 50, 200); //left wall
|
||||
PhysicsHelper.CreateStaticBody(Matrix.Translation(-200, 15, 0), boxShape2, World);
|
||||
|
||||
var boxShape3 = new BoxShape(1, 50, 200); //right wall
|
||||
PhysicsHelper.CreateStaticBody(Matrix.Translation(200, 15, 0), boxShape3, World);
|
||||
|
||||
var boxShape4 = new BoxShape(200, 50, 1); //front wall
|
||||
PhysicsHelper.CreateStaticBody(Matrix.Translation(0, 15, 200), boxShape4, World);
|
||||
|
||||
var boxShape5 = new BoxShape(200, 50, 1); //back wall
|
||||
PhysicsHelper.CreateStaticBody(Matrix.Translation(0, 15, -200), boxShape5, World);
|
||||
|
||||
|
||||
Vector3 normal = new Vector3(-0.5f, 0.5f, 0.0f);
|
||||
normal.Normalize();
|
||||
var planeShape1 = new StaticPlaneShape(normal, 0.5f);
|
||||
PhysicsHelper.CreateStaticBody(Matrix.Translation(0, -9, 0), planeShape1, World);
|
||||
|
||||
normal = new Vector3(0.5f, 0.7f, 0.0f);
|
||||
normal.Normalize();
|
||||
var planeShape2 = new StaticPlaneShape(normal, 0.0f);
|
||||
PhysicsHelper.CreateStaticBody(Matrix.Translation(0, -10, 0), planeShape2, World);
|
||||
}
|
||||
|
||||
private void CreateTorusChain()
|
||||
{
|
||||
const float step = 2.5f;
|
||||
const float mass = 1.0f;
|
||||
const float quarterTurn = (float)Math.PI * 0.5f;
|
||||
|
||||
float angle = quarterTurn;
|
||||
float height = 28;
|
||||
|
||||
Matrix startTransform =
|
||||
Matrix.RotationYawPitchRoll(angle, 0, quarterTurn) *
|
||||
Matrix.Translation(0, height, -5);
|
||||
var kinematicTorus = PhysicsHelper.CreateStaticBody(startTransform, _torusShape, World);
|
||||
//kinematicTorus.CollisionFlags |= CollisionFlags.StaticObject;
|
||||
//kinematicTorus.ActivationState = ActivationState.IslandSleeping;
|
||||
kinematicTorus.CollisionFlags |= CollisionFlags.KinematicObject;
|
||||
kinematicTorus.ActivationState = ActivationState.DisableDeactivation;
|
||||
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
angle += quarterTurn;
|
||||
height -= step;
|
||||
startTransform =
|
||||
Matrix.RotationYawPitchRoll(angle, 0, quarterTurn) *
|
||||
Matrix.Translation(0, height, -5);
|
||||
PhysicsHelper.CreateBody(mass, startTransform, _torusShape, World);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateBoxes()
|
||||
{
|
||||
var boxShape = new BoxShape(1);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
PhysicsHelper.CreateBody(1, Matrix.Translation(2 * i - 5, 2, -3), boxShape, World);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,283 +6,270 @@ using System.Collections.Generic;
|
|||
|
||||
namespace MotorDemo
|
||||
{
|
||||
class MotorDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(8, 4, 8);
|
||||
Vector3 target = new Vector3(0, 0, 0);
|
||||
|
||||
List<TestRig> rigs = new List<TestRig>();
|
||||
float m_Time;
|
||||
float fCyclePeriod;
|
||||
float fMuscleStrength;
|
||||
|
||||
const int NumLegs = 6;
|
||||
const int BodyPartCount = 2 * NumLegs + 1;
|
||||
const int JointCount = BodyPartCount - 1;
|
||||
|
||||
class TestRig
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
DynamicsWorld ownerWorld;
|
||||
CollisionShape[] shapes = new CollisionShape[BodyPartCount];
|
||||
RigidBody[] bodies = new RigidBody[BodyPartCount];
|
||||
TypedConstraint[] joints = new TypedConstraint[JointCount];
|
||||
|
||||
public RigidBody LocalCreateRigidBody(float mass, Matrix startTransform, CollisionShape shape)
|
||||
{
|
||||
//rigidbody is dynamic if and only if mass is non zero, otherwise static
|
||||
bool isDynamic = (mass != 0.0f);
|
||||
|
||||
Vector3 localInertia = Vector3.Zero;
|
||||
if (isDynamic)
|
||||
shape.CalculateLocalInertia(mass, out localInertia);
|
||||
|
||||
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
|
||||
DefaultMotionState myMotionState = new DefaultMotionState(startTransform);
|
||||
RigidBody body;
|
||||
using (var rbInfo = new RigidBodyConstructionInfo(mass, myMotionState, shape, localInertia))
|
||||
{
|
||||
body = new RigidBody(rbInfo);
|
||||
}
|
||||
|
||||
ownerWorld.AddRigidBody(body);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
public TestRig(DynamicsWorld ownerWorld, Vector3 positionOffset, bool bFixed)
|
||||
{
|
||||
this.ownerWorld = ownerWorld;
|
||||
Vector3 vUp = new Vector3(0, 1, 0);
|
||||
|
||||
//
|
||||
// Setup geometry
|
||||
//
|
||||
const float fBodySize = 0.25f;
|
||||
const float fLegLength = 0.45f;
|
||||
const float fForeLegLength = 0.75f;
|
||||
const float PI_2 = (float)(0.5f * Math.PI);
|
||||
const float PI_4 = (float)(0.25f * Math.PI);
|
||||
const float PI_8 = (float)(0.125f * Math.PI);
|
||||
shapes[0] = new CapsuleShape(fBodySize, 0.10f);
|
||||
int i;
|
||||
for (i = 0; i < NumLegs; i++)
|
||||
{
|
||||
shapes[1 + 2 * i] = new CapsuleShape(0.10f, fLegLength);
|
||||
shapes[2 + 2 * i] = new CapsuleShape(0.08f, fForeLegLength);
|
||||
}
|
||||
|
||||
//
|
||||
// Setup rigid bodies
|
||||
//
|
||||
const float fHeight = 0.5f;
|
||||
Matrix offset = Matrix.Translation(positionOffset);
|
||||
|
||||
// root
|
||||
Vector3 vRoot = new Vector3(0, fHeight, 0);
|
||||
Matrix transform = Matrix.Translation(vRoot);
|
||||
if (bFixed)
|
||||
{
|
||||
bodies[0] = LocalCreateRigidBody(0, transform * offset, shapes[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
bodies[0] = LocalCreateRigidBody(1, transform * offset, shapes[0]);
|
||||
}
|
||||
// legs
|
||||
for (i = 0; i < NumLegs; i++)
|
||||
{
|
||||
float fAngle = (float)(2 * Math.PI * i / NumLegs);
|
||||
float fSin = (float)Math.Sin(fAngle);
|
||||
float fCos = (float)Math.Cos(fAngle);
|
||||
|
||||
Vector3 vBoneOrigin = new Vector3(fCos * (fBodySize + 0.5f * fLegLength), fHeight, fSin * (fBodySize + 0.5f * fLegLength));
|
||||
|
||||
// thigh
|
||||
Vector3 vToBone = (vBoneOrigin - vRoot);
|
||||
vToBone.Normalize();
|
||||
Vector3 vAxis = Vector3.Cross(vToBone, vUp);
|
||||
transform = Matrix.RotationQuaternion(Quaternion.RotationAxis(vAxis, PI_2)) * Matrix.Translation(vBoneOrigin);
|
||||
bodies[1 + 2 * i] = LocalCreateRigidBody(1, transform * offset, shapes[1 + 2 * i]);
|
||||
|
||||
// shin
|
||||
transform = Matrix.Translation(fCos * (fBodySize + fLegLength), fHeight - 0.5f * fForeLegLength, fSin * (fBodySize + fLegLength));
|
||||
bodies[2 + 2 * i] = LocalCreateRigidBody(1, transform * offset, shapes[2 + 2 * i]);
|
||||
}
|
||||
|
||||
// Setup some damping on the bodies
|
||||
for (i = 0; i < BodyPartCount; ++i)
|
||||
{
|
||||
bodies[i].SetDamping(0.05f, 0.85f);
|
||||
bodies[i].DeactivationTime = 0.8f;
|
||||
//bodies[i].SetSleepingThresholds(1.6f, 2.5f);
|
||||
bodies[i].SetSleepingThresholds(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
//
|
||||
// Setup the constraints
|
||||
//
|
||||
HingeConstraint hingeC;
|
||||
//ConeTwistConstraint coneC;
|
||||
|
||||
Matrix localA, localB, localC;
|
||||
|
||||
for (i = 0; i < NumLegs; i++)
|
||||
{
|
||||
float fAngle = (float)(2 * Math.PI * i / NumLegs);
|
||||
float fSin = (float)Math.Sin(fAngle);
|
||||
float fCos = (float)Math.Cos(fAngle);
|
||||
|
||||
// hip joints
|
||||
localA = Matrix.RotationYawPitchRoll(-fAngle, 0, 0) * Matrix.Translation(fCos * fBodySize, 0, fSin * fBodySize); // OK
|
||||
localB = localA * bodies[0].WorldTransform * Matrix.Invert(bodies[1 + 2 * i].WorldTransform);
|
||||
hingeC = new HingeConstraint(bodies[0], bodies[1 + 2 * i], localA, localB);
|
||||
hingeC.SetLimit(-0.75f * PI_4, PI_8);
|
||||
//hingeC.SetLimit(-0.1f, 0.1f);
|
||||
joints[2 * i] = hingeC;
|
||||
ownerWorld.AddConstraint(joints[2 * i], true);
|
||||
|
||||
// knee joints
|
||||
localA = Matrix.RotationYawPitchRoll(-fAngle, 0, 0) * Matrix.Translation(fCos * (fBodySize + fLegLength), 0, fSin * (fBodySize + fLegLength));
|
||||
localB = localA * bodies[0].WorldTransform * Matrix.Invert(bodies[1 + 2 * i].WorldTransform);
|
||||
localC = localA * bodies[0].WorldTransform * Matrix.Invert(bodies[2 + 2 * i].WorldTransform);
|
||||
hingeC = new HingeConstraint(bodies[1 + 2 * i], bodies[2 + 2 * i], localB, localC);
|
||||
//hingeC.SetLimit(-0.01f, 0.01f);
|
||||
hingeC.SetLimit(-PI_8, 0.2f);
|
||||
joints[1 + 2 * i] = hingeC;
|
||||
ownerWorld.AddConstraint(joints[1 + 2 * i], true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
int i;
|
||||
|
||||
// Remove all constraints
|
||||
for (i = 0; i < JointCount; ++i)
|
||||
{
|
||||
ownerWorld.RemoveConstraint(joints[i]);
|
||||
joints[i].Dispose();
|
||||
joints[i] = null;
|
||||
}
|
||||
|
||||
// Remove all bodies and shapes
|
||||
for (i = 0; i < BodyPartCount; ++i)
|
||||
{
|
||||
ownerWorld.RemoveRigidBody(bodies[i]);
|
||||
bodies[i].MotionState.Dispose();
|
||||
bodies[i].Dispose();
|
||||
bodies[i] = null;
|
||||
shapes[i].Dispose();
|
||||
shapes[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public TypedConstraint[] GetJoints()
|
||||
{
|
||||
return joints;
|
||||
}
|
||||
};
|
||||
|
||||
void MotorPreTickCallback(DynamicsWorld world, float timeStep)
|
||||
{
|
||||
SetMotorTargets(timeStep);
|
||||
DemoRunner.Run<MotorDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitialize()
|
||||
internal sealed class MotorDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Motor Demo");
|
||||
|
||||
DebugDrawMode = DebugDrawModes.DrawConstraintLimits | DebugDrawModes.DrawConstraints | DebugDrawModes.DrawWireframe;
|
||||
demo.FreeLook.Eye = new Vector3(8, 4, 8);
|
||||
demo.FreeLook.Target = Vector3.Zero;
|
||||
demo.DebugDrawMode = DebugDrawModes.DrawConstraintLimits | DebugDrawModes.DrawConstraints | DebugDrawModes.DrawWireframe;
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Motor Demo";
|
||||
return new MotorDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
internal sealed class MotorDemoSimulation : ISimulation
|
||||
{
|
||||
private List<TestRig> _rigs = new List<TestRig>();
|
||||
private float _time = 0;
|
||||
private float _cyclePeriod = 2000.0f;
|
||||
private float _muscleStrength = 0.5f;
|
||||
|
||||
private const int NumLegs = 6;
|
||||
|
||||
public MotorDemoSimulation()
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
Vector3 worldAabbMin = new Vector3(-10000, -10000, -10000);
|
||||
Vector3 worldAabbMax = new Vector3(10000, 10000, 10000);
|
||||
var worldAabbMin = new Vector3(-10000, -10000, -10000);
|
||||
var worldAabbMax = new Vector3(10000, 10000, 10000);
|
||||
Broadphase = new AxisSweep3(worldAabbMin, worldAabbMax);
|
||||
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
World.SetInternalTickCallback(MotorPreTickCallback, this, true);
|
||||
|
||||
// create the ground
|
||||
CollisionShape groundShape = new BoxShape(200, 10, 200);
|
||||
CollisionShapes.Add(groundShape);
|
||||
CollisionObject ground = LocalCreateRigidBody(0, Matrix.Translation(0, -10, 0), groundShape);
|
||||
ground.UserObject = "Ground";
|
||||
|
||||
fCyclePeriod = 2000.0f;
|
||||
fMuscleStrength = 0.5f;
|
||||
m_Time = 0;
|
||||
CreateGround();
|
||||
|
||||
SpawnTestRig(new Vector3(1, 0.5f, 0), false);
|
||||
SpawnTestRig(new Vector3(-2, 0.5f, 0), true);
|
||||
}
|
||||
|
||||
private void SpawnTestRig(Vector3 startOffset, bool isFixed)
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
TestRig rig = new TestRig(World, startOffset, isFixed);
|
||||
rigs.Add(rig);
|
||||
foreach (var testRig in _rigs)
|
||||
{
|
||||
testRig.Dispose();
|
||||
}
|
||||
_rigs.Clear();
|
||||
}
|
||||
|
||||
|
||||
void SetMotorTargets(float deltaTime)
|
||||
private void CreateGround()
|
||||
{
|
||||
float ms = deltaTime * 1000000.0f;
|
||||
float minFPS = 1000000.0f / 60.0f;
|
||||
if (ms > minFPS)
|
||||
ms = minFPS;
|
||||
var groundShape = new BoxShape(200, 10, 200);
|
||||
CollisionObject ground = PhysicsHelper.CreateStaticBody(Matrix.Translation(0, -10, 0), groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
}
|
||||
|
||||
m_Time += ms;
|
||||
private void MotorPreTickCallback(DynamicsWorld world, float timeStep)
|
||||
{
|
||||
SetMotorTargets(timeStep);
|
||||
}
|
||||
|
||||
private void SpawnTestRig(Vector3 startOffset, bool isFixed)
|
||||
{
|
||||
var rig = new TestRig(World, NumLegs, startOffset, isFixed);
|
||||
_rigs.Add(rig);
|
||||
}
|
||||
|
||||
private void SetMotorTargets(float deltaTime)
|
||||
{
|
||||
float deltaTimeMs = deltaTime * 1000000.0f;
|
||||
float minFps = 1000000.0f / 60.0f;
|
||||
if (deltaTimeMs > minFps)
|
||||
deltaTimeMs = minFps;
|
||||
|
||||
_time += deltaTimeMs;
|
||||
|
||||
//
|
||||
// set per-frame sinusoidal position targets using angular motor (hacky?)
|
||||
//
|
||||
foreach (var rig in rigs)
|
||||
foreach (var rig in _rigs)
|
||||
{
|
||||
for (int i = 0; i < 2 * NumLegs; i++)
|
||||
foreach (var leg in rig.Legs)
|
||||
{
|
||||
HingeConstraint hingeC = rig.GetJoints()[i] as HingeConstraint;
|
||||
float fCurAngle = hingeC.HingeAngle;
|
||||
|
||||
float fTargetPercent = ((int)(m_Time / 1000.0f) % (int)fCyclePeriod) / fCyclePeriod;
|
||||
float fTargetAngle = (float)(0.5 * (1 + Math.Sin(2.0f * Math.PI * fTargetPercent)));
|
||||
float fTargetLimitAngle = hingeC.LowerLimit + fTargetAngle * (hingeC.UpperLimit - hingeC.LowerLimit);
|
||||
float fAngleError = fTargetLimitAngle - fCurAngle;
|
||||
float fDesiredAngularVel = 1000000.0f * fAngleError / ms;
|
||||
hingeC.EnableAngularMotor(true, fDesiredAngularVel, fMuscleStrength);
|
||||
SetJointMotorTarget(leg.Hip, deltaTimeMs);
|
||||
SetJointMotorTarget(leg.Knee, deltaTimeMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExitPhysics()
|
||||
private void SetJointMotorTarget(HingeConstraint joint, float deltaTimeMs)
|
||||
{
|
||||
foreach (var testRig in rigs)
|
||||
{
|
||||
testRig.Dispose();
|
||||
}
|
||||
rigs.Clear();
|
||||
base.ExitPhysics();
|
||||
float currentAngle = joint.HingeAngle;
|
||||
|
||||
float targetPercent = ((int)(_time / 1000.0f) % (int)_cyclePeriod) / _cyclePeriod;
|
||||
float targetAngle = (float)(0.5 * (1 + Math.Sin(2.0f * Math.PI * targetPercent)));
|
||||
float targetLimitAngle = joint.LowerLimit + targetAngle * (joint.UpperLimit - joint.LowerLimit);
|
||||
float angleError = targetLimitAngle - currentAngle;
|
||||
float desiredAngularVel = 1000000.0f * angleError / deltaTimeMs;
|
||||
joint.EnableAngularMotor(true, desiredAngularVel, _muscleStrength);
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
internal sealed class TestRig
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
private const float BodyRadius = 0.25f;
|
||||
private const float ThighLength = 0.45f;
|
||||
private const float ShinLength = 0.75f;
|
||||
|
||||
private const float PI_2 = (float)(0.5f * Math.PI);
|
||||
private const float PI_4 = (float)(0.25f * Math.PI);
|
||||
private const float PI_8 = (float)(0.125f * Math.PI);
|
||||
|
||||
private readonly DynamicsWorld _world;
|
||||
|
||||
private readonly CollisionShape _bodyShape;
|
||||
private readonly CollisionShape _thighShape;
|
||||
private readonly CollisionShape _shinShape;
|
||||
|
||||
private RigidBody _bodyObject;
|
||||
|
||||
public TestRig(DynamicsWorld ownerWorld, int numLegs, Vector3 position, bool isFixed)
|
||||
{
|
||||
using (Demo demo = new MotorDemo())
|
||||
_world = ownerWorld;
|
||||
|
||||
Legs = new Leg[numLegs];
|
||||
for (int i = 0; i < numLegs; i++)
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
Legs[i] = new Leg();
|
||||
}
|
||||
|
||||
_bodyShape = new CapsuleShape(BodyRadius, 0.10f);
|
||||
_thighShape = new CapsuleShape(0.1f, ThighLength);
|
||||
_shinShape = new CapsuleShape(0.08f, ShinLength);
|
||||
|
||||
SetupRigidBodies(position, isFixed);
|
||||
SetupConstraints();
|
||||
}
|
||||
|
||||
public Leg[] Legs { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var leg in Legs)
|
||||
{
|
||||
_world.RemoveConstraint(leg.Hip);
|
||||
leg.Hip.Dispose();
|
||||
_world.RemoveConstraint(leg.Knee);
|
||||
leg.Knee.Dispose();
|
||||
}
|
||||
|
||||
DisposeRigidBody(_bodyObject);
|
||||
foreach (var leg in Legs)
|
||||
{
|
||||
DisposeRigidBody(leg.Thigh);
|
||||
DisposeRigidBody(leg.Shin);
|
||||
}
|
||||
|
||||
_bodyShape.Dispose();
|
||||
_thighShape.Dispose();
|
||||
_shinShape.Dispose();
|
||||
}
|
||||
|
||||
private void DisposeRigidBody(RigidBody body)
|
||||
{
|
||||
_world.RemoveRigidBody(body);
|
||||
if (body.MotionState != null)
|
||||
{
|
||||
body.MotionState.Dispose();
|
||||
}
|
||||
body.Dispose();
|
||||
}
|
||||
|
||||
private void SetupRigidBodies(Vector3 position, bool isFixed)
|
||||
{
|
||||
const float heightFromGround = 0.5f;
|
||||
Matrix offset = Matrix.Translation(position);
|
||||
|
||||
// body
|
||||
Vector3 rootPosition = new Vector3(0, heightFromGround, 0);
|
||||
Matrix transform = Matrix.Translation(rootPosition);
|
||||
float mass = isFixed ? 0 : 1;
|
||||
_bodyObject = PhysicsHelper.CreateBody(mass, transform * offset, _bodyShape, _world);
|
||||
|
||||
// legs
|
||||
for (int i = 0; i < Legs.Length; i++)
|
||||
{
|
||||
Leg leg = Legs[i];
|
||||
|
||||
float fAngle = (float)(2 * Math.PI * i / Legs.Length);
|
||||
float fSin = (float)Math.Sin(fAngle);
|
||||
float fCos = (float)Math.Cos(fAngle);
|
||||
|
||||
Vector3 boneOrigin = new Vector3(fCos * (BodyRadius + 0.5f * ThighLength), heightFromGround, fSin * (BodyRadius + 0.5f * ThighLength));
|
||||
|
||||
Vector3 vToBone = boneOrigin - rootPosition;
|
||||
vToBone.Normalize();
|
||||
Vector3 vUp = Vector3.UnitY;
|
||||
Vector3 vAxis = Vector3.Cross(vToBone, vUp);
|
||||
|
||||
transform = Matrix.RotationAxis(vAxis, PI_2) * Matrix.Translation(boneOrigin);
|
||||
leg.Thigh = PhysicsHelper.CreateBody(1, transform * offset, _thighShape, _world);
|
||||
|
||||
transform = Matrix.Translation(fCos * (BodyRadius + ThighLength), heightFromGround - 0.5f * ShinLength, fSin * (BodyRadius + ThighLength));
|
||||
leg.Shin = PhysicsHelper.CreateBody(1, transform * offset, _shinShape, _world);
|
||||
|
||||
SetBodyDamping(leg.Thigh);
|
||||
SetBodyDamping(leg.Shin);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetBodyDamping(RigidBody body)
|
||||
{
|
||||
body.SetDamping(0.05f, 0.85f);
|
||||
body.DeactivationTime = 0.8f;
|
||||
//body.SetSleepingThresholds(1.6f, 2.5f);
|
||||
body.SetSleepingThresholds(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
private void SetupConstraints()
|
||||
{
|
||||
Matrix localA, localB, localC;
|
||||
|
||||
for (int i = 0; i < Legs.Length; i++)
|
||||
{
|
||||
Leg leg = Legs[i];
|
||||
|
||||
float legAngle = (float)(2 * Math.PI * i / Legs.Length);
|
||||
float fSin = (float)Math.Sin(legAngle);
|
||||
float fCos = (float)Math.Cos(legAngle);
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(-legAngle, 0, 0) * Matrix.Translation(fCos * BodyRadius, 0, fSin * BodyRadius);
|
||||
localB = localA * _bodyObject.WorldTransform * Matrix.Invert(leg.Thigh.WorldTransform);
|
||||
leg.Hip = new HingeConstraint(_bodyObject, leg.Thigh, localA, localB);
|
||||
leg.Hip.SetLimit(-0.75f * PI_4, PI_8);
|
||||
//leg.Hip.SetLimit(-0.1f, 0.1f);
|
||||
_world.AddConstraint(leg.Hip, true);
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(-legAngle, 0, 0) * Matrix.Translation(fCos * (BodyRadius + ThighLength), 0, fSin * (BodyRadius + ThighLength));
|
||||
localB = localA * _bodyObject.WorldTransform * Matrix.Invert(leg.Thigh.WorldTransform);
|
||||
localC = localA * _bodyObject.WorldTransform * Matrix.Invert(leg.Shin.WorldTransform);
|
||||
leg.Knee = new HingeConstraint(leg.Thigh, leg.Shin, localB, localC);
|
||||
//leg.Knee.SetLimit(-0.01f, 0.01f);
|
||||
leg.Knee.SetLimit(-PI_8, 0.2f);
|
||||
_world.AddConstraint(leg.Knee, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public sealed class Leg
|
||||
{
|
||||
public RigidBody Thigh { get; set; }
|
||||
public RigidBody Shin { get; set; }
|
||||
public HingeConstraint Hip { get; set; }
|
||||
public HingeConstraint Knee { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,64 +1,77 @@
|
|||
#define PENDULUM_DAMPING
|
||||
|
||||
using System;
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using DemoFramework;
|
||||
using System;
|
||||
|
||||
namespace PendulumDemo
|
||||
{
|
||||
class PendulumDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(-2, 0, 1);
|
||||
Vector3 target = new Vector3(0, -0.5f, 0);
|
||||
|
||||
const float radius = 0.05f;
|
||||
|
||||
MultiBody multiBody;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
DemoRunner.Run<PendulumDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Pendulum Demo");
|
||||
Graphics.SetInfoText("Move using mouse and WASD+shift\n" +
|
||||
"F3 - Toggle debug\n" +
|
||||
//"F11 - Toggle fullscreen\n" +
|
||||
"Space - Shoot box");
|
||||
|
||||
IsDebugDrawEnabled = true;
|
||||
DebugDrawMode = DebugDrawModes.DrawWireframe | DebugDrawModes.DrawContactPoints | DebugDrawModes.DrawAabb;
|
||||
internal sealed class PendulumDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
demo.FreeLook.Eye = new Vector3(-2, 0, 1);
|
||||
demo.FreeLook.Target = new Vector3(0, -0.5f, 0);
|
||||
demo.IsDebugDrawEnabled = true;
|
||||
demo.DebugDrawMode = DebugDrawModes.DrawWireframe | DebugDrawModes.DrawContactPoints | DebugDrawModes.DrawAabb;
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Pendulum Demo";
|
||||
return new PendulumDemoSimulation();
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
if (demo.IsDebugDrawEnabled)
|
||||
{
|
||||
var simulation = demo.Simulation as PendulumDemoSimulation;
|
||||
simulation.DrawPendulum();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class PendulumDemoSimulation : ISimulation
|
||||
{
|
||||
const float radius = 0.05f;
|
||||
|
||||
private MultiBodyConstraintSolver _solver;
|
||||
|
||||
public PendulumDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
Broadphase = new DbvtBroadphase();
|
||||
Solver = new MultiBodyConstraintSolver();
|
||||
_solver = new MultiBodyConstraintSolver();
|
||||
|
||||
World = new MultiBodyDynamicsWorld(Dispatcher, Broadphase, Solver as MultiBodyConstraintSolver, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -9.81f, 0);
|
||||
MultiBodyWorld = new MultiBodyDynamicsWorld(Dispatcher, Broadphase, _solver, CollisionConfiguration);
|
||||
World.SetInternalTickCallback(TickCallback, null, true);
|
||||
|
||||
const bool floating = false;
|
||||
const bool gyro = false;
|
||||
const int numLinks = 1;
|
||||
const bool canSleep = false;
|
||||
const bool selfCollide = false;
|
||||
Vector3 linkHalfExtents = new Vector3(0.05f, 0.5f, 0.1f);
|
||||
Vector3 baseHalfExtents = new Vector3(0.05f, 0.5f, 0.1f);
|
||||
var linkHalfExtents = new Vector3(0.05f, 0.5f, 0.1f);
|
||||
var baseHalfExtents = new Vector3(0.05f, 0.5f, 0.1f);
|
||||
|
||||
Vector3 baseInertiaDiag = Vector3.Zero;
|
||||
var baseInertiaDiag = Vector3.Zero;
|
||||
const float baseMass = 0;
|
||||
|
||||
multiBody = new MultiBody(numLinks, baseMass, baseInertiaDiag, !floating, canSleep);
|
||||
//multiBody.UseRK4Integration = true;
|
||||
//multiBody.BaseWorldTransform = Matrix.Identity;
|
||||
MultiBody = new MultiBody(numLinks, baseMass, baseInertiaDiag, !floating, canSleep);
|
||||
//MultiBody.UseRK4Integration = true;
|
||||
//MultiBody.BaseWorldTransform = Matrix.Identity;
|
||||
|
||||
//init the links
|
||||
Vector3 hingeJointAxis = new Vector3(1, 0, 0);
|
||||
var hingeJointAxis = new Vector3(1, 0, 0);
|
||||
|
||||
//y-axis assumed up
|
||||
Vector3 parentComToCurrentCom = new Vector3(0, -linkHalfExtents[1], 0);
|
||||
|
@ -74,64 +87,65 @@ namespace PendulumDemo
|
|||
shape.CalculateLocalInertia(linkMass, out linkInertiaDiag);
|
||||
}
|
||||
|
||||
multiBody.SetupRevolute(i, linkMass, linkInertiaDiag, i - 1, Quaternion.Identity,
|
||||
MultiBody.SetupRevolute(i, linkMass, linkInertiaDiag, i - 1, Quaternion.Identity,
|
||||
hingeJointAxis, parentComToCurrentPivot, currentPivotToCurrentCom, false);
|
||||
}
|
||||
|
||||
multiBody.FinalizeMultiDof();
|
||||
MultiBody.FinalizeMultiDof();
|
||||
|
||||
(World as MultiBodyDynamicsWorld).AddMultiBody(multiBody);
|
||||
multiBody.CanSleep = canSleep;
|
||||
multiBody.HasSelfCollision = selfCollide;
|
||||
multiBody.UseGyroTerm = gyro;
|
||||
MultiBodyWorld.AddMultiBody(MultiBody);
|
||||
MultiBody.CanSleep = canSleep;
|
||||
MultiBody.HasSelfCollision = selfCollide;
|
||||
MultiBody.UseGyroTerm = gyro;
|
||||
|
||||
#if PENDULUM_DAMPING
|
||||
multiBody.LinearDamping = 0.1f;
|
||||
multiBody.AngularDamping = 0.9f;
|
||||
MultiBody.LinearDamping = 0.1f;
|
||||
MultiBody.AngularDamping = 0.9f;
|
||||
#else
|
||||
multiBody.LinearDamping = 0;
|
||||
multiBody.AngularDamping = 0;
|
||||
MultiBody.LinearDamping = 0;
|
||||
MultiBody.AngularDamping = 0;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < numLinks; i++)
|
||||
{
|
||||
var shape = new SphereShape(radius);
|
||||
CollisionShapes.Add(shape);
|
||||
var col = new MultiBodyLinkCollider(multiBody, i);
|
||||
var col = new MultiBodyLinkCollider(MultiBody, i);
|
||||
col.CollisionShape = shape;
|
||||
const bool isDynamic = true;
|
||||
CollisionFilterGroups collisionFilterGroup = isDynamic ? CollisionFilterGroups.DefaultFilter : CollisionFilterGroups.StaticFilter;
|
||||
CollisionFilterGroups collisionFilterMask = isDynamic ? CollisionFilterGroups.AllFilter : CollisionFilterGroups.AllFilter & ~CollisionFilterGroups.StaticFilter;
|
||||
World.AddCollisionObject(col, collisionFilterGroup, collisionFilterMask);
|
||||
multiBody.GetLink(i).Collider = col;
|
||||
MultiBody.GetLink(i).Collider = col;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnUpdate()
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World => MultiBodyWorld;
|
||||
|
||||
private MultiBodyDynamicsWorld MultiBodyWorld { get; }
|
||||
|
||||
public MultiBody MultiBody { get; }
|
||||
|
||||
public void DrawPendulum()
|
||||
{
|
||||
base.OnUpdate();
|
||||
|
||||
multiBody.AddJointTorque(0, 20.0f);
|
||||
|
||||
if (IsDebugDrawEnabled)
|
||||
{
|
||||
Vector3 from = multiBody.BaseWorldTransform.Origin;
|
||||
Vector3 to = multiBody.GetLink(0).Collider.WorldTransform.Origin;
|
||||
Vector3 color = new Vector3(1, 0, 0);
|
||||
World.DebugDrawer.DrawLine(ref from, ref to, ref color);
|
||||
}
|
||||
Vector3 from = MultiBody.BaseWorldTransform.Origin;
|
||||
Vector3 to = MultiBody.GetLink(0).Collider.WorldTransform.Origin;
|
||||
Vector3 color = new Vector3(1, 0, 0);
|
||||
World.DebugDrawer.DrawLine(ref from, ref to, ref color);
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
public void Dispose()
|
||||
{
|
||||
using (Demo demo = new PendulumDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
_solver.Dispose();
|
||||
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void TickCallback(DynamicsWorld world, float timeStep)
|
||||
{
|
||||
MultiBody.AddJointTorque(0, timeStep * 1000.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using BulletSharp;
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using DemoFramework;
|
||||
using System;
|
||||
|
||||
namespace RagdollDemo
|
||||
{
|
||||
enum BodyPart
|
||||
internal enum BodyPart
|
||||
{
|
||||
Pelvis, Spine, Head,
|
||||
LeftUpperLeg, LeftLowerLeg,
|
||||
|
@ -14,7 +15,7 @@ namespace RagdollDemo
|
|||
Count
|
||||
};
|
||||
|
||||
enum Joint
|
||||
internal enum Joint
|
||||
{
|
||||
PelvisSpine, SpineHead,
|
||||
LeftHip, LeftKnee,
|
||||
|
@ -24,201 +25,218 @@ namespace RagdollDemo
|
|||
Count
|
||||
};
|
||||
|
||||
class Ragdoll
|
||||
internal sealed class Ragdoll : IDisposable
|
||||
{
|
||||
const float ConstraintDebugSize = 0.2f;
|
||||
const float PI_2 = (float)Math.PI / 2;
|
||||
const float PI_4 = (float)Math.PI / 4;
|
||||
private const float ConstraintDebugSize = 0.2f;
|
||||
private const float PI_2 = (float)Math.PI / 2;
|
||||
private const float PI_4 = (float)Math.PI / 4;
|
||||
|
||||
DynamicsWorld ownerWorld;
|
||||
CollisionShape[] shapes = new CollisionShape[(int)BodyPart.Count];
|
||||
RigidBody[] bodies = new RigidBody[(int)BodyPart.Count];
|
||||
TypedConstraint[] joints = new TypedConstraint[(int)Joint.Count];
|
||||
private DynamicsWorld _world;
|
||||
private CollisionShape[] _shapes = new CollisionShape[(int)BodyPart.Count];
|
||||
private RigidBody[] _bodies = new RigidBody[(int)BodyPart.Count];
|
||||
private TypedConstraint[] _joints = new TypedConstraint[(int)Joint.Count];
|
||||
|
||||
public Ragdoll(DynamicsWorld ownerWorld, Vector3 positionOffset)
|
||||
{
|
||||
this.ownerWorld = ownerWorld;
|
||||
_world = ownerWorld;
|
||||
|
||||
// Setup the geometry
|
||||
shapes[(int)BodyPart.Pelvis] = new CapsuleShape(0.15f, 0.20f);
|
||||
shapes[(int)BodyPart.Spine] = new CapsuleShape(0.15f, 0.28f);
|
||||
shapes[(int)BodyPart.Head] = new CapsuleShape(0.10f, 0.05f);
|
||||
shapes[(int)BodyPart.LeftUpperLeg] = new CapsuleShape(0.07f, 0.45f);
|
||||
shapes[(int)BodyPart.LeftLowerLeg] = new CapsuleShape(0.05f, 0.37f);
|
||||
shapes[(int)BodyPart.RightUpperLeg] = new CapsuleShape(0.07f, 0.45f);
|
||||
shapes[(int)BodyPart.RightLowerLeg] = new CapsuleShape(0.05f, 0.37f);
|
||||
shapes[(int)BodyPart.LeftUpperArm] = new CapsuleShape(0.05f, 0.33f);
|
||||
shapes[(int)BodyPart.LeftLowerArm] = new CapsuleShape(0.04f, 0.25f);
|
||||
shapes[(int)BodyPart.RightUpperArm] = new CapsuleShape(0.05f, 0.33f);
|
||||
shapes[(int)BodyPart.RightLowerArm] = new CapsuleShape(0.04f, 0.25f);
|
||||
SetupShapes();
|
||||
SetupBodies(positionOffset);
|
||||
SetupConstraints();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var joint in _joints)
|
||||
{
|
||||
_world.RemoveConstraint(joint);
|
||||
joint.Dispose();
|
||||
}
|
||||
|
||||
foreach (var body in _bodies)
|
||||
{
|
||||
_world.RemoveRigidBody(body);
|
||||
body.Dispose();
|
||||
}
|
||||
|
||||
foreach (var shape in _shapes)
|
||||
{
|
||||
shape.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupShapes()
|
||||
{
|
||||
_shapes[(int)BodyPart.Pelvis] = new CapsuleShape(0.15f, 0.20f);
|
||||
_shapes[(int)BodyPart.Spine] = new CapsuleShape(0.15f, 0.28f);
|
||||
_shapes[(int)BodyPart.Head] = new CapsuleShape(0.10f, 0.05f);
|
||||
_shapes[(int)BodyPart.LeftUpperLeg] = new CapsuleShape(0.07f, 0.45f);
|
||||
_shapes[(int)BodyPart.LeftLowerLeg] = new CapsuleShape(0.05f, 0.37f);
|
||||
_shapes[(int)BodyPart.RightUpperLeg] = new CapsuleShape(0.07f, 0.45f);
|
||||
_shapes[(int)BodyPart.RightLowerLeg] = new CapsuleShape(0.05f, 0.37f);
|
||||
_shapes[(int)BodyPart.LeftUpperArm] = new CapsuleShape(0.05f, 0.33f);
|
||||
_shapes[(int)BodyPart.LeftLowerArm] = new CapsuleShape(0.04f, 0.25f);
|
||||
_shapes[(int)BodyPart.RightUpperArm] = new CapsuleShape(0.05f, 0.33f);
|
||||
_shapes[(int)BodyPart.RightLowerArm] = new CapsuleShape(0.04f, 0.25f);
|
||||
}
|
||||
|
||||
private void SetupBodies(Vector3 positionOffset)
|
||||
{
|
||||
Matrix offset = Matrix.Translation(positionOffset);
|
||||
Matrix transform;
|
||||
transform = offset * Matrix.Translation(0, 1, 0);
|
||||
bodies[(int)BodyPart.Pelvis] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.Pelvis]);
|
||||
_bodies[(int)BodyPart.Pelvis] = CreateBody(1, transform, _shapes[(int)BodyPart.Pelvis]);
|
||||
|
||||
transform = offset * Matrix.Translation(0, 1.2f, 0);
|
||||
bodies[(int)BodyPart.Spine] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.Spine]);
|
||||
_bodies[(int)BodyPart.Spine] = CreateBody(1, transform, _shapes[(int)BodyPart.Spine]);
|
||||
|
||||
transform = offset * Matrix.Translation(0, 1.6f, 0);
|
||||
bodies[(int)BodyPart.Head] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.Head]);
|
||||
_bodies[(int)BodyPart.Head] = CreateBody(1, transform, _shapes[(int)BodyPart.Head]);
|
||||
|
||||
transform = offset * Matrix.Translation(-0.18f, 0.6f, 0);
|
||||
bodies[(int)BodyPart.LeftUpperLeg] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.LeftUpperLeg]);
|
||||
_bodies[(int)BodyPart.LeftUpperLeg] = CreateBody(1, transform, _shapes[(int)BodyPart.LeftUpperLeg]);
|
||||
|
||||
transform = offset * Matrix.Translation(-0.18f, 0.2f, 0);
|
||||
bodies[(int)BodyPart.LeftLowerLeg] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.LeftLowerLeg]);
|
||||
_bodies[(int)BodyPart.LeftLowerLeg] = CreateBody(1, transform, _shapes[(int)BodyPart.LeftLowerLeg]);
|
||||
|
||||
transform = offset * Matrix.Translation(0.18f, 0.65f, 0);
|
||||
bodies[(int)BodyPart.RightUpperLeg] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.RightUpperLeg]);
|
||||
_bodies[(int)BodyPart.RightUpperLeg] = CreateBody(1, transform, _shapes[(int)BodyPart.RightUpperLeg]);
|
||||
|
||||
transform = offset * Matrix.Translation(0.18f, 0.2f, 0);
|
||||
bodies[(int)BodyPart.RightLowerLeg] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.RightLowerLeg]);
|
||||
_bodies[(int)BodyPart.RightLowerLeg] = CreateBody(1, transform, _shapes[(int)BodyPart.RightLowerLeg]);
|
||||
|
||||
transform = Matrix.RotationZ(PI_2) * offset * Matrix.Translation(-0.35f, 1.45f, 0);
|
||||
bodies[(int)BodyPart.LeftUpperArm] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.LeftUpperArm]);
|
||||
_bodies[(int)BodyPart.LeftUpperArm] = CreateBody(1, transform, _shapes[(int)BodyPart.LeftUpperArm]);
|
||||
|
||||
transform = Matrix.RotationZ(PI_2) * offset * Matrix.Translation(-0.7f, 1.45f, 0);
|
||||
bodies[(int)BodyPart.LeftLowerArm] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.LeftLowerArm]);
|
||||
_bodies[(int)BodyPart.LeftLowerArm] = CreateBody(1, transform, _shapes[(int)BodyPart.LeftLowerArm]);
|
||||
|
||||
transform = Matrix.RotationZ(-PI_2) * offset * Matrix.Translation(0.35f, 1.45f, 0);
|
||||
bodies[(int)BodyPart.RightUpperArm] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.RightUpperArm]);
|
||||
_bodies[(int)BodyPart.RightUpperArm] = CreateBody(1, transform, _shapes[(int)BodyPart.RightUpperArm]);
|
||||
|
||||
transform = Matrix.RotationZ(-PI_2) * offset * Matrix.Translation(0.7f, 1.45f, 0);
|
||||
bodies[(int)BodyPart.RightLowerArm] = LocalCreateRigidBody(1, transform, shapes[(int)BodyPart.RightLowerArm]);
|
||||
_bodies[(int)BodyPart.RightLowerArm] = CreateBody(1, transform, _shapes[(int)BodyPart.RightLowerArm]);
|
||||
|
||||
// Setup some damping on the m_bodies
|
||||
foreach (RigidBody body in bodies)
|
||||
// Some damping on the bodies
|
||||
foreach (RigidBody body in _bodies)
|
||||
{
|
||||
body.SetDamping(0.05f, 0.85f);
|
||||
body.DeactivationTime = 0.8f;
|
||||
body.SetSleepingThresholds(1.6f, 2.5f);
|
||||
}
|
||||
}
|
||||
|
||||
// Now setup the constraints
|
||||
HingeConstraint hingeC;
|
||||
ConeTwistConstraint coneC;
|
||||
private void SetupConstraints()
|
||||
{
|
||||
HingeConstraint hinge;
|
||||
ConeTwistConstraint cone;
|
||||
|
||||
Matrix localA, localB;
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, 0.15f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, -0.15f, 0);
|
||||
hingeC = new HingeConstraint(bodies[(int)BodyPart.Pelvis], bodies[(int)BodyPart.Spine], localA, localB);
|
||||
hingeC.SetLimit(-PI_4, PI_2);
|
||||
joints[(int)Joint.PelvisSpine] = hingeC;
|
||||
hingeC.DebugDrawSize = ConstraintDebugSize;
|
||||
hinge = new HingeConstraint(_bodies[(int)BodyPart.Pelvis], _bodies[(int)BodyPart.Spine], localA, localB);
|
||||
hinge.SetLimit(-PI_4, PI_2);
|
||||
_joints[(int)Joint.PelvisSpine] = hinge;
|
||||
hinge.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.PelvisSpine], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.PelvisSpine], true);
|
||||
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(0, 0, PI_2) * Matrix.Translation(0, 0.30f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(0, 0, PI_2) * Matrix.Translation(0, -0.14f, 0);
|
||||
coneC = new ConeTwistConstraint(bodies[(int)BodyPart.Spine], bodies[(int)BodyPart.Head], localA, localB);
|
||||
coneC.SetLimit(PI_4, PI_4, PI_2);
|
||||
joints[(int)Joint.SpineHead] = coneC;
|
||||
coneC.DebugDrawSize = ConstraintDebugSize;
|
||||
cone = new ConeTwistConstraint(_bodies[(int)BodyPart.Spine], _bodies[(int)BodyPart.Head], localA, localB);
|
||||
cone.SetLimit(PI_4, PI_4, PI_2);
|
||||
_joints[(int)Joint.SpineHead] = cone;
|
||||
cone.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.SpineHead], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.SpineHead], true);
|
||||
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(0, 0, -PI_4 * 5) * Matrix.Translation(-0.18f, -0.18f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(0, 0, -PI_4 * 5) * Matrix.Translation(0, 0.225f, 0);
|
||||
coneC = new ConeTwistConstraint(bodies[(int)BodyPart.Pelvis], bodies[(int)BodyPart.LeftUpperLeg], localA, localB);
|
||||
coneC.SetLimit(PI_4, PI_4, 0);
|
||||
joints[(int)Joint.LeftHip] = coneC;
|
||||
coneC.DebugDrawSize = ConstraintDebugSize;
|
||||
cone = new ConeTwistConstraint(_bodies[(int)BodyPart.Pelvis], _bodies[(int)BodyPart.LeftUpperLeg], localA, localB);
|
||||
cone.SetLimit(PI_4, PI_4, 0);
|
||||
_joints[(int)Joint.LeftHip] = cone;
|
||||
cone.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.LeftHip], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.LeftHip], true);
|
||||
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, -0.225f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, 0.185f, 0);
|
||||
hingeC = new HingeConstraint(bodies[(int)BodyPart.LeftUpperLeg], bodies[(int)BodyPart.LeftLowerLeg], localA, localB);
|
||||
hingeC.SetLimit(0, PI_2);
|
||||
joints[(int)Joint.LeftKnee] = hingeC;
|
||||
hingeC.DebugDrawSize = ConstraintDebugSize;
|
||||
hinge = new HingeConstraint(_bodies[(int)BodyPart.LeftUpperLeg], _bodies[(int)BodyPart.LeftLowerLeg], localA, localB);
|
||||
hinge.SetLimit(0, PI_2);
|
||||
_joints[(int)Joint.LeftKnee] = hinge;
|
||||
hinge.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.LeftKnee], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.LeftKnee], true);
|
||||
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(0, 0, PI_4) * Matrix.Translation(0.18f, -0.10f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(0, 0, PI_4) * Matrix.Translation(0, 0.225f, 0);
|
||||
coneC = new ConeTwistConstraint(bodies[(int)BodyPart.Pelvis], bodies[(int)BodyPart.RightUpperLeg], localA, localB);
|
||||
coneC.SetLimit(PI_4, PI_4, 0);
|
||||
joints[(int)Joint.RightHip] = coneC;
|
||||
coneC.DebugDrawSize = ConstraintDebugSize;
|
||||
cone = new ConeTwistConstraint(_bodies[(int)BodyPart.Pelvis], _bodies[(int)BodyPart.RightUpperLeg], localA, localB);
|
||||
cone.SetLimit(PI_4, PI_4, 0);
|
||||
_joints[(int)Joint.RightHip] = cone;
|
||||
cone.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.RightHip], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.RightHip], true);
|
||||
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, -0.225f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, 0.185f, 0);
|
||||
hingeC = new HingeConstraint(bodies[(int)BodyPart.RightUpperLeg], bodies[(int)BodyPart.RightLowerLeg], localA, localB);
|
||||
hingeC.SetLimit(0, PI_2);
|
||||
joints[(int)Joint.RightKnee] = hingeC;
|
||||
hingeC.DebugDrawSize = ConstraintDebugSize;
|
||||
hinge = new HingeConstraint(_bodies[(int)BodyPart.RightUpperLeg], _bodies[(int)BodyPart.RightLowerLeg], localA, localB);
|
||||
hinge.SetLimit(0, PI_2);
|
||||
_joints[(int)Joint.RightKnee] = hinge;
|
||||
hinge.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.RightKnee], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.RightKnee], true);
|
||||
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(0, 0, (float)Math.PI) * Matrix.Translation(-0.2f, 0.15f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(0, 0, PI_2) * Matrix.Translation(0, -0.18f, 0);
|
||||
coneC = new ConeTwistConstraint(bodies[(int)BodyPart.Spine], bodies[(int)BodyPart.LeftUpperArm], localA, localB);
|
||||
coneC.SetLimit(PI_2, PI_2, 0);
|
||||
joints[(int)Joint.LeftShoulder] = coneC;
|
||||
coneC.DebugDrawSize = ConstraintDebugSize;
|
||||
cone = new ConeTwistConstraint(_bodies[(int)BodyPart.Spine], _bodies[(int)BodyPart.LeftUpperArm], localA, localB);
|
||||
cone.SetLimit(PI_2, PI_2, 0);
|
||||
_joints[(int)Joint.LeftShoulder] = cone;
|
||||
cone.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.LeftShoulder], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.LeftShoulder], true);
|
||||
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, 0.18f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, -0.14f, 0);
|
||||
hingeC = new HingeConstraint(bodies[(int)BodyPart.LeftUpperArm], bodies[(int)BodyPart.LeftLowerArm], localA, localB);
|
||||
hingeC.SetLimit(0, PI_2);
|
||||
joints[(int)Joint.LeftElbow] = hingeC;
|
||||
hingeC.DebugDrawSize = ConstraintDebugSize;
|
||||
hinge = new HingeConstraint(_bodies[(int)BodyPart.LeftUpperArm], _bodies[(int)BodyPart.LeftLowerArm], localA, localB);
|
||||
hinge.SetLimit(0, PI_2);
|
||||
_joints[(int)Joint.LeftElbow] = hinge;
|
||||
hinge.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.LeftElbow], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.LeftElbow], true);
|
||||
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(0, 0, 0) * Matrix.Translation(0.2f, 0.15f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(0, 0, PI_2) * Matrix.Translation(0, -0.18f, 0);
|
||||
coneC = new ConeTwistConstraint(bodies[(int)BodyPart.Spine], bodies[(int)BodyPart.RightUpperArm], localA, localB);
|
||||
coneC.SetLimit(PI_2, PI_2, 0);
|
||||
joints[(int)Joint.RightShoulder] = coneC;
|
||||
coneC.DebugDrawSize = ConstraintDebugSize;
|
||||
cone = new ConeTwistConstraint(_bodies[(int)BodyPart.Spine], _bodies[(int)BodyPart.RightUpperArm], localA, localB);
|
||||
cone.SetLimit(PI_2, PI_2, 0);
|
||||
_joints[(int)Joint.RightShoulder] = cone;
|
||||
cone.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.RightShoulder], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.RightShoulder], true);
|
||||
|
||||
|
||||
localA = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, 0.18f, 0);
|
||||
localB = Matrix.RotationYawPitchRoll(PI_2, 0, 0) * Matrix.Translation(0, -0.14f, 0);
|
||||
hingeC = new HingeConstraint(bodies[(int)BodyPart.RightUpperArm], bodies[(int)BodyPart.RightLowerArm], localA, localB);
|
||||
//hingeC.SetLimit(-PI_2, 0);
|
||||
hingeC.SetLimit(0, PI_2);
|
||||
joints[(int)Joint.RightElbow] = hingeC;
|
||||
hingeC.DebugDrawSize = ConstraintDebugSize;
|
||||
hinge = new HingeConstraint(_bodies[(int)BodyPart.RightUpperArm], _bodies[(int)BodyPart.RightLowerArm], localA, localB);
|
||||
//hinge.SetLimit(-PI_2, 0);
|
||||
hinge.SetLimit(0, PI_2);
|
||||
_joints[(int)Joint.RightElbow] = hinge;
|
||||
hinge.DebugDrawSize = ConstraintDebugSize;
|
||||
|
||||
ownerWorld.AddConstraint(joints[(int)Joint.RightElbow], true);
|
||||
_world.AddConstraint(_joints[(int)Joint.RightElbow], true);
|
||||
}
|
||||
|
||||
RigidBody LocalCreateRigidBody(float mass, Matrix startTransform, CollisionShape shape)
|
||||
private RigidBody CreateBody(float mass, Matrix startTransform, CollisionShape shape)
|
||||
{
|
||||
bool isDynamic = (mass != 0.0f);
|
||||
|
||||
Vector3 localInertia = Vector3.Zero;
|
||||
if (isDynamic)
|
||||
shape.CalculateLocalInertia(mass, out localInertia);
|
||||
|
||||
DefaultMotionState myMotionState = new DefaultMotionState(startTransform);
|
||||
|
||||
RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(mass, myMotionState, shape, localInertia);
|
||||
RigidBody body = new RigidBody(rbInfo);
|
||||
rbInfo.Dispose();
|
||||
|
||||
ownerWorld.AddRigidBody(body);
|
||||
|
||||
return body;
|
||||
return PhysicsHelper.CreateBody(mass, startTransform, shape, _world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,64 +6,73 @@ using System.Collections.Generic;
|
|||
|
||||
namespace RagdollDemo
|
||||
{
|
||||
class RagdollDemo : Demo
|
||||
{
|
||||
Vector3 eye = new Vector3(0, 1, 5);
|
||||
Vector3 target = new Vector3(0, 1, 0);
|
||||
|
||||
List<Ragdoll> ragdolls = new List<Ragdoll>();
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Ragdoll Demo");
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
|
||||
Broadphase = new AxisSweep3(new Vector3(-10000, -10000, -10000), new Vector3(10000, 10000, 10000));
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
|
||||
//World.DispatchInfo.UseConvexConservativeDistanceUtil = true;
|
||||
//World.DispatchInfo.ConvexConservativeDistanceThreshold = 0.01f;
|
||||
|
||||
// Setup a big ground box
|
||||
CollisionShape groundShape = new BoxShape(100, 10, 100);
|
||||
CollisionShapes.Add(groundShape);
|
||||
Matrix groundTransform = Matrix.Translation(0, -10, 0);
|
||||
|
||||
RigidBody ground = LocalCreateRigidBody(0, groundTransform, groundShape);
|
||||
ground.UserObject = "Ground";
|
||||
|
||||
// Spawn one ragdoll
|
||||
SpawnRagdoll(new Vector3(1, 0.5f, 0));
|
||||
SpawnRagdoll(new Vector3(-1, 0.5f, 0));
|
||||
}
|
||||
|
||||
void SpawnRagdoll(Vector3 startOffset)
|
||||
{
|
||||
Ragdoll ragdoll = new Ragdoll(World, startOffset);
|
||||
ragdolls.Add(ragdoll);
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
internal static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new RagdollDemo())
|
||||
DemoRunner.Run<RagdollDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class RagdollDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
demo.FreeLook.Eye = new Vector3(0, 1, 5);
|
||||
demo.FreeLook.Target = new Vector3(0, 1, 0);
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Ragdoll Demo";
|
||||
return new RagdollDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class RagdollDemoSimulation : ISimulation
|
||||
{
|
||||
private List<Ragdoll> _ragdolls = new List<Ragdoll>();
|
||||
|
||||
public RagdollDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Broadphase = new AxisSweep3(new Vector3(-10000, -10000, -10000), new Vector3(10000, 10000, 10000));
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
//World.DispatchInfo.UseConvexConservativeDistanceUtil = true;
|
||||
//World.DispatchInfo.ConvexConservativeDistanceThreshold = 0.01f;
|
||||
|
||||
CreateGround();
|
||||
|
||||
SpawnRagdoll(new Vector3(1, 0.5f, 0));
|
||||
SpawnRagdoll(new Vector3(-1, 0.5f, 0));
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var ragdoll in _ragdolls)
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
ragdoll.Dispose();
|
||||
}
|
||||
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
var groundShape = new BoxShape(100, 10, 100);
|
||||
Matrix groundTransform = Matrix.Translation(0, -10, 0);
|
||||
RigidBody ground = PhysicsHelper.CreateStaticBody(groundTransform, groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
}
|
||||
|
||||
private void SpawnRagdoll(Vector3 startOffset)
|
||||
{
|
||||
var ragdoll = new Ragdoll(World, startOffset);
|
||||
_ragdolls.Add(ragdoll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,107 +5,88 @@ using System;
|
|||
|
||||
namespace RollingFrictionDemo
|
||||
{
|
||||
class RollingFrictionDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(10, 10, 40);
|
||||
Vector3 target = new Vector3(0, 5, -4);
|
||||
|
||||
// create 125 (5x5x5) dynamic objects
|
||||
const int ArraySizeX = 5, ArraySizeY = 5, ArraySizeZ = 5;
|
||||
|
||||
// scaling of the objects (0.1 = 20 centimeter boxes )
|
||||
const float StartPosX = -5;
|
||||
const float StartPosY = -5;
|
||||
const float StartPosZ = -3;
|
||||
|
||||
protected override void OnInitialize()
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Rolling Friction Demo");
|
||||
DemoRunner.Run<RollingFrictionDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
internal sealed class RollingFrictionDemo : IDemoConfiguration
|
||||
{
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
demo.FreeLook.Eye = new Vector3(10, 10, 40);
|
||||
demo.FreeLook.Target = new Vector3(0, 5, -4);
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Rolling Friction Demo";
|
||||
return new RollingFrictionDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class RollingFrictionDemoSimulation : ISimulation
|
||||
{
|
||||
private const int NumObjectsX = 5, NumObjectsY = 5, NumObjectsZ = 5;
|
||||
|
||||
private Vector3 _startPosition = new Vector3(-7f, 2, 0);
|
||||
|
||||
public RollingFrictionDemoSimulation()
|
||||
{
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Broadphase = new DbvtBroadphase();
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
|
||||
// create the ground
|
||||
CollisionShape groundShape = new BoxShape(20, 50, 10);
|
||||
CollisionShapes.Add(groundShape);
|
||||
CollisionObject ground = LocalCreateRigidBody(0,
|
||||
Matrix.RotationAxis(new Vector3(0, 0, 1), (float)Math.PI * 0.03f) * Matrix.Translation(0, -50, 0),
|
||||
groundShape);
|
||||
ground.Friction = 1;
|
||||
ground.RollingFriction = 1;
|
||||
ground.UserObject = "Ground";
|
||||
|
||||
groundShape = new BoxShape(100, 50, 100);
|
||||
CollisionShapes.Add(groundShape);
|
||||
ground = LocalCreateRigidBody(0, Matrix.Translation(0, -54, 0), groundShape);
|
||||
ground.Friction = 1;
|
||||
ground.RollingFriction = 1;
|
||||
ground.UserObject = "Ground";
|
||||
CreateGround();
|
||||
|
||||
// create a few dynamic rigidbodies
|
||||
CollisionShape[] colShapes = {
|
||||
new SphereShape(1),
|
||||
new CapsuleShape(0.5f,1),
|
||||
new CapsuleShapeX(0.5f,1),
|
||||
new CapsuleShapeZ(0.5f,1),
|
||||
new ConeShape(0.5f,1),
|
||||
new ConeShapeX(0.5f,1),
|
||||
new ConeShapeZ(0.5f,1),
|
||||
new CylinderShape(new Vector3(0.5f,1,0.5f)),
|
||||
new CylinderShapeX(new Vector3(1,0.5f,0.5f)),
|
||||
new CylinderShapeZ(new Vector3(0.5f,0.5f,1)),
|
||||
};
|
||||
foreach (var collisionShape in colShapes)
|
||||
{
|
||||
CollisionShapes.Add(collisionShape);
|
||||
}
|
||||
new SphereShape(1),
|
||||
new CapsuleShape(0.5f, 1),
|
||||
new CapsuleShapeX(0.5f, 1),
|
||||
new CapsuleShapeZ(0.5f, 1),
|
||||
new ConeShape(0.5f, 1),
|
||||
new ConeShapeX(0.5f, 1),
|
||||
new ConeShapeZ(0.5f, 1),
|
||||
new CylinderShape(new Vector3(0.5f, 1, 0.5f)),
|
||||
new CylinderShapeX(new Vector3(1, 0.5f, 0.5f)),
|
||||
new CylinderShapeZ(new Vector3(0.5f, 0.5f, 1)),
|
||||
};
|
||||
|
||||
const float mass = 1.0f;
|
||||
var anisotropicRollingFrictionDirection = new Vector3(1, 1, 1);
|
||||
|
||||
CollisionShape colShape = new BoxShape(1);
|
||||
CollisionShapes.Add(colShape);
|
||||
Vector3 localInertia = colShape.CalculateLocalInertia(mass);
|
||||
|
||||
var rbInfo = new RigidBodyConstructionInfo(mass, null, null, localInertia);
|
||||
|
||||
const float startX = StartPosX - ArraySizeX / 2;
|
||||
const float startY = StartPosY;
|
||||
const float startZ = StartPosZ - ArraySizeZ / 2;
|
||||
var rbInfo = new RigidBodyConstructionInfo(mass, null, null);
|
||||
|
||||
int shapeIndex = 0;
|
||||
for (int k = 0; k < ArraySizeY; k++)
|
||||
for (int y = 0; y < NumObjectsY; y++)
|
||||
{
|
||||
for (int i = 0; i < ArraySizeX; i++)
|
||||
for (int x = 0; x < NumObjectsX; x++)
|
||||
{
|
||||
for (int j = 0; j < ArraySizeZ; j++)
|
||||
for (int z = 0; z < NumObjectsZ; z++)
|
||||
{
|
||||
Matrix startTransform = Matrix.Translation(
|
||||
2 * i + startX,
|
||||
2 * k + startY + 20,
|
||||
2 * j + startZ
|
||||
);
|
||||
Vector3 position = _startPosition + 2 * new Vector3(x, y, z);
|
||||
position += new Vector3(0, 10, 0);
|
||||
Matrix startTransform = Matrix.Translation(position);
|
||||
|
||||
shapeIndex++;
|
||||
var shape = colShapes[shapeIndex % colShapes.Length];
|
||||
|
||||
// using motionstate is recommended, it provides interpolation capabilities
|
||||
// and only synchronizes 'active' objects
|
||||
rbInfo.MotionState = new DefaultMotionState(startTransform);
|
||||
rbInfo.CollisionShape = colShapes[shapeIndex % colShapes.Length];
|
||||
rbInfo.CollisionShape = shape;
|
||||
rbInfo.LocalInertia = shape.CalculateLocalInertia(rbInfo.Mass);
|
||||
|
||||
RigidBody body = new RigidBody(rbInfo);
|
||||
body.Friction = 1;
|
||||
body.RollingFriction = 0.3f;
|
||||
body.SetAnisotropicFriction(colShape.AnisotropicRollingFrictionDirection, AnisotropicFrictionFlags.RollingFriction);
|
||||
var body = new RigidBody(rbInfo)
|
||||
{
|
||||
Friction = 1,
|
||||
RollingFriction = 0.1f,
|
||||
SpinningFriction = 0.1f
|
||||
};
|
||||
body.SetAnisotropicFriction(shape.AnisotropicRollingFrictionDirection,
|
||||
AnisotropicFrictionFlags.RollingFriction);
|
||||
|
||||
World.AddRigidBody(body);
|
||||
}
|
||||
|
@ -114,17 +95,32 @@ namespace RollingFrictionDemo
|
|||
|
||||
rbInfo.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
using (Demo demo = new RollingFrictionDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
private void CreateGround()
|
||||
{
|
||||
var groundShape = new BoxShape(20, 50, 10);
|
||||
CollisionObject ground = PhysicsHelper.CreateStaticBody(
|
||||
Matrix.RotationAxis(new Vector3(0, 0, 1), (float)Math.PI * 0.03f) * Matrix.Translation(0, -50, 0),
|
||||
groundShape, World);
|
||||
ground.Friction = 1;
|
||||
ground.RollingFriction = 1;
|
||||
ground.UserObject = "Ground";
|
||||
|
||||
groundShape = new BoxShape(100, 50, 100);
|
||||
ground = PhysicsHelper.CreateStaticBody(Matrix.Translation(0, -54, 0), groundShape, World);
|
||||
ground.Friction = 1;
|
||||
ground.RollingFriction = 1;
|
||||
ground.UserObject = "Ground";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,64 +2,51 @@
|
|||
using BulletSharp.Math;
|
||||
using DemoFramework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SerializeDemo
|
||||
{
|
||||
class CustomBulletWorldImporter : BulletWorldImporter
|
||||
internal static class Program
|
||||
{
|
||||
public CustomBulletWorldImporter(DynamicsWorld world)
|
||||
: base(world)
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
}
|
||||
|
||||
public override RigidBody CreateRigidBody(bool isDynamic, float mass, ref Matrix startTransform, CollisionShape shape, string bodyName)
|
||||
{
|
||||
RigidBody body = base.CreateRigidBody(isDynamic, mass, ref startTransform, shape, bodyName);
|
||||
|
||||
if (bodyName != null && bodyName.Equals("GroundName"))
|
||||
body.UserObject = "Ground";
|
||||
|
||||
if (shape.ShapeType == BroadphaseNativeType.StaticPlaneShape)
|
||||
body.UserObject = "Ground";
|
||||
|
||||
return body;
|
||||
DemoRunner.Run<SerializeDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
class SerializeDemo : Demo
|
||||
internal sealed class SerializeDemo : IDemoConfiguration
|
||||
{
|
||||
Vector3 eye = new Vector3(30, 20, 10);
|
||||
Vector3 target = new Vector3(0, 5, 0);
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
demo.FreeLook.Eye = new Vector3(30, 20, 10);
|
||||
demo.FreeLook.Target = new Vector3(0, 5, 0);
|
||||
demo.Graphics.WindowTitle = "BulletSharp - Serialize Demo";
|
||||
return new SerializeDemoSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
///create 125 (5x5x5) dynamic objects
|
||||
int ArraySizeX = 5, ArraySizeY = 5, ArraySizeZ = 5;
|
||||
internal sealed class SerializeDemoSimulation : ISimulation
|
||||
{
|
||||
const int NumObjectsX = 5, NumObjectsY = 5, NumObjectsZ = 5;
|
||||
|
||||
///scaling of the objects (0.1 = 20 centimeter boxes )
|
||||
float StartPosX = -5;
|
||||
float StartPosY = -5;
|
||||
float StartPosZ = -3;
|
||||
|
||||
BulletWorldImporter fileLoader;
|
||||
private BulletWorldImporter _fileLoader;
|
||||
|
||||
protected override void OnInitialize()
|
||||
private List<CollisionShape> _collisionShapes = new List<CollisionShape>();
|
||||
|
||||
public SerializeDemoSimulation()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Serialize Demo");
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
{
|
||||
// collision configuration contains default setup for memory, collision setup
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
Broadphase = new DbvtBroadphase();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConf);
|
||||
World.Gravity = new Vector3(0, -10, 0);
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
|
||||
GImpactCollisionAlgorithm.RegisterAlgorithm(Dispatcher);
|
||||
|
||||
|
@ -74,44 +61,44 @@ namespace SerializeDemo
|
|||
bulletFile = args[1];
|
||||
}
|
||||
|
||||
fileLoader = new CustomBulletWorldImporter(World);
|
||||
if (!fileLoader.LoadFile(bulletFile))
|
||||
_fileLoader = new CustomBulletWorldImporter(World);
|
||||
if (!_fileLoader.LoadFile(bulletFile))
|
||||
{
|
||||
CollisionShape groundShape = new BoxShape(50);
|
||||
CollisionShapes.Add(groundShape);
|
||||
RigidBody ground = LocalCreateRigidBody(0, Matrix.Translation(0, -50, 0), groundShape);
|
||||
var groundShape = new BoxShape(50);
|
||||
_collisionShapes.Add(groundShape);
|
||||
RigidBody ground = PhysicsHelper.CreateStaticBody(Matrix.Translation(0, -50, 0), groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
|
||||
// create a few dynamic rigidbodies
|
||||
float mass = 1.0f;
|
||||
|
||||
Vector3[] positions = new Vector3[2] { new Vector3(0.1f, 0.2f, 0.3f), new Vector3(0.4f, 0.5f, 0.6f) };
|
||||
Vector3[] positions = new[] { new Vector3(0.1f, 0.2f, 0.3f), new Vector3(0.4f, 0.5f, 0.6f) };
|
||||
float[] radi = new float[2] { 0.3f, 0.4f };
|
||||
|
||||
CollisionShape colShape = new MultiSphereShape(positions, radi);
|
||||
var colShape = new MultiSphereShape(positions, radi);
|
||||
|
||||
//CollisionShape colShape = new CapsuleShapeZ(1, 1);
|
||||
//CollisionShape colShape = new CylinderShapeZ(1, 1, 1);
|
||||
//CollisionShape colShape = new BoxShape(1);
|
||||
//CollisionShape colShape = new SphereShape(1);
|
||||
CollisionShapes.Add(colShape);
|
||||
//var colShape = new CapsuleShapeZ(1, 1);
|
||||
//var colShape = new CylinderShapeZ(1, 1, 1);
|
||||
//var colShape = new BoxShape(1);
|
||||
//var colShape = new SphereShape(1);
|
||||
_collisionShapes.Add(colShape);
|
||||
|
||||
Vector3 localInertia = colShape.CalculateLocalInertia(mass);
|
||||
|
||||
float startX = StartPosX - ArraySizeX / 2;
|
||||
float startX = StartPosX - NumObjectsX / 2;
|
||||
float startY = StartPosY;
|
||||
float startZ = StartPosZ - ArraySizeZ / 2;
|
||||
float startZ = StartPosZ - NumObjectsZ / 2;
|
||||
|
||||
for (int k = 0; k < ArraySizeY; k++)
|
||||
for (int y = 0; y < NumObjectsY; y++)
|
||||
{
|
||||
for (int i = 0; i < ArraySizeX; i++)
|
||||
for (int x = 0; x < NumObjectsX; x++)
|
||||
{
|
||||
for (int j = 0; j < ArraySizeZ; j++)
|
||||
for (int z = 0; z < NumObjectsZ; z++)
|
||||
{
|
||||
Matrix startTransform = Matrix.Translation(
|
||||
2 * i + startX,
|
||||
2 * k + startY,
|
||||
2 * j + startZ
|
||||
2 * x + startX,
|
||||
2 * y + startY,
|
||||
2 * z + startZ
|
||||
);
|
||||
|
||||
// using motionstate is recommended, it provides interpolation capabilities
|
||||
|
@ -134,10 +121,10 @@ namespace SerializeDemo
|
|||
{
|
||||
serializer.RegisterNameForObject(ground, "GroundName");
|
||||
|
||||
for (int i = 0; i < CollisionShapes.Count; i++)
|
||||
serializer.RegisterNameForObject(CollisionShapes[i], "name" + i.ToString());
|
||||
for (int i = 0; i < _collisionShapes.Count; i++)
|
||||
serializer.RegisterNameForObject(_collisionShapes[i], "name" + i.ToString());
|
||||
|
||||
Point2PointConstraint p2p = new Point2PointConstraint((RigidBody) World.CollisionObjectArray[2],
|
||||
var p2p = new Point2PointConstraint((RigidBody) World.CollisionObjectArray[2],
|
||||
new Vector3(0, 1, 0));
|
||||
World.AddConstraint(p2p);
|
||||
serializer.RegisterNameForObject(p2p, "constraintje");
|
||||
|
@ -154,22 +141,37 @@ namespace SerializeDemo
|
|||
}
|
||||
}
|
||||
|
||||
public override void ExitPhysics()
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
fileLoader.DeleteAllData();
|
||||
base.ExitPhysics();
|
||||
_fileLoader.DeleteAllData();
|
||||
|
||||
this.StandardCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
internal sealed class CustomBulletWorldImporter : BulletWorldImporter
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
public CustomBulletWorldImporter(DynamicsWorld world)
|
||||
: base(world)
|
||||
{
|
||||
using (Demo demo = new SerializeDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
}
|
||||
|
||||
public override RigidBody CreateRigidBody(bool isDynamic, float mass, ref Matrix startTransform, CollisionShape shape, string bodyName)
|
||||
{
|
||||
RigidBody body = base.CreateRigidBody(isDynamic, mass, ref startTransform, shape, bodyName);
|
||||
|
||||
if (bodyName != null && bodyName.Equals("GroundName"))
|
||||
body.UserObject = "Ground";
|
||||
|
||||
if (shape.ShapeType == BroadphaseNativeType.StaticPlaneShape)
|
||||
body.UserObject = "Ground";
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,23 +1,22 @@
|
|||
#define ROLLING_INFLUENCE_FIX
|
||||
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using BulletSharp;
|
||||
using BulletSharp.Math;
|
||||
|
||||
namespace VehicleDemo
|
||||
{
|
||||
// This class is equivalent to RaycastVehicle, but is used to test the IAction interface
|
||||
public class CustomVehicle : IAction
|
||||
{
|
||||
List<WheelInfo> wheelInfo = new List<WheelInfo>();
|
||||
private List<WheelInfo> _wheelInfo = new List<WheelInfo>();
|
||||
|
||||
Vector3[] forwardWS = new Vector3[0];
|
||||
Vector3[] axle = new Vector3[0];
|
||||
float[] forwardImpulse = new float[0];
|
||||
float[] sideImpulse = new float[0];
|
||||
private Vector3[] _forwardWS = new Vector3[0];
|
||||
private Vector3[] _axle = new Vector3[0];
|
||||
private float[] _forwardImpulse = new float[0];
|
||||
private float[] _sideImpulse = new float[0];
|
||||
|
||||
public Matrix ChassisWorldTransform
|
||||
{
|
||||
|
@ -35,7 +34,7 @@ namespace VehicleDemo
|
|||
|
||||
public int NumWheels
|
||||
{
|
||||
get { return wheelInfo.Count; }
|
||||
get { return _wheelInfo.Count; }
|
||||
}
|
||||
|
||||
int indexRightAxis = 0;
|
||||
|
@ -86,7 +85,7 @@ namespace VehicleDemo
|
|||
public Matrix GetWheelTransformWS(int wheelIndex)
|
||||
{
|
||||
Debug.Assert(wheelIndex < NumWheels);
|
||||
return wheelInfo[wheelIndex].WorldTransform;
|
||||
return _wheelInfo[wheelIndex].WorldTransform;
|
||||
}
|
||||
|
||||
static CustomVehicle()
|
||||
|
@ -106,23 +105,24 @@ namespace VehicleDemo
|
|||
|
||||
public WheelInfo AddWheel(Vector3 connectionPointCS, Vector3 wheelDirectionCS0, Vector3 wheelAxleCS, float suspensionRestLength, float wheelRadius, VehicleTuning tuning, bool isFrontWheel)
|
||||
{
|
||||
WheelInfoConstructionInfo ci = new WheelInfoConstructionInfo();
|
||||
var ci = new WheelInfoConstructionInfo
|
||||
{
|
||||
ChassisConnectionCS = connectionPointCS,
|
||||
WheelDirectionCS = wheelDirectionCS0,
|
||||
WheelAxleCS = wheelAxleCS,
|
||||
SuspensionRestLength = suspensionRestLength,
|
||||
WheelRadius = wheelRadius,
|
||||
SuspensionStiffness = tuning.SuspensionStiffness,
|
||||
WheelsDampingCompression = tuning.SuspensionCompression,
|
||||
WheelsDampingRelaxation = tuning.SuspensionDamping,
|
||||
FrictionSlip = tuning.FrictionSlip,
|
||||
IsFrontWheel = isFrontWheel,
|
||||
MaxSuspensionTravelCm = tuning.MaxSuspensionTravelCm,
|
||||
MaxSuspensionForce = tuning.MaxSuspensionForce,
|
||||
};
|
||||
|
||||
ci.ChassisConnectionCS = connectionPointCS;
|
||||
ci.WheelDirectionCS = wheelDirectionCS0;
|
||||
ci.WheelAxleCS = wheelAxleCS;
|
||||
ci.SuspensionRestLength = suspensionRestLength;
|
||||
ci.WheelRadius = wheelRadius;
|
||||
ci.SuspensionStiffness = tuning.SuspensionStiffness;
|
||||
ci.WheelsDampingCompression = tuning.SuspensionCompression;
|
||||
ci.WheelsDampingRelaxation = tuning.SuspensionDamping;
|
||||
ci.FrictionSlip = tuning.FrictionSlip;
|
||||
ci.IsFrontWheel = isFrontWheel;
|
||||
ci.MaxSuspensionTravelCm = tuning.MaxSuspensionTravelCm;
|
||||
ci.MaxSuspensionForce = tuning.MaxSuspensionForce;
|
||||
|
||||
WheelInfo wheel = new WheelInfo(ci);
|
||||
wheelInfo.Add(wheel);
|
||||
var wheel = new WheelInfo(ci);
|
||||
_wheelInfo.Add(wheel);
|
||||
|
||||
UpdateWheelTransformsWS(wheel, false);
|
||||
UpdateWheelTransform(NumWheels - 1, false);
|
||||
|
@ -203,7 +203,7 @@ namespace VehicleDemo
|
|||
{
|
||||
Debug.Assert((index >= 0) && (index < NumWheels));
|
||||
|
||||
return wheelInfo[index];
|
||||
return _wheelInfo[index];
|
||||
}
|
||||
|
||||
private float RayCast(WheelInfo wheel)
|
||||
|
@ -356,51 +356,51 @@ namespace VehicleDemo
|
|||
if (numWheel == 0)
|
||||
return;
|
||||
|
||||
Array.Resize<Vector3>(ref forwardWS, numWheel);
|
||||
Array.Resize<Vector3>(ref axle, numWheel);
|
||||
Array.Resize<float>(ref forwardImpulse, numWheel);
|
||||
Array.Resize<float>(ref sideImpulse, numWheel);
|
||||
Array.Resize(ref _forwardWS, numWheel);
|
||||
Array.Resize(ref _axle, numWheel);
|
||||
Array.Resize(ref _forwardImpulse, numWheel);
|
||||
Array.Resize(ref _sideImpulse, numWheel);
|
||||
|
||||
int numWheelsOnGround = 0;
|
||||
|
||||
//collapse all those loops into one!
|
||||
for (int i = 0; i < NumWheels; i++)
|
||||
{
|
||||
RigidBody groundObject = wheelInfo[i].RaycastInfo.GroundObject as RigidBody;
|
||||
RigidBody groundObject = _wheelInfo[i].RaycastInfo.GroundObject as RigidBody;
|
||||
if (groundObject != null)
|
||||
numWheelsOnGround++;
|
||||
sideImpulse[i] = 0;
|
||||
forwardImpulse[i] = 0;
|
||||
_sideImpulse[i] = 0;
|
||||
_forwardImpulse[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumWheels; i++)
|
||||
{
|
||||
WheelInfo wheel = wheelInfo[i];
|
||||
WheelInfo wheel = _wheelInfo[i];
|
||||
|
||||
RigidBody groundObject = wheel.RaycastInfo.GroundObject as RigidBody;
|
||||
if (groundObject != null)
|
||||
{
|
||||
Matrix wheelTrans = GetWheelTransformWS(i);
|
||||
|
||||
axle[i] = new Vector3(
|
||||
_axle[i] = new Vector3(
|
||||
wheelTrans[0, indexRightAxis],
|
||||
wheelTrans[1, indexRightAxis],
|
||||
wheelTrans[2, indexRightAxis]);
|
||||
|
||||
Vector3 surfNormalWS = wheel.RaycastInfo.ContactNormalWS;
|
||||
float proj;
|
||||
Vector3.Dot(ref axle[i], ref surfNormalWS, out proj);
|
||||
axle[i] -= surfNormalWS * proj;
|
||||
axle[i].Normalize();
|
||||
Vector3.Dot(ref _axle[i], ref surfNormalWS, out proj);
|
||||
_axle[i] -= surfNormalWS * proj;
|
||||
_axle[i].Normalize();
|
||||
|
||||
Vector3.Cross(ref surfNormalWS, ref axle[i], out forwardWS[i]);
|
||||
forwardWS[i].Normalize();
|
||||
Vector3.Cross(ref surfNormalWS, ref _axle[i], out _forwardWS[i]);
|
||||
_forwardWS[i].Normalize();
|
||||
|
||||
ResolveSingleBilateral(chassisBody, wheel.RaycastInfo.ContactPointWS,
|
||||
groundObject, wheel.RaycastInfo.ContactPointWS,
|
||||
0, axle[i], ref sideImpulse[i], timeStep);
|
||||
0, _axle[i], ref _sideImpulse[i], timeStep);
|
||||
|
||||
sideImpulse[i] *= sideFrictionStiffness2;
|
||||
_sideImpulse[i] *= sideFrictionStiffness2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,7 +411,7 @@ namespace VehicleDemo
|
|||
|
||||
for (int i = 0; i < NumWheels; i++)
|
||||
{
|
||||
WheelInfo wheel = wheelInfo[i];
|
||||
WheelInfo wheel = _wheelInfo[i];
|
||||
RigidBody groundObject = wheel.RaycastInfo.GroundObject as RigidBody;
|
||||
|
||||
float rollingFriction = 0.0f;
|
||||
|
@ -426,18 +426,18 @@ namespace VehicleDemo
|
|||
{
|
||||
float defaultRollingFrictionImpulse = 0.0f;
|
||||
float maxImpulse = (wheel.Brake != 0) ? wheel.Brake : defaultRollingFrictionImpulse;
|
||||
rollingFriction = CalcRollingFriction(chassisBody, groundObject, wheel.RaycastInfo.ContactPointWS, forwardWS[i], maxImpulse);
|
||||
rollingFriction = CalcRollingFriction(chassisBody, groundObject, wheel.RaycastInfo.ContactPointWS, _forwardWS[i], maxImpulse);
|
||||
}
|
||||
}
|
||||
|
||||
//switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
|
||||
|
||||
forwardImpulse[i] = 0;
|
||||
wheelInfo[i].SkidInfo = 1.0f;
|
||||
_forwardImpulse[i] = 0;
|
||||
_wheelInfo[i].SkidInfo = 1.0f;
|
||||
|
||||
if (groundObject != null)
|
||||
{
|
||||
wheelInfo[i].SkidInfo = 1.0f;
|
||||
_wheelInfo[i].SkidInfo = 1.0f;
|
||||
|
||||
float maximp = wheel.WheelsSuspensionForce * timeStep * wheel.FrictionSlip;
|
||||
float maximpSide = maximp;
|
||||
|
@ -445,10 +445,10 @@ namespace VehicleDemo
|
|||
float maximpSquared = maximp * maximpSide;
|
||||
|
||||
|
||||
forwardImpulse[i] = rollingFriction;//wheel.EngineForce* timeStep;
|
||||
_forwardImpulse[i] = rollingFriction;//wheel.EngineForce* timeStep;
|
||||
|
||||
float x = forwardImpulse[i] * fwdFactor;
|
||||
float y = sideImpulse[i] * sideFactor;
|
||||
float x = _forwardImpulse[i] * fwdFactor;
|
||||
float y = _sideImpulse[i] * sideFactor;
|
||||
|
||||
float impulseSquared = (x * x + y * y);
|
||||
|
||||
|
@ -458,7 +458,7 @@ namespace VehicleDemo
|
|||
|
||||
float factor = maximp / (float)System.Math.Sqrt(impulseSquared);
|
||||
|
||||
wheelInfo[i].SkidInfo *= factor;
|
||||
_wheelInfo[i].SkidInfo *= factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -467,12 +467,12 @@ namespace VehicleDemo
|
|||
{
|
||||
for (int wheel = 0; wheel < NumWheels; wheel++)
|
||||
{
|
||||
if (sideImpulse[wheel] != 0)
|
||||
if (_sideImpulse[wheel] != 0)
|
||||
{
|
||||
if (wheelInfo[wheel].SkidInfo < 1.0f)
|
||||
if (_wheelInfo[wheel].SkidInfo < 1.0f)
|
||||
{
|
||||
forwardImpulse[wheel] *= wheelInfo[wheel].SkidInfo;
|
||||
sideImpulse[wheel] *= wheelInfo[wheel].SkidInfo;
|
||||
_forwardImpulse[wheel] *= _wheelInfo[wheel].SkidInfo;
|
||||
_sideImpulse[wheel] *= _wheelInfo[wheel].SkidInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -481,16 +481,16 @@ namespace VehicleDemo
|
|||
// apply the impulses
|
||||
for (int i = 0; i < NumWheels; i++)
|
||||
{
|
||||
WheelInfo wheel = wheelInfo[i];
|
||||
WheelInfo wheel = _wheelInfo[i];
|
||||
|
||||
Vector3 rel_pos = wheel.RaycastInfo.ContactPointWS -
|
||||
chassisBody.CenterOfMassPosition;
|
||||
|
||||
if (forwardImpulse[i] != 0)
|
||||
if (_forwardImpulse[i] != 0)
|
||||
{
|
||||
chassisBody.ApplyImpulse(forwardWS[i] * forwardImpulse[i], rel_pos);
|
||||
chassisBody.ApplyImpulse(_forwardWS[i] * _forwardImpulse[i], rel_pos);
|
||||
}
|
||||
if (sideImpulse[i] != 0)
|
||||
if (_sideImpulse[i] != 0)
|
||||
{
|
||||
RigidBody groundObject = wheel.RaycastInfo.GroundObject as RigidBody;
|
||||
|
||||
|
@ -498,7 +498,7 @@ namespace VehicleDemo
|
|||
groundObject.CenterOfMassPosition;
|
||||
|
||||
|
||||
Vector3 sideImp = axle[i] * sideImpulse[i];
|
||||
Vector3 sideImp = _axle[i] * _sideImpulse[i];
|
||||
|
||||
#if ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
|
||||
//Vector4 vChassisWorldUp = RigidBody.CenterOfMassTransform.get_Columns(indexUpAxis);
|
||||
|
@ -526,7 +526,7 @@ namespace VehicleDemo
|
|||
|
||||
for (int w_it = 0; w_it < NumWheels; w_it++)
|
||||
{
|
||||
WheelInfo wheel_info = wheelInfo[w_it];
|
||||
WheelInfo wheel_info = _wheelInfo[w_it];
|
||||
|
||||
if (wheel_info.RaycastInfo.IsInContact)
|
||||
{
|
||||
|
@ -595,18 +595,18 @@ namespace VehicleDemo
|
|||
}
|
||||
|
||||
// Simulate suspension
|
||||
for (int i = 0; i < wheelInfo.Count; i++)
|
||||
for (int i = 0; i < _wheelInfo.Count; i++)
|
||||
{
|
||||
float depth = RayCast(wheelInfo[i]);
|
||||
float depth = RayCast(_wheelInfo[i]);
|
||||
}
|
||||
|
||||
|
||||
UpdateSuspension(step);
|
||||
|
||||
for (int i = 0; i < wheelInfo.Count; i++)
|
||||
for (int i = 0; i < _wheelInfo.Count; i++)
|
||||
{
|
||||
//apply suspension force
|
||||
WheelInfo wheel = wheelInfo[i];
|
||||
WheelInfo wheel = _wheelInfo[i];
|
||||
|
||||
float suspensionForce = wheel.WheelsSuspensionForce;
|
||||
|
||||
|
@ -623,9 +623,9 @@ namespace VehicleDemo
|
|||
|
||||
UpdateFriction(step);
|
||||
|
||||
for (int i = 0; i < wheelInfo.Count; i++)
|
||||
for (int i = 0; i < _wheelInfo.Count; i++)
|
||||
{
|
||||
WheelInfo wheel = wheelInfo[i];
|
||||
WheelInfo wheel = _wheelInfo[i];
|
||||
Vector3 relpos = wheel.RaycastInfo.HardPointWS - RigidBody.CenterOfMassPosition;
|
||||
Vector3 vel = RigidBody.GetVelocityInLocalPoint(relpos);
|
||||
|
||||
|
@ -658,7 +658,7 @@ namespace VehicleDemo
|
|||
|
||||
public void UpdateWheelTransform(int wheelIndex, bool interpolatedTransform)
|
||||
{
|
||||
WheelInfo wheel = wheelInfo[wheelIndex];
|
||||
WheelInfo wheel = _wheelInfo[wheelIndex];
|
||||
UpdateWheelTransformsWS(wheel, interpolatedTransform);
|
||||
Vector3 up = -wheel.RaycastInfo.WheelDirectionWS;
|
||||
Vector3 right = wheel.RaycastInfo.WheelAxleWS;
|
||||
|
|
|
@ -8,287 +8,350 @@ using DemoFramework;
|
|||
|
||||
namespace VehicleDemo
|
||||
{
|
||||
class VehicleDemo : Demo
|
||||
internal static class Program
|
||||
{
|
||||
Vector3 eye = new Vector3(35, 45, -55);
|
||||
Vector3 target = Vector3.Zero;
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
DemoRunner.Run<VehicleDemo>();
|
||||
}
|
||||
}
|
||||
|
||||
//bool UseTrimeshGround = false;
|
||||
//string heightfieldFile = Path.Combine("data", "heightfield128x128.raw");
|
||||
|
||||
const int rightIndex = 0;
|
||||
const int upIndex = 1;
|
||||
const int forwardIndex = 2;
|
||||
Vector3 wheelDirectionCS0 = new Vector3(0, -1, 0);
|
||||
Vector3 wheelAxleCS = new Vector3(-1, 0, 0);
|
||||
|
||||
const int maxProxies = 32766;
|
||||
const int maxOverlap = 65535;
|
||||
|
||||
// btRaycastVehicle is the interface for the constraint that implements the raycast vehicle
|
||||
// notice that for higher-quality slow-moving vehicles, another approach might be better
|
||||
// implementing explicit hinged-wheel constraints with cylinder collision, rather then raycasts
|
||||
float gEngineForce = 0.0f;
|
||||
float gBreakingForce = 0.0f;
|
||||
|
||||
const float maxEngineForce = 2000.0f;//this should be engine/velocity dependent
|
||||
internal sealed class VehicleDemo : IDemoConfiguration, IUpdateReceiver
|
||||
{
|
||||
const float maxEngineForce = 2000.0f;
|
||||
const float maxBreakingForce = 100.0f;
|
||||
|
||||
float gVehicleSteering = 0.0f;
|
||||
const float steeringIncrement = 1.0f;
|
||||
const float steeringClamp = 0.3f;
|
||||
public const float wheelRadius = 0.7f;
|
||||
public const float wheelWidth = 0.4f;
|
||||
const float wheelFriction = 1000;//BT_LARGE_FLOAT;
|
||||
const float suspensionStiffness = 20.0f;
|
||||
const float suspensionDamping = 2.3f;
|
||||
const float suspensionCompression = 4.4f;
|
||||
const float rollInfluence = 0.1f;//1.0f;
|
||||
|
||||
const float suspensionRestLength = 0.6f;
|
||||
const float CUBE_HALF_EXTENTS = 1;
|
||||
public string WindowTitle => "BulletSharp - Vehicle Demo";
|
||||
|
||||
public ISimulation CreateSimulation(Demo demo)
|
||||
{
|
||||
demo.FreeLook.Eye = new Vector3(35, 45, -55);
|
||||
demo.FreeLook.Target = Vector3.Zero;
|
||||
demo.DemoText =
|
||||
"Drive with arrow keys\n" +
|
||||
"Space - break";
|
||||
demo.Graphics.FarPlane = 600.0f;
|
||||
//demo.DebugDrawMode = DebugDrawModes.DrawAabb;
|
||||
demo.IsDebugDrawEnabled = true;
|
||||
return new VehicleDemoSimulation();
|
||||
}
|
||||
|
||||
public void Update(Demo demo)
|
||||
{
|
||||
var simulation = demo.Simulation as VehicleDemoSimulation;
|
||||
|
||||
var keysDown = demo.Input.KeysDown;
|
||||
|
||||
if (keysDown.Contains(Keys.Left))
|
||||
{
|
||||
simulation.VehicleSteering += demo.FrameDelta * steeringIncrement;
|
||||
if (simulation.VehicleSteering > steeringClamp)
|
||||
simulation.VehicleSteering = steeringClamp;
|
||||
}
|
||||
else if (simulation.VehicleSteering - float.Epsilon > 0)
|
||||
{
|
||||
simulation.VehicleSteering -= demo.FrameDelta * steeringIncrement;
|
||||
}
|
||||
|
||||
if (keysDown.Contains(Keys.Right))
|
||||
{
|
||||
simulation.VehicleSteering -= demo.FrameDelta * steeringIncrement;
|
||||
if (simulation.VehicleSteering < -steeringClamp)
|
||||
simulation.VehicleSteering = -steeringClamp;
|
||||
}
|
||||
else if (simulation.VehicleSteering + float.Epsilon < 0)
|
||||
{
|
||||
simulation.VehicleSteering += demo.FrameDelta * steeringIncrement;
|
||||
}
|
||||
|
||||
if (keysDown.Contains(Keys.Up))
|
||||
{
|
||||
simulation.EngineForce = maxEngineForce;
|
||||
}
|
||||
|
||||
if (keysDown.Contains(Keys.Down))
|
||||
{
|
||||
simulation.EngineForce = -maxEngineForce;
|
||||
}
|
||||
|
||||
if (keysDown.Contains(Keys.Space))
|
||||
{
|
||||
simulation.EngineForce = 0;
|
||||
simulation.BreakingForce = maxBreakingForce;
|
||||
}
|
||||
|
||||
if (demo.Input.KeysReleased.Contains(Keys.Space))
|
||||
{
|
||||
simulation.BreakingForce = 0;
|
||||
}
|
||||
|
||||
simulation.OnUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class VehicleDemoSimulation : ISimulation
|
||||
{
|
||||
private const int rightIndex = 0;
|
||||
private const int upIndex = 1;
|
||||
private const int forwardIndex = 2;
|
||||
|
||||
private const int maxProxies = 32766;
|
||||
private const int maxOverlap = 65535;
|
||||
|
||||
private const float wheelRadius = 0.7f;
|
||||
private const float wheelWidth = 0.4f;
|
||||
private const float wheelFriction = 1000; //float.MaxValue
|
||||
private const float suspensionStiffness = 20.0f;
|
||||
private const float suspensionDamping = 2.3f;
|
||||
private const float suspensionCompression = 4.4f;
|
||||
private const float rollInfluence = 0.1f; //1.0f;
|
||||
|
||||
private const float suspensionRestLength = 0.6f;
|
||||
private const float CUBE_HALF_EXTENTS = 1;
|
||||
|
||||
private IntPtr _terrainData;
|
||||
|
||||
//public RaycastVehicle vehicle;
|
||||
public CustomVehicle vehicle;
|
||||
|
||||
protected override void OnInitialize()
|
||||
public VehicleDemoSimulation()
|
||||
{
|
||||
Freelook.SetEyeTarget(eye, target);
|
||||
|
||||
Graphics.SetFormText("BulletSharp - Vehicle Demo");
|
||||
DemoText = "Drive with arrow keys\n" +
|
||||
"Space - break";
|
||||
|
||||
Graphics.FarPlane = 600.0f;
|
||||
//DebugDrawMode = DebugDrawModes.DrawAabb;
|
||||
IsDebugDrawEnabled = true;
|
||||
}
|
||||
|
||||
protected override void OnInitializePhysics()
|
||||
{
|
||||
CollisionShape groundShape = new BoxShape(50, 3, 50);
|
||||
CollisionShapes.Add(groundShape);
|
||||
|
||||
CollisionConf = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConf);
|
||||
Solver = new SequentialImpulseConstraintSolver();
|
||||
CollisionConfiguration = new DefaultCollisionConfiguration();
|
||||
Dispatcher = new CollisionDispatcher(CollisionConfiguration);
|
||||
|
||||
Vector3 worldMin = new Vector3(-10000, -10000, -10000);
|
||||
Vector3 worldMax = new Vector3(10000, 10000, 10000);
|
||||
Broadphase = new AxisSweep3(worldMin, worldMax);
|
||||
//Broadphase = new DbvtBroadphase();
|
||||
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);
|
||||
World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, null, CollisionConfiguration);
|
||||
World.SetInternalTickCallback(PickingPreTickCallback, this, true);
|
||||
|
||||
int i;
|
||||
Matrix tr;
|
||||
Matrix vehicleTr;
|
||||
//if (UseTrimeshGround)
|
||||
CreateScene();
|
||||
}
|
||||
|
||||
public CollisionConfiguration CollisionConfiguration { get; }
|
||||
public CollisionDispatcher Dispatcher { get; }
|
||||
public BroadphaseInterface Broadphase { get; }
|
||||
public DiscreteDynamicsWorld World { get; }
|
||||
|
||||
// RaycastVehicle is the interface for the constraint that implements the raycast vehicle
|
||||
// notice that for higher-quality slow-moving vehicles, another approach might be better
|
||||
// implementing explicit hinged-wheel constraints with cylinder collision, rather then raycasts
|
||||
public float EngineForce { get; set; } = 0.0f;
|
||||
public float BreakingForce { get; set; } = 0.0f;
|
||||
|
||||
public float VehicleSteering { get; set; } = 0.0f;
|
||||
|
||||
public void OnUpdate()
|
||||
{
|
||||
vehicle.ApplyEngineForce(EngineForce, 2);
|
||||
vehicle.SetBrake(BreakingForce, 2);
|
||||
vehicle.ApplyEngineForce(EngineForce, 3);
|
||||
vehicle.SetBrake(BreakingForce, 3);
|
||||
|
||||
vehicle.SetSteeringValue(VehicleSteering, 0);
|
||||
vehicle.SetSteeringValue(VehicleSteering, 1);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_terrainData != IntPtr.Zero)
|
||||
{
|
||||
const float scale = 20.0f;
|
||||
Marshal.FreeHGlobal(_terrainData);
|
||||
}
|
||||
|
||||
//create a triangle-mesh ground
|
||||
const int NumVertsX = 20;
|
||||
const int NumVertsY = 20;
|
||||
const int totalVerts = NumVertsX * NumVertsY;
|
||||
this.StandardCleanup();
|
||||
}
|
||||
|
||||
const int totalTriangles = 2 * (NumVertsX - 1) * (NumVertsY - 1);
|
||||
private void PickingPreTickCallback(DynamicsWorld world, float timeStep)
|
||||
{
|
||||
EngineForce *= (1.0f - timeStep);
|
||||
|
||||
TriangleIndexVertexArray vertexArray = new TriangleIndexVertexArray();
|
||||
IndexedMesh mesh = new IndexedMesh();
|
||||
mesh.Allocate(totalTriangles, totalVerts);
|
||||
mesh.NumTriangles = totalTriangles;
|
||||
mesh.NumVertices = totalVerts;
|
||||
mesh.TriangleIndexStride = 3 * sizeof(int);
|
||||
mesh.VertexStride = Vector3.SizeInBytes;
|
||||
using (var indicesStream = mesh.GetTriangleStream())
|
||||
{
|
||||
var indices = new BinaryWriter(indicesStream);
|
||||
for (i = 0; i < NumVertsX - 1; i++)
|
||||
{
|
||||
for (int j = 0; j < NumVertsY - 1; j++)
|
||||
{
|
||||
indices.Write(j * NumVertsX + i);
|
||||
indices.Write(j * NumVertsX + i + 1);
|
||||
indices.Write((j + 1) * NumVertsX + i + 1);
|
||||
vehicle.ApplyEngineForce(EngineForce, 2);
|
||||
vehicle.SetBrake(BreakingForce, 2);
|
||||
vehicle.ApplyEngineForce(EngineForce, 3);
|
||||
vehicle.SetBrake(BreakingForce, 3);
|
||||
|
||||
indices.Write(j * NumVertsX + i);
|
||||
indices.Write((j + 1) * NumVertsX + i + 1);
|
||||
indices.Write((j + 1) * NumVertsX + i);
|
||||
}
|
||||
}
|
||||
indices.Dispose();
|
||||
}
|
||||
vehicle.SetSteeringValue(VehicleSteering, 0);
|
||||
vehicle.SetSteeringValue(VehicleSteering, 1);
|
||||
}
|
||||
|
||||
using (var vertexStream = mesh.GetVertexStream())
|
||||
{
|
||||
var vertices = new BinaryWriter(vertexStream);
|
||||
for (i = 0; i < NumVertsX; i++)
|
||||
{
|
||||
for (int j = 0; j < NumVertsY; j++)
|
||||
{
|
||||
float wl = .2f;
|
||||
float height = 20.0f * (float)(Math.Sin(i * wl) * Math.Cos(j * wl));
|
||||
private void CreateScene()
|
||||
{
|
||||
CreateTrimeshGround();
|
||||
//CreateHeightfieldTerrainFromFile();
|
||||
//CreateHeightfieldTerrain();
|
||||
}
|
||||
|
||||
vertices.Write((i - NumVertsX * 0.5f) * scale);
|
||||
vertices.Write(height);
|
||||
vertices.Write((j - NumVertsY * 0.5f) * scale);
|
||||
}
|
||||
}
|
||||
vertices.Dispose();
|
||||
}
|
||||
private void CreateTrimeshGround()
|
||||
{
|
||||
const float scale = 20.0f;
|
||||
|
||||
vertexArray.AddIndexedMesh(mesh);
|
||||
groundShape = new BvhTriangleMeshShape(vertexArray, true);
|
||||
//create a triangle-mesh ground
|
||||
const int NumVertsX = 20;
|
||||
const int NumVertsY = 20;
|
||||
const int totalVerts = NumVertsX * NumVertsY;
|
||||
|
||||
tr = Matrix.Identity;
|
||||
vehicleTr = Matrix.Translation(0, -2, 0);
|
||||
}/*
|
||||
else
|
||||
const int totalTriangles = 2 * (NumVertsX - 1) * (NumVertsY - 1);
|
||||
|
||||
var vertexArray = new TriangleIndexVertexArray();
|
||||
var mesh = new IndexedMesh();
|
||||
mesh.Allocate(totalTriangles, totalVerts);
|
||||
mesh.NumTriangles = totalTriangles;
|
||||
mesh.NumVertices = totalVerts;
|
||||
mesh.TriangleIndexStride = 3 * sizeof(int);
|
||||
mesh.VertexStride = Vector3.SizeInBytes;
|
||||
using (var indicesStream = mesh.GetTriangleStream())
|
||||
{
|
||||
// Use HeightfieldTerrainShape
|
||||
|
||||
int width = 40, length = 40;
|
||||
//int width = 128, length = 128; // Debugging is too slow for this
|
||||
float maxHeight = 10.0f;
|
||||
float heightScale = maxHeight / 256.0f;
|
||||
Vector3 scale = new Vector3(20.0f, maxHeight, 20.0f);
|
||||
|
||||
//PhyScalarType scalarType = PhyScalarType.PhyUChar;
|
||||
//FileStream file = new FileStream(heightfieldFile, FileMode.Open, FileAccess.Read);
|
||||
|
||||
// Use float data
|
||||
PhyScalarType scalarType = PhyScalarType.PhyFloat;
|
||||
byte[] terr = new byte[width * length * 4];
|
||||
MemoryStream file = new MemoryStream(terr);
|
||||
BinaryWriter writer = new BinaryWriter(file);
|
||||
for (i = 0; i < width; i++)
|
||||
for (int j = 0; j < length; j++)
|
||||
writer.Write((float)((maxHeight / 2) + 4 * Math.Sin(j * 0.5f) * Math.Cos(i)));
|
||||
writer.Flush();
|
||||
file.Position = 0;
|
||||
|
||||
HeightfieldTerrainShape heightterrainShape = new HeightfieldTerrainShape(width, length,
|
||||
file, heightScale, 0, maxHeight, upIndex, scalarType, false);
|
||||
heightterrainShape.SetUseDiamondSubdivision(true);
|
||||
|
||||
groundShape = heightterrainShape;
|
||||
groundShape.LocalScaling = new Vector3(scale.X, 1, scale.Z);
|
||||
|
||||
tr = Matrix.Translation(new Vector3(-scale.X / 2, scale.Y / 2, -scale.Z / 2));
|
||||
vehicleTr = Matrix.Translation(new Vector3(20, 3, -3));
|
||||
|
||||
|
||||
// Create graphics object
|
||||
|
||||
file.Position = 0;
|
||||
BinaryReader reader = new BinaryReader(file);
|
||||
|
||||
int totalTriangles = (width - 1) * (length - 1) * 2;
|
||||
int totalVerts = width * length;
|
||||
|
||||
game.groundMesh = new Mesh(game.Device, totalTriangles, totalVerts,
|
||||
MeshFlags.SystemMemory | MeshFlags.Use32Bit, VertexFormat.Position | VertexFormat.Normal);
|
||||
SlimDX.DataStream data = game.groundMesh.LockVertexBuffer(LockFlags.None);
|
||||
for (i = 0; i < width; i++)
|
||||
var indices = new BinaryWriter(indicesStream);
|
||||
for (int i = 0; i < NumVertsX - 1; i++)
|
||||
{
|
||||
for (int j = 0; j < length; j++)
|
||||
for (int j = 0; j < NumVertsY - 1; j++)
|
||||
{
|
||||
float height;
|
||||
if (scalarType == PhyScalarType.PhyFloat)
|
||||
{
|
||||
// heightScale isn't applied internally for float data
|
||||
height = reader.ReadSingle();
|
||||
}
|
||||
else if (scalarType == PhyScalarType.PhyUChar)
|
||||
{
|
||||
height = file.ReadByte() * heightScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
height = 0.0f;
|
||||
}
|
||||
indices.Write(j * NumVertsX + i);
|
||||
indices.Write(j * NumVertsX + i + 1);
|
||||
indices.Write((j + 1) * NumVertsX + i + 1);
|
||||
|
||||
data.Write((j - length * 0.5f) * scale.X);
|
||||
data.Write(height);
|
||||
data.Write((i - width * 0.5f) * scale.Z);
|
||||
|
||||
// Normals will be calculated later
|
||||
data.Position += 12;
|
||||
indices.Write(j * NumVertsX + i);
|
||||
indices.Write((j + 1) * NumVertsX + i + 1);
|
||||
indices.Write((j + 1) * NumVertsX + i);
|
||||
}
|
||||
}
|
||||
game.groundMesh.UnlockVertexBuffer();
|
||||
file.Close();
|
||||
indices.Dispose();
|
||||
}
|
||||
|
||||
data = game.groundMesh.LockIndexBuffer(LockFlags.None);
|
||||
for (i = 0; i < width - 1; i++)
|
||||
using (var vertexStream = mesh.GetVertexStream())
|
||||
{
|
||||
var vertices = new BinaryWriter(vertexStream);
|
||||
for (int i = 0; i < NumVertsX; i++)
|
||||
{
|
||||
for (int j = 0; j < length - 1; j++)
|
||||
for (int j = 0; j < NumVertsY; j++)
|
||||
{
|
||||
// Using diamond subdivision
|
||||
if ((j + i) % 2 == 0)
|
||||
{
|
||||
data.Write(j * width + i);
|
||||
data.Write((j + 1) * width + i + 1);
|
||||
data.Write(j * width + i + 1);
|
||||
float wl = .2f;
|
||||
float height = 20.0f * (float)(Math.Sin(i * wl) * Math.Cos(j * wl));
|
||||
|
||||
data.Write(j * width + i);
|
||||
data.Write((j + 1) * width + i);
|
||||
data.Write((j + 1) * width + i + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Write(j * width + i);
|
||||
data.Write((j + 1) * width + i);
|
||||
data.Write(j * width + i + 1);
|
||||
|
||||
data.Write(j * width + i + 1);
|
||||
data.Write((j + 1) * width + i);
|
||||
data.Write((j + 1) * width + i + 1);
|
||||
}
|
||||
|
||||
/ *
|
||||
// Not using diamond subdivision
|
||||
data.Write(j * width + i);
|
||||
data.Write((j + 1) * width + i);
|
||||
data.Write(j * width + i + 1);
|
||||
|
||||
data.Write(j * width + i + 1);
|
||||
data.Write((j + 1) * width + i);
|
||||
data.Write((j + 1) * width + i + 1);
|
||||
* /
|
||||
vertices.Write((i - NumVertsX * 0.5f) * scale);
|
||||
vertices.Write(height);
|
||||
vertices.Write((j - NumVertsY * 0.5f) * scale);
|
||||
}
|
||||
}
|
||||
game.groundMesh.UnlockIndexBuffer();
|
||||
vertices.Dispose();
|
||||
}
|
||||
|
||||
game.groundMesh.ComputeNormals();
|
||||
}*/
|
||||
vertexArray.AddIndexedMesh(mesh);
|
||||
var groundShape = new BvhTriangleMeshShape(vertexArray, true);
|
||||
|
||||
CollisionShapes.Add(groundShape);
|
||||
|
||||
RigidBody ground = LocalCreateRigidBody(0, tr, groundShape);
|
||||
RigidBody ground = PhysicsHelper.CreateStaticBody(Matrix.Identity, groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
|
||||
CreateVehicle(vehicleTr);
|
||||
Matrix vehicleTransform = Matrix.Translation(0, -2, 0);
|
||||
CreateVehicle(vehicleTransform);
|
||||
}
|
||||
|
||||
private void CreateHeightfieldTerrainFromFile()
|
||||
{
|
||||
const float minHeight = 0;
|
||||
const float maxHeight = 10.0f;
|
||||
const float heightScale = maxHeight / 256.0f;
|
||||
const int width = 128, length = 128;
|
||||
const int dataLength = width * length * sizeof(byte);
|
||||
const PhyScalarType scalarType = PhyScalarType.UChar;
|
||||
|
||||
var scale = new Vector3(5.0f, maxHeight, 5.0f);
|
||||
|
||||
string heightfieldFile = Path.Combine("data", "heightfield128x128.raw");
|
||||
_terrainData = Marshal.AllocHGlobal(dataLength);
|
||||
|
||||
using (var stream = new FileStream(heightfieldFile, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
using (var reader = new BinaryReader(stream))
|
||||
{
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
int offset = (int)stream.Position;
|
||||
byte height = reader.ReadByte();
|
||||
Marshal.WriteByte(_terrainData, offset, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var shape = new HeightfieldTerrainShape(width, length,
|
||||
_terrainData, heightScale, minHeight, maxHeight, upIndex, scalarType, false);
|
||||
shape.SetUseDiamondSubdivision(true);
|
||||
shape.LocalScaling = new Vector3(scale.X, 1, scale.Z);
|
||||
|
||||
Matrix transform = Matrix.Translation(-scale.X / 2, scale.Y / 2, -scale.Z / 2);
|
||||
|
||||
RigidBody ground = PhysicsHelper.CreateStaticBody(transform, shape, World);
|
||||
ground.UserObject = "Ground";
|
||||
|
||||
Matrix vehicleTransform = Matrix.Translation(new Vector3(20, 3, -3));
|
||||
CreateVehicle(vehicleTransform);
|
||||
}
|
||||
|
||||
private void CreateHeightfieldTerrain()
|
||||
{
|
||||
const float minHeight = 0;
|
||||
const float maxHeight = 10.0f;
|
||||
const float heightScale = maxHeight / 256.0f;
|
||||
const int width = 64, length = 64;
|
||||
const int dataLength = width * length * sizeof(float);
|
||||
const PhyScalarType scalarType = PhyScalarType.Float;
|
||||
|
||||
var scale = new Vector3(15.0f, maxHeight, 15.0f);
|
||||
|
||||
_terrainData = Marshal.AllocHGlobal(dataLength);
|
||||
var terrain = new byte[dataLength];
|
||||
|
||||
using (var file = new MemoryStream(terrain))
|
||||
{
|
||||
using (var writer = new BinaryWriter(file))
|
||||
{
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
for (int j = 0; j < length; j++)
|
||||
{
|
||||
writer.Write((float)((maxHeight / 2) + 4 * Math.Sin(j * 0.5f) * Math.Cos(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Marshal.Copy(terrain, 0, _terrainData, terrain.Length);
|
||||
|
||||
var groundShape = new HeightfieldTerrainShape(width, length,
|
||||
_terrainData, heightScale, minHeight, maxHeight, upIndex, scalarType, false);
|
||||
groundShape.SetUseDiamondSubdivision(true);
|
||||
groundShape.LocalScaling = new Vector3(scale.X, 1, scale.Z);
|
||||
|
||||
Matrix transform = Matrix.Translation(-scale.X / 2, scale.Y / 2, -scale.Z / 2);
|
||||
|
||||
RigidBody ground = PhysicsHelper.CreateStaticBody(transform, groundShape, World);
|
||||
ground.UserObject = "Ground";
|
||||
|
||||
Matrix vehicleTransform = Matrix.Translation(new Vector3(20, 3, -3));
|
||||
CreateVehicle(vehicleTransform);
|
||||
}
|
||||
|
||||
private void CreateVehicle(Matrix transform)
|
||||
{
|
||||
CollisionShape chassisShape = new BoxShape(1.0f, 0.5f, 2.0f);
|
||||
CollisionShapes.Add(chassisShape);
|
||||
var chassisShape = new BoxShape(1.0f, 0.5f, 2.0f);
|
||||
|
||||
CompoundShape compound = new CompoundShape();
|
||||
CollisionShapes.Add(compound);
|
||||
var compound = new CompoundShape();
|
||||
|
||||
//localTrans effectively shifts the center of mass with respect to the chassis
|
||||
Matrix localTrans = Matrix.Translation(Vector3.UnitY);
|
||||
compound.AddChildShape(localTrans, chassisShape);
|
||||
RigidBody carChassis = LocalCreateRigidBody(800, Matrix.Identity, compound);
|
||||
RigidBody carChassis = PhysicsHelper.CreateBody(800, Matrix.Identity, compound, World);
|
||||
carChassis.UserObject = "Chassis";
|
||||
//carChassis.SetDamping(0.2f, 0.2f);
|
||||
|
||||
VehicleTuning tuning = new VehicleTuning();
|
||||
IVehicleRaycaster vehicleRayCaster = new DefaultVehicleRaycaster(World);
|
||||
var tuning = new VehicleTuning();
|
||||
var vehicleRayCaster = new DefaultVehicleRaycaster(World);
|
||||
//vehicle = new RaycastVehicle(tuning, carChassis, vehicleRayCaster);
|
||||
vehicle = new CustomVehicle(tuning, carChassis, vehicleRayCaster);
|
||||
|
||||
|
@ -297,23 +360,29 @@ namespace VehicleDemo
|
|||
|
||||
|
||||
const float connectionHeight = 1.2f;
|
||||
bool isFrontWheel = true;
|
||||
|
||||
// choose coordinate system
|
||||
vehicle.SetCoordinateSystem(rightIndex, upIndex, forwardIndex);
|
||||
|
||||
Vector3 connectionPointCS0 = new Vector3(CUBE_HALF_EXTENTS - (0.3f * wheelWidth), connectionHeight, 2 * CUBE_HALF_EXTENTS - wheelRadius);
|
||||
vehicle.AddWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius, tuning, isFrontWheel);
|
||||
Vector3 wheelDirection = Vector3.Zero;
|
||||
Vector3 wheelAxle = Vector3.Zero;
|
||||
|
||||
connectionPointCS0 = new Vector3(-CUBE_HALF_EXTENTS + (0.3f * wheelWidth), connectionHeight, 2 * CUBE_HALF_EXTENTS - wheelRadius);
|
||||
vehicle.AddWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius, tuning, isFrontWheel);
|
||||
wheelDirection[upIndex] = -1;
|
||||
wheelAxle[rightIndex] = -1;
|
||||
|
||||
bool isFrontWheel = true;
|
||||
var connectionPoint = new Vector3(CUBE_HALF_EXTENTS - (0.3f * wheelWidth), connectionHeight, 2 * CUBE_HALF_EXTENTS - wheelRadius);
|
||||
vehicle.AddWheel(connectionPoint, wheelDirection, wheelAxle, suspensionRestLength, wheelRadius, tuning, isFrontWheel);
|
||||
|
||||
connectionPoint = new Vector3(-CUBE_HALF_EXTENTS + (0.3f * wheelWidth), connectionHeight, 2 * CUBE_HALF_EXTENTS - wheelRadius);
|
||||
vehicle.AddWheel(connectionPoint, wheelDirection, wheelAxle, suspensionRestLength, wheelRadius, tuning, isFrontWheel);
|
||||
|
||||
isFrontWheel = false;
|
||||
connectionPointCS0 = new Vector3(-CUBE_HALF_EXTENTS + (0.3f * wheelWidth), connectionHeight, -2 * CUBE_HALF_EXTENTS + wheelRadius);
|
||||
vehicle.AddWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius, tuning, isFrontWheel);
|
||||
connectionPoint = new Vector3(-CUBE_HALF_EXTENTS + (0.3f * wheelWidth), connectionHeight, -2 * CUBE_HALF_EXTENTS + wheelRadius);
|
||||
vehicle.AddWheel(connectionPoint, wheelDirection, wheelAxle, suspensionRestLength, wheelRadius, tuning, isFrontWheel);
|
||||
|
||||
connectionPointCS0 = new Vector3(CUBE_HALF_EXTENTS - (0.3f * wheelWidth), connectionHeight, -2 * CUBE_HALF_EXTENTS + wheelRadius);
|
||||
vehicle.AddWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius, tuning, isFrontWheel);
|
||||
connectionPoint = new Vector3(CUBE_HALF_EXTENTS - (0.3f * wheelWidth), connectionHeight, -2 * CUBE_HALF_EXTENTS + wheelRadius);
|
||||
vehicle.AddWheel(connectionPoint, wheelDirection, wheelAxle, suspensionRestLength, wheelRadius, tuning, isFrontWheel);
|
||||
|
||||
|
||||
for (int i = 0; i < vehicle.NumWheels; i++)
|
||||
|
@ -328,79 +397,5 @@ namespace VehicleDemo
|
|||
|
||||
vehicle.RigidBody.WorldTransform = transform;
|
||||
}
|
||||
|
||||
public override void OnUpdate()
|
||||
{
|
||||
gEngineForce *= (1.0f - FrameDelta);
|
||||
|
||||
vehicle.ApplyEngineForce(gEngineForce, 2);
|
||||
vehicle.SetBrake(gBreakingForce, 2);
|
||||
vehicle.ApplyEngineForce(gEngineForce, 3);
|
||||
vehicle.SetBrake(gBreakingForce, 3);
|
||||
|
||||
vehicle.SetSteeringValue(gVehicleSteering, 0);
|
||||
vehicle.SetSteeringValue(gVehicleSteering, 1);
|
||||
|
||||
base.OnUpdate();
|
||||
}
|
||||
|
||||
public override void OnHandleInput()
|
||||
{
|
||||
if (Input.KeysDown.Contains(Keys.Left))
|
||||
{
|
||||
gVehicleSteering += FrameDelta * steeringIncrement;
|
||||
if (gVehicleSteering > steeringClamp)
|
||||
gVehicleSteering = steeringClamp;
|
||||
}
|
||||
else if ((gVehicleSteering - float.Epsilon) > 0)
|
||||
{
|
||||
gVehicleSteering -= FrameDelta * steeringIncrement;
|
||||
}
|
||||
|
||||
if (Input.KeysDown.Contains(Keys.Right))
|
||||
{
|
||||
gVehicleSteering -= FrameDelta * steeringIncrement;
|
||||
if (gVehicleSteering < -steeringClamp)
|
||||
gVehicleSteering = -steeringClamp;
|
||||
}
|
||||
else if ((gVehicleSteering + float.Epsilon) < 0)
|
||||
{
|
||||
gVehicleSteering += FrameDelta * steeringIncrement;
|
||||
}
|
||||
|
||||
if (Input.KeysDown.Contains(Keys.Up))
|
||||
{
|
||||
gEngineForce = maxEngineForce;
|
||||
}
|
||||
|
||||
if (Input.KeysDown.Contains(Keys.Down))
|
||||
{
|
||||
gEngineForce = -maxEngineForce;
|
||||
}
|
||||
|
||||
if (Input.KeysDown.Contains(Keys.Space))
|
||||
{
|
||||
gBreakingForce = maxBreakingForce;
|
||||
}
|
||||
|
||||
if (Input.KeysReleased.Contains(Keys.Space))
|
||||
{
|
||||
gBreakingForce = 0;
|
||||
}
|
||||
|
||||
base.OnHandleInput();
|
||||
}
|
||||
}
|
||||
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
using (Demo demo = new VehicleDemo())
|
||||
{
|
||||
GraphicsLibraryManager.Run(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,9 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="heightfield128x128.raw" />
|
||||
<Content Include="data\heightfield128x128.raw">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
|
|
@ -4,28 +4,13 @@
|
|||
#include "btBvhTriangleMeshShape_wrap.h"
|
||||
|
||||
btBvhTriangleMeshShape* btBvhTriangleMeshShape_new(btStridingMeshInterface* meshInterface,
|
||||
bool useQuantizedAabbCompression)
|
||||
{
|
||||
return new btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression);
|
||||
}
|
||||
|
||||
btBvhTriangleMeshShape* btBvhTriangleMeshShape_new2(btStridingMeshInterface* meshInterface,
|
||||
bool useQuantizedAabbCompression, bool buildBvh)
|
||||
{
|
||||
return new btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression,
|
||||
buildBvh);
|
||||
}
|
||||
|
||||
btBvhTriangleMeshShape* btBvhTriangleMeshShape_new3(btStridingMeshInterface* meshInterface,
|
||||
bool useQuantizedAabbCompression, const btVector3* bvhAabbMin, const btVector3* bvhAabbMax)
|
||||
{
|
||||
BTVECTOR3_IN(bvhAabbMin);
|
||||
BTVECTOR3_IN(bvhAabbMax);
|
||||
return new btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression,
|
||||
BTVECTOR3_USE(bvhAabbMin), BTVECTOR3_USE(bvhAabbMax));
|
||||
}
|
||||
|
||||
btBvhTriangleMeshShape* btBvhTriangleMeshShape_new4(btStridingMeshInterface* meshInterface,
|
||||
btBvhTriangleMeshShape* btBvhTriangleMeshShape_new2(btStridingMeshInterface* meshInterface,
|
||||
bool useQuantizedAabbCompression, const btVector3* bvhAabbMin, const btVector3* bvhAabbMax,
|
||||
bool buildBvh)
|
||||
{
|
||||
|
|
|
@ -3,10 +3,8 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
EXPORT btBvhTriangleMeshShape* btBvhTriangleMeshShape_new(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression);
|
||||
EXPORT btBvhTriangleMeshShape* btBvhTriangleMeshShape_new2(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh);
|
||||
EXPORT btBvhTriangleMeshShape* btBvhTriangleMeshShape_new3(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, const btVector3* bvhAabbMin, const btVector3* bvhAabbMax);
|
||||
EXPORT btBvhTriangleMeshShape* btBvhTriangleMeshShape_new4(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, const btVector3* bvhAabbMin, const btVector3* bvhAabbMax, bool buildBvh);
|
||||
EXPORT btBvhTriangleMeshShape* btBvhTriangleMeshShape_new(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh);
|
||||
EXPORT btBvhTriangleMeshShape* btBvhTriangleMeshShape_new2(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, const btVector3* bvhAabbMin, const btVector3* bvhAabbMax, bool buildBvh);
|
||||
EXPORT void btBvhTriangleMeshShape_buildOptimizedBvh(btBvhTriangleMeshShape* obj);
|
||||
EXPORT btOptimizedBvh* btBvhTriangleMeshShape_getOptimizedBvh(btBvhTriangleMeshShape* obj);
|
||||
EXPORT bool btBvhTriangleMeshShape_getOwnsBvh(btBvhTriangleMeshShape* obj);
|
||||
|
|
|
@ -151,6 +151,11 @@ btScalar btCollisionObject_getRollingFriction(btCollisionObject* obj)
|
|||
return obj->getRollingFriction();
|
||||
}
|
||||
|
||||
btScalar btCollisionObject_getSpinningFriction(btCollisionObject* obj)
|
||||
{
|
||||
return obj->getSpinningFriction();
|
||||
}
|
||||
|
||||
int btCollisionObject_getWorldArrayIndex(btCollisionObject * obj)
|
||||
{
|
||||
return obj->getWorldArrayIndex();
|
||||
|
@ -349,6 +354,11 @@ void btCollisionObject_setRollingFriction(btCollisionObject* obj, btScalar frict
|
|||
obj->setRollingFriction(frict);
|
||||
}
|
||||
|
||||
void btCollisionObject_setSpinningFriction(btCollisionObject* obj, btScalar frict)
|
||||
{
|
||||
obj->setSpinningFriction(frict);
|
||||
}
|
||||
|
||||
void btCollisionObject_setWorldArrayIndex(btCollisionObject * obj, int ix)
|
||||
{
|
||||
obj->setWorldArrayIndex(ix);
|
||||
|
|
|
@ -32,6 +32,7 @@ extern "C" {
|
|||
EXPORT int btCollisionObject_getIslandTag(btCollisionObject* obj);
|
||||
EXPORT btScalar btCollisionObject_getRestitution(btCollisionObject* obj);
|
||||
EXPORT btScalar btCollisionObject_getRollingFriction(btCollisionObject* obj);
|
||||
EXPORT btScalar btCollisionObject_getSpinningFriction(btCollisionObject* obj);
|
||||
EXPORT int btCollisionObject_getWorldArrayIndex(btCollisionObject* obj);
|
||||
EXPORT int btCollisionObject_getUserIndex(btCollisionObject* obj);
|
||||
EXPORT int btCollisionObject_getUserIndex2(btCollisionObject* obj);
|
||||
|
@ -70,6 +71,7 @@ extern "C" {
|
|||
EXPORT void btCollisionObject_setIslandTag(btCollisionObject* obj, int tag);
|
||||
EXPORT void btCollisionObject_setRestitution(btCollisionObject* obj, btScalar rest);
|
||||
EXPORT void btCollisionObject_setRollingFriction(btCollisionObject* obj, btScalar frict);
|
||||
EXPORT void btCollisionObject_setSpinningFriction(btCollisionObject* obj, btScalar frict);
|
||||
EXPORT void btCollisionObject_setWorldArrayIndex(btCollisionObject* obj, int ix);
|
||||
EXPORT void btCollisionObject_setUserIndex(btCollisionObject* obj, int index);
|
||||
EXPORT void btCollisionObject_setUserIndex2(btCollisionObject* obj, int index);
|
||||
|
|
Загрузка…
Ссылка в новой задаче