Decouple graphics and input from simulations. Cleanup.

This commit is contained in:
AndresTraks 2017-01-04 22:13:57 +02:00
Родитель 7d3fcd57ff
Коммит 8e5164df0e
69 изменённых файлов: 4626 добавлений и 4473 удалений

3
.gitignore поставляемый Normal file
Просмотреть файл

@ -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);