From 3bf7201fd4d3e2b240f8139c20f88c916d338c31 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 9 Oct 2012 00:18:39 +0100 Subject: [PATCH] move terrain geom to own ode space. Limit range on raycast if includes terrain until ode doesn't eat all stack. Add a pre-simulation method to do pending actors changes (except mesh assets still not ready to use), to be optionaly called before firing heartbeat. [UNTESTED] --- .../Region/Physics/Manager/PhysicsScene.cs | 3 + .../Region/Physics/UbitOdePlugin/ODEPrim.cs | 140 +++++++++------ .../UbitOdePlugin/ODERayCastRequestManager.cs | 16 +- .../Region/Physics/UbitOdePlugin/OdeScene.cs | 165 ++++++++++++++---- 4 files changed, 235 insertions(+), 89 deletions(-) diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index 46bfa59271..ce269fabc1 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -246,6 +246,9 @@ namespace OpenSim.Region.Physics.Manager public abstract void AddPhysicsActorTaint(PhysicsActor prim); + + public virtual void PrepareSimulation() { } + /// /// Perform a simulation of the current physics scene over the given timestep. /// diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs index c2c4384efb..535a4e2fb0 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs @@ -1325,12 +1325,48 @@ namespace OpenSim.Region.Physics.OdePlugin } } + + private void SetGeom(IntPtr geom) + { + prim_geom = geom; + //Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); + if (prim_geom != IntPtr.Zero) + { + + if (m_NoColide) + { + d.GeomSetCategoryBits(prim_geom, 0); + if (m_isphysical) + { + d.GeomSetCollideBits(prim_geom, (uint)CollisionCategories.Land); + } + else + { + d.GeomSetCollideBits(prim_geom, 0); + d.GeomDisable(prim_geom); + } + } + else + { + d.GeomSetCategoryBits(prim_geom, (uint)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (uint)m_collisionFlags); + } + + UpdatePrimBodyData(); + _parent_scene.actor_name_map[prim_geom] = this; + + } + else + m_log.Warn("Setting bad Geom"); + } + private bool GetMeshGeom() { IntPtr vertices, indices; int vertexCount, indexCount; int vertexStride, triStride; + IMesh mesh = m_mesh; if (mesh == null) @@ -1356,6 +1392,9 @@ namespace OpenSim.Region.Physics.OdePlugin m_mesh = null; return false; } + + IntPtr geo = IntPtr.Zero; + try { _triMeshData = d.GeomTriMeshDataCreate(); @@ -1363,7 +1402,7 @@ namespace OpenSim.Region.Physics.OdePlugin d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride); d.GeomTriMeshDataPreprocess(_triMeshData); - prim_geom = d.CreateTriMesh(m_targetSpace, _triMeshData, null, null, null); + geo = d.CreateTriMesh(m_targetSpace, _triMeshData, null, null, null); } catch (Exception e) @@ -1380,15 +1419,15 @@ namespace OpenSim.Region.Physics.OdePlugin } } _triMeshData = IntPtr.Zero; - prim_geom = IntPtr.Zero; m_hasOBB = false; m_OBBOffset = Vector3.Zero; m_OBB = _size * 0.5f; m_physCost = 0.1f; - m_streamCost = 1.0f; + m_streamCost = 1.0f; + _parent_scene.mesher.ReleaseMesh(mesh); - m_meshState = MeshState.AssetFailed; + m_meshState = MeshState.MeshFailed; m_mesh = null; return false; } @@ -1397,12 +1436,13 @@ namespace OpenSim.Region.Physics.OdePlugin // todo m_streamCost = 1.0f; + SetGeom(geo); + return true; } private void CreateGeom() { - IntPtr geo = IntPtr.Zero; bool hasMesh = false; m_NoColide = false; @@ -1418,8 +1458,11 @@ namespace OpenSim.Region.Physics.OdePlugin m_NoColide = true; } + if (!hasMesh) { + IntPtr geo = IntPtr.Zero; + if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1 && _size.X == _size.Y && _size.Y == _size.Z) { // it's a sphere @@ -1447,7 +1490,7 @@ namespace OpenSim.Region.Physics.OdePlugin } m_physCost = 0.1f; m_streamCost = 1.0f; - prim_geom = geo; + SetGeom(geo); } } @@ -2740,8 +2783,6 @@ namespace OpenSim.Region.Physics.OdePlugin { } - - private void changeAddPhysRep(ODEPhysRepData repData) { _size = repData.size; //?? @@ -2763,10 +2804,6 @@ namespace OpenSim.Region.Physics.OdePlugin if (prim_geom != IntPtr.Zero) { - UpdatePrimBodyData(); - - _parent_scene.actor_name_map[prim_geom] = this; - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); d.Quaternion myrot = new d.Quaternion(); myrot.X = _orientation.X; @@ -2774,23 +2811,23 @@ namespace OpenSim.Region.Physics.OdePlugin myrot.Z = _orientation.Z; myrot.W = _orientation.W; d.GeomSetQuaternion(prim_geom, ref myrot); + } - if (!m_isphysical) - { - SetInStaticSpace(this); - UpdateCollisionCatFlags(); - ApplyCollisionCatFlags(); - } - else - MakeBody(); + if (!m_isphysical) + { + SetInStaticSpace(this); + UpdateCollisionCatFlags(); + ApplyCollisionCatFlags(); + } + else + MakeBody(); - if ((m_meshState & MeshState.NeedMask) != 0) - { - repData.size = _size; - repData.pbs = _pbs; - repData.shapetype = m_shapetype; - _parent_scene.m_meshWorker.RequestMesh(repData); - } + if ((m_meshState & MeshState.NeedMask) != 0) + { + repData.size = _size; + repData.pbs = _pbs; + repData.shapetype = m_shapetype; + _parent_scene.m_meshWorker.RequestMesh(repData); } } @@ -2831,14 +2868,10 @@ namespace OpenSim.Region.Physics.OdePlugin primVolume = repData.volume; - CreateGeom(); + CreateGeom(); if (prim_geom != IntPtr.Zero) { - UpdatePrimBodyData(); - - _parent_scene.actor_name_map[prim_geom] = this; - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); d.Quaternion myrot = new d.Quaternion(); myrot.X = _orientation.X; @@ -2846,30 +2879,29 @@ namespace OpenSim.Region.Physics.OdePlugin myrot.Z = _orientation.Z; myrot.W = _orientation.W; d.GeomSetQuaternion(prim_geom, ref myrot); - - if (m_isphysical) - { - if (chp) - { - if (parent != null) - { - parent.MakeBody(); - } - } - else - MakeBody(); - } - - else - { - SetInStaticSpace(this); - UpdateCollisionCatFlags(); - ApplyCollisionCatFlags(); - } - - resetCollisionAccounting(); } + if (m_isphysical) + { + if (chp) + { + if (parent != null) + { + parent.MakeBody(); + } + } + else + MakeBody(); + } + else + { + SetInStaticSpace(this); + UpdateCollisionCatFlags(); + ApplyCollisionCatFlags(); + } + + resetCollisionAccounting(); + if ((m_meshState & MeshState.NeedMask) != 0) { repData.size = _size; diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs index 21fe9c08f7..06cb3029b4 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODERayCastRequestManager.cs @@ -129,7 +129,7 @@ namespace OpenSim.Region.Physics.OdePlugin req.length = length; req.Normal = direction; req.Origin = position; - req.filter = RayFilterFlags.AllPrims; + req.filter = RayFilterFlags.AllPrims | RayFilterFlags.land; m_PendingRequests.Enqueue(req); } @@ -261,6 +261,12 @@ namespace OpenSim.Region.Physics.OdePlugin closestHit = ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0 ? 0 : 1); backfacecull = ((CurrentRayFilter & RayFilterFlags.BackFaceCull) == 0 ? 0 : 1); + // current ode land to ray collisions is very bad + // so for now limit its range badly + + if (req.length > 30.0f && (CurrentRayFilter & RayFilterFlags.land) != 0) + req.length = 30.0f; + d.GeomRaySetLength(ray, req.length); d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); d.GeomRaySetParams(ray, 0, backfacecull); @@ -288,7 +294,10 @@ namespace OpenSim.Region.Physics.OdePlugin catflags |= CollisionCategories.Water; if (catflags != 0) + { + d.GeomSetCollideBits(ray, (uint)catflags); doSpaceRay(req); + } } else { @@ -314,7 +323,8 @@ namespace OpenSim.Region.Physics.OdePlugin /// private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhanton; - private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; +// private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; + private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton; private void doSpaceRay(ODERayRequest req) { @@ -323,6 +333,8 @@ namespace OpenSim.Region.Physics.OdePlugin d.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback); if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount)) d.SpaceCollide2(ray, m_scene.StaticSpace, IntPtr.Zero, nearCallback); + if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount)) + d.SpaceCollide2(ray, m_scene.GroundSpace, IntPtr.Zero, nearCallback); if (req.callbackMethod is RaycastCallback) { diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs index ed2a531f55..beaba13280 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs @@ -300,6 +300,7 @@ namespace OpenSim.Region.Physics.OdePlugin public IntPtr TopSpace; // the global space public IntPtr ActiveSpace; // space for active prims public IntPtr StaticSpace; // space for the static things around + public IntPtr GroundSpace; // space for ground // some speedup variables private int spaceGridMaxX; @@ -372,6 +373,7 @@ namespace OpenSim.Region.Physics.OdePlugin // now the major subspaces ActiveSpace = d.HashSpaceCreate(TopSpace); StaticSpace = d.HashSpaceCreate(TopSpace); + GroundSpace = d.HashSpaceCreate(TopSpace); } catch { @@ -381,10 +383,12 @@ namespace OpenSim.Region.Physics.OdePlugin d.HashSpaceSetLevels(TopSpace, -2, 8); d.HashSpaceSetLevels(ActiveSpace, -2, 8); d.HashSpaceSetLevels(StaticSpace, -2, 8); + d.HashSpaceSetLevels(GroundSpace, 0, 8); // demote to second level d.SpaceSetSublevel(ActiveSpace, 1); d.SpaceSetSublevel(StaticSpace, 1); + d.SpaceSetSublevel(GroundSpace, 1); d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space | CollisionCategories.Geom | @@ -402,6 +406,8 @@ namespace OpenSim.Region.Physics.OdePlugin )); d.GeomSetCollideBits(StaticSpace, 0); + d.GeomSetCategoryBits(GroundSpace, (uint)(CollisionCategories.Land)); + d.GeomSetCollideBits(GroundSpace, 0); contactgroup = d.JointGroupCreate(0); //contactgroup @@ -1210,6 +1216,7 @@ namespace OpenSim.Region.Physics.OdePlugin chr.CollidingObj = false; // do colisions with static space d.SpaceCollide2(StaticSpace, chr.Shell, IntPtr.Zero, nearCallback); + // no coll with gnd } } catch (AccessViolationException) @@ -1238,7 +1245,10 @@ namespace OpenSim.Region.Physics.OdePlugin if (!prm.m_outbounds) { if (d.BodyIsEnabled(prm.Body)) + { d.SpaceCollide2(StaticSpace, prm.collide_geom, IntPtr.Zero, nearCallback); + d.SpaceCollide2(GroundSpace, prm.collide_geom, IntPtr.Zero, nearCallback); + } } } } @@ -1595,8 +1605,52 @@ namespace OpenSim.Region.Physics.OdePlugin /// /// public override void AddPhysicsActorTaint(PhysicsActor prim) + { + } + + // does all pending changes generated during region load process + public override void PrepareSimulation() + { + lock (OdeLock) { + if (world == IntPtr.Zero) + { + ChangesQueue.Clear(); + return; + } + + ODEchangeitem item; + + int donechanges = 0; + if (ChangesQueue.Count > 0) + { + m_log.InfoFormat("[ODE] start processing pending actor operations"); + int tstart = Util.EnvironmentTickCount(); + + while (ChangesQueue.Dequeue(out item)) + { + if (item.actor != null) + { + try + { + if (item.actor is OdeCharacter) + ((OdeCharacter)item.actor).DoAChange(item.what, item.arg); + else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) + RemovePrimThreadLocked((OdePrim)item.actor); + } + catch + { + m_log.WarnFormat("[PHYSICS]: Operation failed for a actor {0} {1}", + item.actor.Name, item.what.ToString()); + } + } + donechanges++; + } + int time = Util.EnvironmentTickCountSubtract(tstart); + m_log.InfoFormat("[ODE] finished {0} operations in {1}ms", donechanges, time); + } } + } /// /// This is our main simulate loop @@ -1642,7 +1696,40 @@ namespace OpenSim.Region.Physics.OdePlugin lock(OdeLock) { if (world == IntPtr.Zero) + { + ChangesQueue.Clear(); return 0; + } + + ODEchangeitem item; + + if (ChangesQueue.Count > 0) + { + int ttmpstart = Util.EnvironmentTickCount(); + int ttmp; + + while (ChangesQueue.Dequeue(out item)) + { + if (item.actor != null) + { + try + { + if (item.actor is OdeCharacter) + ((OdeCharacter)item.actor).DoAChange(item.what, item.arg); + else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) + RemovePrimThreadLocked((OdePrim)item.actor); + } + catch + { + m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}", + item.actor.Name, item.what.ToString()); + } + } + ttmp = Util.EnvironmentTickCountSubtract(ttmpstart); + if (ttmp > 20) + break; + } + } d.WorldSetQuickStepNumIterations(world, curphysiteractions); @@ -1653,35 +1740,6 @@ namespace OpenSim.Region.Physics.OdePlugin // clear pointer/counter to contacts to pass into joints m_global_contactcount = 0; - ODEchangeitem item; - - if(ChangesQueue.Count >0) - { - int ttmpstart = Util.EnvironmentTickCount(); - int ttmp; - - while(ChangesQueue.Dequeue(out item)) - { - if (item.actor != null) - { - try - { - if (item.actor is OdeCharacter) - ((OdeCharacter)item.actor).DoAChange(item.what, item.arg); - else if (((OdePrim)item.actor).DoAChange(item.what, item.arg)) - RemovePrimThreadLocked((OdePrim)item.actor); - } - catch - { - m_log.WarnFormat("[PHYSICS]: doChange failed for a actor {0} {1}", - item.actor.Name, item.what.ToString()); - } - } - ttmp = Util.EnvironmentTickCountSubtract(ttmpstart); - if (ttmp > 20) - break; - } - } // Move characters lock (_characters) @@ -1813,10 +1871,47 @@ namespace OpenSim.Region.Physics.OdePlugin mesher.ExpireReleaseMeshs(); m_lastMeshExpire = now; } + +// information block running in debug only /* - int nactivegeoms = d.SpaceGetNumGeoms(ActiveSpace); - int nstaticgeoms = d.SpaceGetNumGeoms(StaticSpace); + int ntopactivegeoms = d.SpaceGetNumGeoms(ActiveSpace); + int ntopstaticgeoms = d.SpaceGetNumGeoms(StaticSpace); + int ngroundgeoms = d.SpaceGetNumGeoms(GroundSpace); + + int nactivegeoms = 0; + int nactivespaces = 0; + + int nstaticgeoms = 0; + int nstaticspaces = 0; + IntPtr sp; + + for (int i = 0; i < ntopactivegeoms; i++) + { + sp = d.SpaceGetGeom(ActiveSpace, i); + if (d.GeomIsSpace(sp)) + { + nactivespaces++; + nactivegeoms += d.SpaceGetNumGeoms(sp); + } + else + nactivegeoms++; + } + + for (int i = 0; i < ntopstaticgeoms; i++) + { + sp = d.SpaceGetGeom(StaticSpace, i); + if (d.GeomIsSpace(sp)) + { + nstaticspaces++; + nstaticgeoms += d.SpaceGetNumGeoms(sp); + } + else + nstaticgeoms++; + } + int ntopgeoms = d.SpaceGetNumGeoms(TopSpace); + + int totgeoms = nstaticgeoms + nactivegeoms + ngroundgeoms + 1; // one ray int nbodies = d.NTotalBodies; int ngeoms = d.NTotalGeoms; */ @@ -2113,7 +2208,9 @@ namespace OpenSim.Region.Physics.OdePlugin offset, thickness, wrap); d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); - GroundGeom = d.CreateHeightfield(StaticSpace, HeightmapData, 1); + + GroundGeom = d.CreateHeightfield(GroundSpace, HeightmapData, 1); + if (GroundGeom != IntPtr.Zero) { d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land)); @@ -2234,12 +2331,13 @@ namespace OpenSim.Region.Physics.OdePlugin thickness, wrap); // d.GeomUbitTerrainDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); - GroundGeom = d.CreateUbitTerrain(StaticSpace, HeightmapData, 1); + GroundGeom = d.CreateUbitTerrain(GroundSpace, HeightmapData, 1); if (GroundGeom != IntPtr.Zero) { d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land)); d.GeomSetCollideBits(GroundGeom, 0); + PhysicsActor pa = new NullPhysicsActor(); pa.Name = "Terrain"; pa.PhysicsActorType = (int)ActorTypes.Ground; @@ -2455,6 +2553,7 @@ namespace OpenSim.Region.Physics.OdePlugin d.GeomDestroy(GroundGeom); } + RegionTerrain.Clear(); if (TerrainHeightFieldHeightsHandlers.Count > 0)