BulletSim: add parameter for terrain collision margin.

Add locking around unlikely but possible race conditions on terrain list.
connector_plugin^2
Robert Adams 2012-11-24 19:57:11 -08:00
parent 4ae30873ad
commit c3f30fef96
3 changed files with 46 additions and 55 deletions

View File

@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
{ {
m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
m_mapInfo.minCoords, m_mapInfo.maxCoords, m_mapInfo.minCoords, m_mapInfo.maxCoords,
m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin);
// Create the terrain shape from the mapInfo // Create the terrain shape from the mapInfo
m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),

View File

@ -80,8 +80,6 @@ public sealed class BSTerrainManager
// amount to make sure that a bounding box is built for the terrain. // amount to make sure that a bounding box is built for the terrain.
public const float HEIGHT_EQUAL_FUDGE = 0.2f; public const float HEIGHT_EQUAL_FUDGE = 0.2f;
public const float TERRAIN_COLLISION_MARGIN = 0.0f;
// Until the whole simulator is changed to pass us the region size, we rely on constants. // Until the whole simulator is changed to pass us the region size, we rely on constants.
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
@ -129,7 +127,8 @@ public sealed class BSTerrainManager
{ {
// 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 = new BulletShape( BulletShape groundPlaneShape = new BulletShape(
BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
PhysicsScene.Params.terrainCollisionMargin),
BSPhysicsShapeType.SHAPE_GROUNDPLANE); BSPhysicsShapeType.SHAPE_GROUNDPLANE);
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
@ -165,17 +164,22 @@ public sealed class BSTerrainManager
// Release all the terrain we have allocated // Release all the terrain we have allocated
public void ReleaseTerrain() public void ReleaseTerrain()
{ {
foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) lock (m_terrains)
{ {
kvp.Value.Dispose(); foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
{
kvp.Value.Dispose();
}
m_terrains.Clear();
} }
m_terrains.Clear();
} }
// The simulator wants to set a new heightmap for the terrain. // The simulator wants to set a new heightmap for the terrain.
public void SetTerrain(float[] heightMap) { public void SetTerrain(float[] heightMap) {
float[] localHeightMap = heightMap; float[] localHeightMap = heightMap;
PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() // If there are multiple requests for changes to the same terrain between ticks,
// only do that last one.
PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
{ {
if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
{ {
@ -211,6 +215,7 @@ public sealed class BSTerrainManager
// 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.)
// Called during taint-time.
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)
{ {
@ -220,7 +225,7 @@ public sealed class BSTerrainManager
// 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
// object height, for instance). The terrain wants the bounding box for the // object height, for instance). The terrain wants the bounding box for the
// terrain so we replace passed min and max Z with the actual terrain min/max Z. // terrain so replace passed min and max Z with the actual terrain min/max Z.
float minZ = float.MaxValue; float minZ = float.MaxValue;
float maxZ = float.MinValue; float maxZ = float.MinValue;
foreach (float height in heightMap) foreach (float height in heightMap)
@ -238,15 +243,15 @@ public sealed class BSTerrainManager
Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
BSTerrainPhys terrainPhys; lock (m_terrains)
if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
{ {
// There is already a terrain in this spot. Free the old and build the new. BSTerrainPhys terrainPhys;
DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
{ {
// 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}",
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
// Remove old terrain from the collection // Remove old terrain from the collection
m_terrains.Remove(terrainRegionBase); m_terrains.Remove(terrainRegionBase);
// Release any physical memory it may be using. // Release any physical memory it may be using.
@ -271,35 +276,24 @@ public sealed class BSTerrainManager
// I hate doing this, but just bail // I hate doing this, but just bail
return; return;
} }
}); }
} else
else
{
// We don't know about this terrain so either we are creating a new terrain or
// our mega-prim child is giving us a new terrain to add to the phys world
// if this is a child terrain, calculate a unique terrain id
uint newTerrainID = id;
if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
newTerrainID = ++m_terrainCount;
float[] heightMapX = heightMap;
Vector3 minCoordsX = minCoords;
Vector3 maxCoordsX = maxCoords;
DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
// Code that must happen at taint-time
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate()
{ {
DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", // We don't know about this terrain so either we are creating a new terrain or
BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y); // our mega-prim child is giving us a new terrain to add to the phys world
// if this is a child terrain, calculate a unique terrain id
uint newTerrainID = id;
if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
newTerrainID = ++m_terrainCount;
DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
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);
m_terrainModified = true; m_terrainModified = true;
}); }
} }
} }
@ -349,6 +343,7 @@ public sealed class BSTerrainManager
// with the same parameters as last time. // with the same parameters as last time.
if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
return lastHeight; return lastHeight;
m_terrainModified = false;
lastHeightTX = tX; lastHeightTX = tX;
lastHeightTY = tY; lastHeightTY = tY;
@ -358,19 +353,19 @@ public sealed class BSTerrainManager
int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
BSTerrainPhys physTerrain; lock (m_terrains)
if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
{ {
ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); BSTerrainPhys physTerrain;
DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); {
ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
}
else
{
PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
LogHeader, PhysicsScene.RegionName, tX, tY);
}
} }
else
{
PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
LogHeader, PhysicsScene.RegionName, tX, tY);
}
m_terrainModified = false;
lastHeight = ret; lastHeight = ret;
return ret; return ret;
} }

View File

@ -217,8 +217,6 @@ public sealed class BSTerrainMesh : BSTerrainPhys
} }
} }
verticesCount = verticesCount / 3; verticesCount = verticesCount / 3;
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
BSScene.DetailLogZero, verticesCount);
for (int yy = 0; yy < sizeY; yy++) for (int yy = 0; yy < sizeY; yy++)
{ {
@ -235,8 +233,6 @@ public sealed class BSTerrainMesh : BSTerrainPhys
indicesCount += 6; indicesCount += 6;
} }
} }
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG
LogHeader, indicesCount); // DEBUG
ret = true; ret = true;
} }
catch (Exception e) catch (Exception e)