BulletSim: fix race condition when creating very large mega-regions.

The symptom was exceptions while creating physical terrain.
Reduce default terrain mesh magnification to 2 from 3 because the
higher resolution uses a lot of memory and doesn't solve the terrain
smoothness for vehicles.
Added comments here and there and improved some debugging log messages.
user_profiles
Robert Adams 2013-03-28 10:56:21 -07:00
parent 3f9b274180
commit 6a9630d2bd
5 changed files with 35 additions and 22 deletions

View File

@ -479,7 +479,7 @@ public sealed class BSCharacter : BSPhysObject
// The character is out of the known/simulated area. // The character is out of the known/simulated area.
// Force the avatar position to be within known. ScenePresence will use the position // Force the avatar position to be within known. ScenePresence will use the position
// plus the velocity to decide if the avatar is moving out of the region. // plus the velocity to decide if the avatar is moving out of the region.
RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
return true; return true;
} }
@ -898,7 +898,7 @@ public sealed class BSCharacter : BSPhysObject
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds. // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
if (PositionSanityCheck(true)) if (PositionSanityCheck(true))
{ {
DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position);
entprop.Position = _position; entprop.Position = _position;
} }

View File

@ -180,11 +180,14 @@ public static class BSMaterials
// Use reflection to set the value in the attribute structure. // Use reflection to set the value in the attribute structure.
private static void SetAttributeValue(int matType, string attribName, float val) private static void SetAttributeValue(int matType, string attribName, float val)
{ {
// Get the current attribute values for this material
MaterialAttributes thisAttrib = Attributes[matType]; MaterialAttributes thisAttrib = Attributes[matType];
// Find the field for the passed attribute name (eg, find field named 'friction')
FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
if (fieldInfo != null) if (fieldInfo != null)
{ {
fieldInfo.SetValue(thisAttrib, val); fieldInfo.SetValue(thisAttrib, val);
// Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
Attributes[matType] = thisAttrib; Attributes[matType] = thisAttrib;
} }
} }

View File

@ -482,7 +482,7 @@ public static class BSParam
(s) => { return TerrainImplementation; }, (s) => { return TerrainImplementation; },
(s,v) => { TerrainImplementation = v; } ), (s,v) => { TerrainImplementation = v; } ),
new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
3, 2,
(s) => { return TerrainMeshMagnification; }, (s) => { return TerrainMeshMagnification; },
(s,v) => { TerrainMeshMagnification = v; } ), (s,v) => { TerrainMeshMagnification = v; } ),
new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,

View File

@ -132,6 +132,7 @@ public sealed class BSTerrainManager : IDisposable
// safe to call Bullet in real time. We hope no one is moving prims around yet. // safe to call Bullet in real time. We hope no one is moving prims around yet.
public void CreateInitialGroundPlaneAndTerrain() public void CreateInitialGroundPlaneAndTerrain()
{ {
DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
// The ground plane is here to catch things that are trying to drop to negative infinity // The ground plane is here to catch things that are trying to drop to negative infinity
BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
@ -145,14 +146,18 @@ public sealed class BSTerrainManager : IDisposable
m_groundPlane.collisionType = CollisionType.Groundplane; m_groundPlane.collisionType = CollisionType.Groundplane;
m_groundPlane.ApplyCollisionMask(PhysicsScene); m_groundPlane.ApplyCollisionMask(PhysicsScene);
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
m_terrains.Add(Vector3.Zero, initialTerrain); lock (m_terrains)
{
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
m_terrains.Add(Vector3.Zero, initialTerrain);
}
} }
// Release all the terrain structures we might have allocated // Release all the terrain structures we might have allocated
public void ReleaseGroundPlaneAndTerrain() public void ReleaseGroundPlaneAndTerrain()
{ {
DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
if (m_groundPlane.HasPhysicalBody) if (m_groundPlane.HasPhysicalBody)
{ {
if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
@ -193,11 +198,16 @@ public sealed class BSTerrainManager : IDisposable
// the terrain is added to our parent // the terrain is added to our parent
if (MegaRegionParentPhysicsScene is BSScene) if (MegaRegionParentPhysicsScene is BSScene)
{ {
DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
BSScene.DetailLogZero, m_worldOffset, m_worldMax); // This looks really odd but this region is passing its terrain to its mega-region root region
((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( // and the creation of the terrain must happen on the root region's taint thread and not
BSScene.CHILDTERRAIN_ID, localHeightMap, // my taint thread.
m_worldOffset, m_worldOffset + DefaultRegionSize, true); ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate()
{
((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
BSScene.CHILDTERRAIN_ID, localHeightMap,
m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
});
} }
} }
else else
@ -206,16 +216,16 @@ public sealed class BSTerrainManager : IDisposable
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
m_worldOffset, m_worldOffset + DefaultRegionSize, true); m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
} }
}); });
} }
// If called with no mapInfo for the terrain, this will create a new mapInfo and terrain // If called for terrain has has not been previously allocated, a new terrain will be built
// based on the passed information. The 'id' should be either the terrain id or // based on the passed information. The 'id' should be either the terrain id or
// BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
// The latter feature is for creating child terrains for mega-regions. // The latter feature is for creating child terrains for mega-regions.
// If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new // If there is an existing terrain body, a new
// terrain shape is created and added to the body. // terrain shape is created and added to the body.
// This call is most often used to update the heightMap and parameters of the terrain. // This call is most often used to update the heightMap and parameters of the terrain.
// (The above does suggest that some simplification/refactoring is in order.) // (The above does suggest that some simplification/refactoring is in order.)
@ -223,8 +233,8 @@ public sealed class BSTerrainManager : IDisposable
private void UpdateTerrain(uint id, float[] heightMap, private void UpdateTerrain(uint id, float[] heightMap,
Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
{ {
DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}",
BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime);
// Find high and low points of passed heightmap. // Find high and low points of passed heightmap.
// The min and max passed in is usually the area objects can be in (maximum // The min and max passed in is usually the area objects can be in (maximum
@ -253,7 +263,7 @@ public sealed class BSTerrainManager : IDisposable
if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
{ {
// There is already a terrain in this spot. Free the old and build the new. // There is already a terrain in this spot. Free the old and build the new.
DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
// Remove old terrain from the collection // Remove old terrain from the collection
@ -292,7 +302,7 @@ public sealed class BSTerrainManager : IDisposable
if (newTerrainID >= BSScene.CHILDTERRAIN_ID) if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
newTerrainID = ++m_terrainCount; newTerrainID = ++m_terrainCount;
DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
m_terrains.Add(terrainRegionBase, newTerrainPhys); m_terrains.Add(terrainRegionBase, newTerrainPhys);

View File

@ -98,20 +98,20 @@ public sealed class BSTerrainMesh : BSTerrainPhys
if (!meshCreationSuccess) if (!meshCreationSuccess)
{ {
// DISASTER!! // DISASTER!!
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
// Something is very messed up and a crash is in our future. // Something is very messed up and a crash is in our future.
return; return;
} }
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
ID, indicesCount, indices.Length, verticesCount, vertices.Length); BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
if (!m_terrainShape.HasPhysicalShape) if (!m_terrainShape.HasPhysicalShape)
{ {
// DISASTER!! // DISASTER!!
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
// Something is very messed up and a crash is in our future. // Something is very messed up and a crash is in our future.
return; return;
@ -151,7 +151,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
if (BSParam.UseSingleSidedMeshes) if (BSParam.UseSingleSidedMeshes)
{ {
PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial", id); PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
} }