BulletSim: add mesh representation. Use meshes for static objects and switch to hulls for physical objects.

bulletsim
Robert Adams 2011-08-26 15:51:21 -07:00 committed by Mic Bowman
parent 23f10f1d22
commit 21708b832b
7 changed files with 237 additions and 136 deletions

View File

@ -45,6 +45,7 @@ public sealed class BSPrim : PhysicsActor
private IMesh _mesh; private IMesh _mesh;
private PrimitiveBaseShape _pbs; private PrimitiveBaseShape _pbs;
private ShapeData.PhysicsShapeType _shapeType; private ShapeData.PhysicsShapeType _shapeType;
private ulong _meshKey;
private ulong _hullKey; private ulong _hullKey;
private List<ConvexResult> _hulls; private List<ConvexResult> _hulls;
@ -117,6 +118,7 @@ public sealed class BSPrim : PhysicsActor
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
_angularVelocity = OMV.Vector3.Zero; _angularVelocity = OMV.Vector3.Zero;
_hullKey = 0; _hullKey = 0;
_meshKey = 0;
_pbs = pbs; _pbs = pbs;
_isPhysical = pisPhysical; _isPhysical = pisPhysical;
_isVolumeDetect = false; _isVolumeDetect = false;
@ -147,6 +149,7 @@ public sealed class BSPrim : PhysicsActor
_scene.RemoveVehiclePrim(this); // just to make sure _scene.RemoveVehiclePrim(this); // just to make sure
_scene.TaintedObject(delegate() _scene.TaintedObject(delegate()
{ {
// everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
BulletSimAPI.DestroyObject(_scene.WorldID, _localID); BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
}); });
} }
@ -283,11 +286,6 @@ public sealed class BSPrim : PhysicsActor
set { _parentPrim = value; } set { _parentPrim = value; }
} }
public ulong HullKey
{
get { return _hullKey; }
}
// return true if we are the root of a linkset (there are children to manage) // return true if we are the root of a linkset (there are children to manage)
public bool IsRootOfLinkset public bool IsRootOfLinkset
{ {
@ -463,7 +461,18 @@ public sealed class BSPrim : PhysicsActor
private void SetObjectDynamic() private void SetObjectDynamic()
{ {
// non-physical things work best with a mass of zero // non-physical things work best with a mass of zero
_mass = IsStatic ? 0f : CalculateMass(); if (IsStatic)
{
_mass = 0f;
}
else
{
_mass = CalculateMass();
// If it's dynamic, make sure the hull has been created for it
// This shouldn't do much work if the object had previously been built
RecreateGeomAndObject();
}
BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass);
// m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}, mass={4}", LogHeader, _localID, IsStatic, IsSolid, _mass); // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}, mass={4}", LogHeader, _localID, IsStatic, IsSolid, _mass);
} }
@ -896,26 +905,19 @@ public sealed class BSPrim : PhysicsActor
#endregion Mass Calculation #endregion Mass Calculation
// Create the geometry information in Bullet for later use // Create the geometry information in Bullet for later use
// The objects needs a hull if it's physical otherwise a mesh is enough
// No locking here because this is done when we know physics is not simulating // No locking here because this is done when we know physics is not simulating
private void CreateGeom() // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
private void CreateGeom(bool forceRebuild)
{ {
// Since we're recreating new, get rid of any previously generated shape // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
if (_hullKey != 0) if (!_scene.NeedsMeshing(_pbs))
{ {
// m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
_hullKey = 0;
_hulls.Clear();
}
if (_mesh == null)
{
// the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
{ {
if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
{ {
// m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to sphere of size {1}", LogHeader, _size); // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
// Bullet native objects are scaled by the Bullet engine so pass the size in // Bullet native objects are scaled by the Bullet engine so pass the size in
_scale = _size; _scale = _size;
@ -923,99 +925,190 @@ public sealed class BSPrim : PhysicsActor
} }
else else
{ {
// m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
_scale = _size; _scale = _size;
} }
} }
else else
{ {
int[] indices = _mesh.getIndexListAsInt(); if (IsPhysical)
List<OMV.Vector3> vertices = _mesh.getVertexList();
//format conversion from IMesh format to DecompDesc format
List<int> convIndices = new List<int>();
List<float3> convVertices = new List<float3>();
for (int ii = 0; ii < indices.GetLength(0); ii++)
{ {
convIndices.Add(indices[ii]); if (forceRebuild || _hullKey == 0)
}
foreach (OMV.Vector3 vv in vertices)
{
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
}
// setup and do convex hull conversion
_hulls = new List<ConvexResult>();
DecompDesc dcomp = new DecompDesc();
dcomp.mIndices = convIndices;
dcomp.mVertices = convVertices;
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
// create the hull into the _hulls variable
convexBuilder.process(dcomp);
// Convert the vertices and indices for passing to unmanaged
// The hull information is passed as a large floating point array.
// The format is:
// convHulls[0] = number of hulls
// convHulls[1] = number of vertices in first hull
// convHulls[2] = hull centroid X coordinate
// convHulls[3] = hull centroid Y coordinate
// convHulls[4] = hull centroid Z coordinate
// convHulls[5] = first hull vertex X
// convHulls[6] = first hull vertex Y
// convHulls[7] = first hull vertex Z
// convHulls[8] = second hull vertex X
// ...
// convHulls[n] = number of vertices in second hull
// convHulls[n+1] = second hull centroid X coordinate
// ...
//
// TODO: is is very inefficient. Someday change the convex hull generator to return
// data structures that do not need to be converted in order to pass to Bullet.
// And maybe put the values directly into pinned memory rather than marshaling.
int hullCount = _hulls.Count;
int totalVertices = 1; // include one for the count of the hulls
foreach (ConvexResult cr in _hulls)
{
totalVertices += 4; // add four for the vertex count and centroid
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
}
float[] convHulls = new float[totalVertices];
convHulls[0] = (float)hullCount;
int jj = 1;
foreach (ConvexResult cr in _hulls)
{
// copy vertices for index access
float3[] verts = new float3[cr.HullVertices.Count];
int kk = 0;
foreach (float3 ff in cr.HullVertices)
{ {
verts[kk++] = ff; // physical objects require a hull for interaction.
} // This will create the mesh if it doesn't already exist
CreateGeomHull();
// add to the array one hull's worth of data }
convHulls[jj++] = cr.HullIndices.Count; }
convHulls[jj++] = 0f; // centroid x,y,z else
convHulls[jj++] = 0f; {
convHulls[jj++] = 0f; if (forceRebuild || _meshKey == 0)
foreach (int ind in cr.HullIndices) {
{ // Static (non-physical) objects only need a mesh for bumping into
convHulls[jj++] = verts[ind].x; CreateGeomMesh();
convHulls[jj++] = verts[ind].y;
convHulls[jj++] = verts[ind].z;
} }
} }
// create the hull definition in Bullet
_hullKey = (ulong)_pbs.GetHashCode();
// m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
// meshes are already scaled by the meshmerizer
_scale = new OMV.Vector3(1f, 1f, 1f);
} }
}
// No locking here because this is done when we know physics is not simulating
private void CreateGeomMesh()
{
ulong newMeshKey = (ulong)_pbs.GetHashCode();
// if this new shape is the same as last time, don't recreate the mesh
if (_meshKey == newMeshKey) return;
// Since we're recreating new, get rid of any previously generated shape
if (_meshKey != 0)
{
// m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _meshKey);
BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
_mesh = null;
_meshKey = 0;
}
_meshKey = newMeshKey;
int lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
// always pass false for physicalness as this creates some sort of bounding box which we don't need
_mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false);
int[] indices = _mesh.getIndexListAsInt();
List<OMV.Vector3> vertices = _mesh.getVertexList();
float[] verticesAsFloats = new float[vertices.Count * 3];
int vi = 0;
foreach (OMV.Vector3 vv in vertices)
{
// m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z);
verticesAsFloats[vi++] = vv.X;
verticesAsFloats[vi++] = vv.Y;
verticesAsFloats[vi++] = vv.Z;
}
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
// LogHeader, _localID, _meshKey, indices.Length, vertices.Count);
BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices,
vertices.Count, verticesAsFloats);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
// meshes are already scaled by the meshmerizer
_scale = new OMV.Vector3(1f, 1f, 1f);
return;
}
// No locking here because this is done when we know physics is not simulating
private void CreateGeomHull()
{
ulong newHullKey = (ulong)_pbs.GetHashCode();
// if the hull hasn't changed, don't rebuild it
if (newHullKey == _hullKey) return;
// Since we're recreating new, get rid of any previously generated shape
if (_hullKey != 0)
{
// m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
_hullKey = 0;
_hulls.Clear();
BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
_mesh = null; // the mesh cannot match either
_meshKey = 0;
}
_hullKey = newHullKey;
if (_meshKey != _hullKey)
{
// if the underlying mesh has changed, rebuild it
CreateGeomMesh();
}
int[] indices = _mesh.getIndexListAsInt();
List<OMV.Vector3> vertices = _mesh.getVertexList();
//format conversion from IMesh format to DecompDesc format
List<int> convIndices = new List<int>();
List<float3> convVertices = new List<float3>();
for (int ii = 0; ii < indices.GetLength(0); ii++)
{
convIndices.Add(indices[ii]);
}
foreach (OMV.Vector3 vv in vertices)
{
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
}
// setup and do convex hull conversion
_hulls = new List<ConvexResult>();
DecompDesc dcomp = new DecompDesc();
dcomp.mIndices = convIndices;
dcomp.mVertices = convVertices;
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
// create the hull into the _hulls variable
convexBuilder.process(dcomp);
// Convert the vertices and indices for passing to unmanaged
// The hull information is passed as a large floating point array.
// The format is:
// convHulls[0] = number of hulls
// convHulls[1] = number of vertices in first hull
// convHulls[2] = hull centroid X coordinate
// convHulls[3] = hull centroid Y coordinate
// convHulls[4] = hull centroid Z coordinate
// convHulls[5] = first hull vertex X
// convHulls[6] = first hull vertex Y
// convHulls[7] = first hull vertex Z
// convHulls[8] = second hull vertex X
// ...
// convHulls[n] = number of vertices in second hull
// convHulls[n+1] = second hull centroid X coordinate
// ...
//
// TODO: is is very inefficient. Someday change the convex hull generator to return
// data structures that do not need to be converted in order to pass to Bullet.
// And maybe put the values directly into pinned memory rather than marshaling.
int hullCount = _hulls.Count;
int totalVertices = 1; // include one for the count of the hulls
foreach (ConvexResult cr in _hulls)
{
totalVertices += 4; // add four for the vertex count and centroid
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
}
float[] convHulls = new float[totalVertices];
convHulls[0] = (float)hullCount;
int jj = 1;
foreach (ConvexResult cr in _hulls)
{
// copy vertices for index access
float3[] verts = new float3[cr.HullVertices.Count];
int kk = 0;
foreach (float3 ff in cr.HullVertices)
{
verts[kk++] = ff;
}
// add to the array one hull's worth of data
convHulls[jj++] = cr.HullIndices.Count;
convHulls[jj++] = 0f; // centroid x,y,z
convHulls[jj++] = 0f;
convHulls[jj++] = 0f;
foreach (int ind in cr.HullIndices)
{
convHulls[jj++] = verts[ind].x;
convHulls[jj++] = verts[ind].y;
convHulls[jj++] = verts[ind].z;
}
}
// create the hull definition in Bullet
// m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
// meshes are already scaled by the meshmerizer
_scale = new OMV.Vector3(1f, 1f, 1f);
return; return;
} }
@ -1040,6 +1133,7 @@ public sealed class BSPrim : PhysicsActor
else else
{ {
// simple object // simple object
// the mesh or hull must have already been created in Bullet
ShapeData shape; ShapeData shape;
FillShapeInfo(out shape); FillShapeInfo(out shape);
BulletSimAPI.CreateObject(_scene.WorldID, shape); BulletSimAPI.CreateObject(_scene.WorldID, shape);
@ -1081,7 +1175,8 @@ public sealed class BSPrim : PhysicsActor
shape.Scale = _scale; shape.Scale = _scale;
shape.Mass = _isPhysical ? _mass : 0f; shape.Mass = _isPhysical ? _mass : 0f;
shape.Buoyancy = _buoyancy; shape.Buoyancy = _buoyancy;
shape.MeshKey = _hullKey; shape.HullKey = _hullKey;
shape.MeshKey = _meshKey;
shape.Friction = _friction; shape.Friction = _friction;
shape.Restitution = _restitution; shape.Restitution = _restitution;
shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
@ -1098,13 +1193,13 @@ public sealed class BSPrim : PhysicsActor
// remove any constraints that might be in place // remove any constraints that might be in place
foreach (BSPrim prim in _childrenPrims) foreach (BSPrim prim in _childrenPrims)
{ {
// m_log.DebugFormat("{0}: CreateObject: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID); BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
} }
// create constraints between the root prim and each of the children // create constraints between the root prim and each of the children
foreach (BSPrim prim in _childrenPrims) foreach (BSPrim prim in _childrenPrims)
{ {
// m_log.DebugFormat("{0}: CreateObject: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
// Zero motion for children so they don't interpolate // Zero motion for children so they don't interpolate
prim.ZeroMotion(); prim.ZeroMotion();
@ -1132,20 +1227,7 @@ public sealed class BSPrim : PhysicsActor
// No locking here because this is done when the physics engine is not simulating // No locking here because this is done when the physics engine is not simulating
private void RecreateGeomAndObject() private void RecreateGeomAndObject()
{ {
// If this object is complex or we are the root of a linkset, build a mesh. CreateGeom(true);
// The root of a linkset must be a mesh so we can create the linked compound object.
// if (_scene.NeedsMeshing(_pbs) || IsRootOfLinkset )
if (_scene.NeedsMeshing(_pbs)) // linksets with constraints don't need a root mesh
{
// m_log.DebugFormat("{0}: RecreateGeomAndObject: creating mesh", LogHeader);
_mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, _scene.MeshLOD, _isPhysical);
}
else
{
// implement the shape with a Bullet native shape.
_mesh = null;
}
CreateGeom();
CreateObject(); CreateObject();
return; return;
} }

View File

@ -37,7 +37,6 @@ using OpenMetaverse;
using OpenSim.Region.Framework; using OpenSim.Region.Framework;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
// Parameterize BulletSim. Pass a structure of parameters to the C++ code. Capsule size, friction, ...
// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) // Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
// Test sculpties // Test sculpties
// Compute physics FPS reasonably // Compute physics FPS reasonably
@ -52,8 +51,6 @@ using OpenSim.Region.Framework;
// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) // Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
// Implement LockAngularMotion // Implement LockAngularMotion
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
// Built Galton board (lots of MoveTo's) and some slats were not positioned correctly (mistakes scattered)
// No mistakes with ODE. Shape creation race condition?
// Does NeedsMeshing() really need to exclude all the different shapes? // Does NeedsMeshing() really need to exclude all the different shapes?
// //
namespace OpenSim.Region.Physics.BulletSPlugin namespace OpenSim.Region.Physics.BulletSPlugin
@ -81,6 +78,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{ {
get { return m_meshLOD; } get { return m_meshLOD; }
} }
private int m_sculptLOD;
public int SculptLOD
{
get { return m_sculptLOD; }
}
private int m_maxSubSteps; private int m_maxSubSteps;
private float m_fixedTimeStep; private float m_fixedTimeStep;
@ -187,7 +189,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
_meshSculptedPrim = true; // mesh sculpted prims _meshSculptedPrim = true; // mesh sculpted prims
_forceSimplePrimMeshing = false; // use complex meshing if called for _forceSimplePrimMeshing = false; // use complex meshing if called for
m_meshLOD = 32; m_meshLOD = 8;
m_sculptLOD = 32;
m_maxSubSteps = 10; m_maxSubSteps = 10;
m_fixedTimeStep = 1f / 60f; m_fixedTimeStep = 1f / 60f;
@ -229,6 +232,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
_forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing);
m_meshLOD = pConfig.GetInt("MeshLevelOfDetail", m_meshLOD); m_meshLOD = pConfig.GetInt("MeshLevelOfDetail", m_meshLOD);
m_sculptLOD = pConfig.GetInt("SculptLevelOfDetail", m_sculptLOD);
m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps); m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps);
m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep); m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep);
@ -489,10 +493,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// can use an internal representation for the prim // can use an internal representation for the prim
if (!_forceSimplePrimMeshing) if (!_forceSimplePrimMeshing)
{ {
// m_log.DebugFormat("{0}: NeedsMeshing: simple mesh: profshape={1}, curve={2}", LogHeader, pbs.ProfileShape, pbs.PathCurve);
if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
|| (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
&& pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
{ {
if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
@ -663,7 +666,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
#region Runtime settable parameters #region Runtime settable parameters
public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[] public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[]
{ {
new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (Power of two. Default 32)"), new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)"),
new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"),
new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"), new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"),
new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"), new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"),
new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"), new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"),
@ -712,6 +716,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
switch (lparm) switch (lparm)
{ {
case "meshlod": m_meshLOD = (int)val; break; case "meshlod": m_meshLOD = (int)val; break;
case "sculptlod": m_sculptLOD = (int)val; break;
case "maxsubstep": m_maxSubSteps = (int)val; break; case "maxsubstep": m_maxSubSteps = (int)val; break;
case "fixedtimestep": m_fixedTimeStep = val; break; case "fixedtimestep": m_fixedTimeStep = val; break;
case "maxobjectmass": m_maximumObjectMass = val; break; case "maxobjectmass": m_maximumObjectMass = val; break;
@ -812,6 +817,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
switch (parm.ToLower()) switch (parm.ToLower())
{ {
case "meshlod": val = (float)m_meshLOD; break; case "meshlod": val = (float)m_meshLOD; break;
case "sculptlod": val = (float)m_sculptLOD; break;
case "maxsubstep": val = (float)m_maxSubSteps; break; case "maxsubstep": val = (float)m_maxSubSteps; break;
case "fixedtimestep": val = m_fixedTimeStep; break; case "fixedtimestep": val = m_fixedTimeStep; break;
case "maxobjectmass": val = m_maximumObjectMass; break; case "maxobjectmass": val = m_maximumObjectMass; break;

View File

@ -49,7 +49,8 @@ public struct ShapeData
SHAPE_CONE = 2, SHAPE_CONE = 2,
SHAPE_CYLINDER = 3, SHAPE_CYLINDER = 3,
SHAPE_SPHERE = 4, SHAPE_SPHERE = 4,
SHAPE_HULL = 5 SHAPE_MESH = 5,
SHAPE_HULL = 6
}; };
public uint ID; public uint ID;
public PhysicsShapeType Type; public PhysicsShapeType Type;
@ -59,6 +60,7 @@ public struct ShapeData
public Vector3 Scale; public Vector3 Scale;
public float Mass; public float Mass;
public float Buoyancy; public float Buoyancy;
public System.UInt64 HullKey;
public System.UInt64 MeshKey; public System.UInt64 MeshKey;
public float Friction; public float Friction;
public float Restitution; public float Restitution;
@ -158,19 +160,28 @@ public static extern void Shutdown(uint worldID);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
out int updatedEntityCount, out int updatedEntityCount,
out IntPtr updatedEntitiesPtr, out IntPtr updatedEntitiesPtr,
out int collidersCount, out int collidersCount,
out IntPtr collidersPtr); out IntPtr collidersPtr);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, int hullCount, public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
[MarshalAs(UnmanagedType.LPArray)] float[] hulls int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
); );
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey); public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CreateObject(uint worldID, ShapeData shapeData); public static extern bool CreateObject(uint worldID, ShapeData shapeData);
@ -179,9 +190,9 @@ public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void AddConstraint(uint worldID, uint id1, uint id2, public static extern void AddConstraint(uint worldID, uint id1, uint id2,
Vector3 frame1, Quaternion frame1rot, Vector3 frame1, Quaternion frame1rot,
Vector3 frame2, Quaternion frame2rot, Vector3 frame2, Quaternion frame2rot,
Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular); Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool RemoveConstraintByID(uint worldID, uint id1); public static extern bool RemoveConstraintByID(uint worldID, uint id1);

Binary file not shown.

Binary file not shown.

View File

@ -766,8 +766,10 @@
; If 'true', force simple prims (box and sphere) to be meshed ; If 'true', force simple prims (box and sphere) to be meshed
ForceSimplePrimMeshing = false ForceSimplePrimMeshing = false
; level of detail for physical meshes. 32,16,8 or 4 with 32 being full detail
MeshLevelOfDetail = 8
; number^2 non-physical level of detail of the sculpt texture. 32x32 - 1024 verticies ; number^2 non-physical level of detail of the sculpt texture. 32x32 - 1024 verticies
MeshLevelOfDetail = 32 SculptLevelOfDetail = 32
; Bullet step parameters ; Bullet step parameters
MaxSubSteps = 10; MaxSubSteps = 10;

Binary file not shown.