mirror of
https://github.com/opensim/opensim.git
synced 2026-08-11 11:57:03 +08:00
BulletSim: add asset fetching so BulletSim works with new physics asset handling.
Refactor some names to make them available for the asset tracking and fetching.
This commit is contained in:
@@ -117,7 +117,7 @@ public class BSShapeCollection : IDisposable
|
||||
|
||||
// Track another user of a body
|
||||
// We presume the caller has allocated the body.
|
||||
// Bodies only have one user so the reference count is either 1 or 0.
|
||||
// Bodies only have one user so the body is just put into the world if not already there.
|
||||
public void ReferenceBody(BulletBody body, bool inTaintTime)
|
||||
{
|
||||
lock (m_collectionActivityLock)
|
||||
@@ -241,26 +241,32 @@ public class BSShapeCollection : IDisposable
|
||||
|
||||
BSScene.TaintCallback dereferenceOperation = delegate()
|
||||
{
|
||||
switch (shape.type)
|
||||
if (shape.ptr != IntPtr.Zero)
|
||||
{
|
||||
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
||||
DereferenceHull(shape, shapeCallback);
|
||||
break;
|
||||
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||
DereferenceMesh(shape, shapeCallback);
|
||||
break;
|
||||
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
||||
break;
|
||||
default:
|
||||
if (shape.isNativeShape)
|
||||
{
|
||||
// Native shapes are not tracked and are released immediately
|
||||
if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
|
||||
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
||||
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
|
||||
if (shapeCallback != null) shapeCallback(shape);
|
||||
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (shape.type)
|
||||
{
|
||||
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
||||
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
|
||||
if (shapeCallback != null) shapeCallback(shape);
|
||||
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
||||
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
||||
DereferenceHull(shape, shapeCallback);
|
||||
break;
|
||||
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||
DereferenceMesh(shape, shapeCallback);
|
||||
break;
|
||||
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (inTaintTime)
|
||||
@@ -405,7 +411,6 @@ public class BSShapeCollection : IDisposable
|
||||
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
|
||||
ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
BulletShape newShape;
|
||||
|
||||
shapeData.Type = shapeType;
|
||||
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
||||
@@ -415,20 +420,7 @@ public class BSShapeCollection : IDisposable
|
||||
// release any previous shape
|
||||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||
|
||||
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
||||
{
|
||||
newShape = new BulletShape(
|
||||
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale),
|
||||
shapeType);
|
||||
newShape.shapeKey = (System.UInt64)shapeKey;
|
||||
newShape.isNativeShape = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
|
||||
newShape.shapeKey = (System.UInt64)shapeKey;
|
||||
newShape.isNativeShape = true;
|
||||
}
|
||||
BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
|
||||
|
||||
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
|
||||
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
|
||||
@@ -438,6 +430,27 @@ public class BSShapeCollection : IDisposable
|
||||
return true;
|
||||
}
|
||||
|
||||
private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
|
||||
ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
|
||||
{
|
||||
BulletShape newShape;
|
||||
|
||||
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
||||
{
|
||||
newShape = new BulletShape(
|
||||
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale),
|
||||
shapeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
|
||||
}
|
||||
newShape.shapeKey = (System.UInt64)shapeKey;
|
||||
newShape.isNativeShape = true;
|
||||
|
||||
return newShape;
|
||||
}
|
||||
|
||||
// Builds a mesh shape in the physical world and updates prim.BSShape.
|
||||
// Dereferences previous shape in BSShape and adds a reference for this new shape.
|
||||
// Returns 'true' of a mesh was actually built. Otherwise .
|
||||
@@ -461,6 +474,8 @@ public class BSShapeCollection : IDisposable
|
||||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||
|
||||
newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
|
||||
// Take evasive action if the mesh was not constructed.
|
||||
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
|
||||
|
||||
ReferenceShape(newShape);
|
||||
|
||||
@@ -474,7 +489,7 @@ public class BSShapeCollection : IDisposable
|
||||
private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||
{
|
||||
IMesh meshData = null;
|
||||
IntPtr meshPtr;
|
||||
IntPtr meshPtr = IntPtr.Zero;
|
||||
MeshDesc meshDesc;
|
||||
if (Meshes.TryGetValue(newMeshKey, out meshDesc))
|
||||
{
|
||||
@@ -486,23 +501,26 @@ public class BSShapeCollection : IDisposable
|
||||
// Pass false for physicalness as this creates some sort of bounding box which we don't need
|
||||
meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
|
||||
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||
|
||||
float[] verticesAsFloats = new float[vertices.Count * 3];
|
||||
int vi = 0;
|
||||
foreach (OMV.Vector3 vv in vertices)
|
||||
if (meshData != null)
|
||||
{
|
||||
verticesAsFloats[vi++] = vv.X;
|
||||
verticesAsFloats[vi++] = vv.Y;
|
||||
verticesAsFloats[vi++] = vv.Z;
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||
|
||||
float[] verticesAsFloats = new float[vertices.Count * 3];
|
||||
int vi = 0;
|
||||
foreach (OMV.Vector3 vv in vertices)
|
||||
{
|
||||
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, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
|
||||
|
||||
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
||||
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
|
||||
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
|
||||
|
||||
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
||||
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
||||
}
|
||||
BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
|
||||
newShape.shapeKey = newMeshKey;
|
||||
@@ -531,6 +549,7 @@ public class BSShapeCollection : IDisposable
|
||||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||
|
||||
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
|
||||
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
|
||||
|
||||
ReferenceShape(newShape);
|
||||
|
||||
@@ -544,7 +563,7 @@ public class BSShapeCollection : IDisposable
|
||||
private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||
{
|
||||
|
||||
IntPtr hullPtr;
|
||||
IntPtr hullPtr = IntPtr.Zero;
|
||||
HullDesc hullDesc;
|
||||
if (Hulls.TryGetValue(newHullKey, out hullDesc))
|
||||
{
|
||||
@@ -556,86 +575,89 @@ public class BSShapeCollection : IDisposable
|
||||
// Build a new hull in the physical world
|
||||
// Pass false for physicalness as this creates some sort of bounding box which we don't need
|
||||
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
|
||||
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.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++)
|
||||
if (meshData != null)
|
||||
{
|
||||
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
|
||||
m_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);
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||
|
||||
// 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 = m_hulls.Count;
|
||||
int totalVertices = 1; // include one for the count of the hulls
|
||||
foreach (ConvexResult cr in m_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 m_hulls)
|
||||
{
|
||||
// copy vertices for index access
|
||||
float3[] verts = new float3[cr.HullVertices.Count];
|
||||
int kk = 0;
|
||||
foreach (float3 ff in cr.HullVertices)
|
||||
//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++)
|
||||
{
|
||||
verts[kk++] = ff;
|
||||
convIndices.Add(indices[ii]);
|
||||
}
|
||||
foreach (OMV.Vector3 vv in vertices)
|
||||
{
|
||||
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
|
||||
}
|
||||
|
||||
// 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)
|
||||
// setup and do convex hull conversion
|
||||
m_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 = m_hulls.Count;
|
||||
int totalVertices = 1; // include one for the count of the hulls
|
||||
foreach (ConvexResult cr in m_hulls)
|
||||
{
|
||||
convHulls[jj++] = verts[ind].x;
|
||||
convHulls[jj++] = verts[ind].y;
|
||||
convHulls[jj++] = verts[ind].z;
|
||||
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 m_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 data structure in Bullet
|
||||
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
|
||||
}
|
||||
// create the hull data structure in Bullet
|
||||
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
|
||||
}
|
||||
|
||||
BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
|
||||
@@ -676,6 +698,50 @@ public class BSShapeCollection : IDisposable
|
||||
return ComputeShapeKey(shapeData, pbs, out lod);
|
||||
}
|
||||
|
||||
private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
|
||||
{
|
||||
// If the shape was successfully created, nothing more to do
|
||||
if (newShape.ptr != IntPtr.Zero)
|
||||
return newShape;
|
||||
|
||||
// The most common reason for failure is that an underlying asset is not available
|
||||
|
||||
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
|
||||
if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
|
||||
{
|
||||
prim.LastAssetBuildFailed = true;
|
||||
BSPhysObject xprim = prim;
|
||||
Util.FireAndForget(delegate
|
||||
{
|
||||
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
|
||||
if (assetProvider != null)
|
||||
{
|
||||
BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
|
||||
assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
|
||||
{
|
||||
if (!yprim.BaseShape.SculptEntry)
|
||||
return;
|
||||
if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
|
||||
return;
|
||||
|
||||
yprim.BaseShape.SculptData = new byte[asset.Data.Length];
|
||||
asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
|
||||
// This will cause the prim to see that the filler shape is not the right
|
||||
// one and try again to build the object.
|
||||
yprim.ForceBodyShapeRebuild(false);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// While we figure out the real problem, stick a simple native shape on the object.
|
||||
BulletShape fillinShape =
|
||||
BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE);
|
||||
|
||||
return fillinShape;
|
||||
}
|
||||
|
||||
// Create a body object in Bullet.
|
||||
// Updates prim.BSBody with the information about the new body if one is created.
|
||||
// Returns 'true' if an object was actually created.
|
||||
|
||||
Reference in New Issue
Block a user