diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 4a48a80645..cddafc5557 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -340,6 +340,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private Prioritizer m_prioritizer; private bool m_disableFacelights = false; + // needs optimazation + private HashSet GroupsInView = new HashSet(); + private bool m_VelocityInterpolate = false; private const uint MaxTransferBytesPerPacket = 600; @@ -3978,7 +3981,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP // float avgTimeDilation = 0.0f; IEntityUpdate iupdate; Int32 timeinqueue; // this is just debugging code & can be dropped later - + + bool doCulling = m_scene.ObjectsCullingByDistance; + float cullingrange = 64.0f; + HashSet GroupsNeedFullUpdate = new HashSet(); + Vector3 mycamera = Vector3.Zero; + Vector3 mypos = Vector3.Zero; + ScenePresence mysp = (ScenePresence)SceneAgent; + if(mysp != null && !mysp.IsDeleted) + { + cullingrange = mysp.DrawDistance + m_scene.ReprioritizationDistance +16f; + mycamera = mysp.CameraPosition; + mypos = mysp.AbsolutePosition; + } + else + doCulling = false; + while (updatesThisCall < maxUpdates) { lock (m_entityUpdates.SyncRoot) @@ -4059,6 +4077,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + if(doCulling && !part.ParentGroup.IsAttachment) + { + lock(GroupsInView) + { + if(!GroupsInView.Contains(part.ParentGroup)) + { + Vector3 partpos = part.ParentGroup.AbsolutePosition; + float dcam = (partpos - mycamera).LengthSquared(); + float dpos = (partpos - mypos).LengthSquared(); + if(dcam < dpos) + dpos = dcam; + dpos = (float)Math.Sqrt(dpos) + part.ParentGroup.GetBoundsRadius(); + if(dpos > cullingrange) + continue; + + if(!GroupsNeedFullUpdate.Contains(part.ParentGroup)) + GroupsNeedFullUpdate.Add(part.ParentGroup); + continue; + } + } + } + if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) { // Ensure that mesh has at least 8 valid faces @@ -4247,8 +4287,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP SendKillObject(m_killRecord); m_killRecord.Clear(); } - #endregion + lock(GroupsNeedFullUpdate) + { + if(GroupsNeedFullUpdate.Count > 0) + { + foreach(SceneObjectGroup grp in GroupsNeedFullUpdate) + { + grp.ScheduleGroupForFullUpdate(); + lock(GroupsInView) + GroupsInView.Add(grp); + } + GroupsNeedFullUpdate.Clear(); + } + } + #endregion } @@ -4282,10 +4335,81 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void ReprioritizeUpdates() { + CheckGroupsInView(); lock (m_entityUpdates.SyncRoot) m_entityUpdates.Reprioritize(UpdatePriorityHandler); } + public void CheckGroupsInView() + { + bool doCulling = m_scene.ObjectsCullingByDistance; + if(!doCulling) + return; + float cullingrange = 64.0f; + Vector3 mycamera = Vector3.Zero; + Vector3 mypos = Vector3.Zero; + ScenePresence mysp = (ScenePresence)SceneAgent; + if(mysp != null && !mysp.IsDeleted) + { + cullingrange = mysp.DrawDistance + m_scene.ReprioritizationDistance + 16f; + mycamera = mysp.CameraPosition; + mypos = mysp.AbsolutePosition; + } + else + return; + + HashSet NewGroupsInView = new HashSet(); + HashSet GroupsNeedFullUpdate = new HashSet(); + + lock(GroupsInView) + { + EntityBase[] entities = m_scene.Entities.GetEntities(); + foreach (EntityBase e in entities) + { + if (e != null && e is SceneObjectGroup && !((SceneObjectGroup)e).IsAttachment) + { + SceneObjectGroup grp = (SceneObjectGroup)e; + Vector3 grppos = grp.AbsolutePosition; + float dcam = (grppos - mycamera).LengthSquared(); + float dpos = (grppos - mypos).LengthSquared(); + if(dcam < dpos) + dpos = dcam; + dpos = (float)Math.Sqrt(dpos) + grp.GetBoundsRadius(); + if(dpos > cullingrange) + { + if(GroupsInView.Contains(grp)) + { + GroupsInView.Remove(grp); + if (!m_killRecord.Contains(grp.LocalId)) + m_killRecord.Add(grp.LocalId); + } + } + else + { + if(!GroupsInView.Contains(grp) && !GroupsNeedFullUpdate.Contains(grp)) + GroupsNeedFullUpdate.Add(grp); + NewGroupsInView.Add(grp); + } + } + } + } + + GroupsInView = NewGroupsInView; + + if (m_killRecord.Count > 0) + { + SendKillObject(m_killRecord); + m_killRecord.Clear(); + } + + if(GroupsNeedFullUpdate.Count > 0) + { + foreach(SceneObjectGroup grp in GroupsNeedFullUpdate) + grp.ScheduleGroupForFullUpdate(); + } + GroupsNeedFullUpdate.Clear(); + } + private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity) { if (entity != null) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 0d19e94582..3c5630ea98 100755 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -803,9 +803,9 @@ namespace OpenSim.Region.Framework.Scenes public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get; set; } public bool IsReprioritizationEnabled { get; set; } public float ReprioritizationInterval { get; set; } - public float RootReprioritizationDistance { get; set; } - public float ChildReprioritizationDistance { get; set; } + public float ReprioritizationDistance { get; set; } private float m_minReprioritizationDistance = 32f; + public bool ObjectsCullingByDistance = false; public AgentCircuitManager AuthenticateHandler { @@ -1185,15 +1185,15 @@ namespace OpenSim.Region.Framework.Scenes = interestConfig.GetBoolean("ReprioritizationEnabled", IsReprioritizationEnabled); ReprioritizationInterval = interestConfig.GetFloat("ReprioritizationInterval", ReprioritizationInterval); - RootReprioritizationDistance - = interestConfig.GetFloat("RootReprioritizationDistance", RootReprioritizationDistance); - ChildReprioritizationDistance - = interestConfig.GetFloat("ChildReprioritizationDistance", ChildReprioritizationDistance); + ReprioritizationDistance + = interestConfig.GetFloat("RootReprioritizationDistance", ReprioritizationDistance); + + if(ReprioritizationDistance < m_minReprioritizationDistance) + ReprioritizationDistance = m_minReprioritizationDistance; + + ObjectsCullingByDistance + = interestConfig.GetBoolean("ObjectsCullingByDistance", ObjectsCullingByDistance); - if(RootReprioritizationDistance < m_minReprioritizationDistance) - RootReprioritizationDistance = m_minReprioritizationDistance; - if(ChildReprioritizationDistance < m_minReprioritizationDistance) - ChildReprioritizationDistance = m_minReprioritizationDistance; RootTerseUpdatePeriod = interestConfig.GetInt("RootTerseUpdatePeriod", RootTerseUpdatePeriod); ChildTerseUpdatePeriod = interestConfig.GetInt("ChildTerseUpdatePeriod", ChildTerseUpdatePeriod); @@ -1252,8 +1252,7 @@ namespace OpenSim.Region.Framework.Scenes RootRotationUpdateTolerance = 0.1f; RootVelocityUpdateTolerance = 0.001f; RootPositionUpdateTolerance = 0.05f; - RootReprioritizationDistance = m_minReprioritizationDistance; - ChildReprioritizationDistance = m_minReprioritizationDistance; + ReprioritizationDistance = m_minReprioritizationDistance; m_eventManager = new EventManager(); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index cb1bf55ebd..4e87014e17 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1567,6 +1567,39 @@ namespace OpenSim.Region.Framework.Scenes #endregion + private float? m_boundsRadius = null; + + public float GetBoundsRadius() + { + // this may need more threading work + if(m_boundsRadius == null) + { + float res = 0; + SceneObjectPart p; + SceneObjectPart[] parts; + float partR; + lock (m_parts) + { + parts = m_parts.GetArray(); + } + + int nparts = parts.Length; + for (int i = 0; i < nparts; i++) + { + p = parts[i]; + partR = p.Scale.Length(); + if(p != RootPart) + partR += p.OffsetPosition.Length(); + if(partR > res) + res = partR; + } + m_boundsRadius = res; + return res; + } + + return m_boundsRadius.Value; + } + public void GetResourcesCosts(SceneObjectPart apart, out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost) { @@ -4596,14 +4629,11 @@ namespace OpenSim.Region.Framework.Scenes if (nparts <= 1) return gc; - Quaternion parentRot = RootPart.RotationOffset; Vector3 pPos; // average all parts positions for (int i = 0; i < nparts; i++) { - // do it directly - // gc += parts[i].GetWorldPosition(); if (parts[i] != RootPart) { pPos = parts[i].OffsetPosition; @@ -4613,8 +4643,6 @@ namespace OpenSim.Region.Framework.Scenes } gc /= nparts; - // relative to root: -// gc -= AbsolutePosition; return gc; } @@ -4661,30 +4689,6 @@ namespace OpenSim.Region.Framework.Scenes return Ptot; } - /// - /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that - /// the physics engine can use it. - /// - /// - /// When the physics engine has finished with it, the sculpt data is discarded to save memory. - /// -/* - public void CheckSculptAndLoad() - { - if (IsDeleted) - return; - - if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) - return; - -// m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId); - - SceneObjectPart[] parts = m_parts.GetArray(); - - for (int i = 0; i < parts.Length; i++) - parts[i].CheckSculptAndLoad(); - } -*/ /// /// Set the user group to which this scene object belongs. /// diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 4775b1fbb6..817ed4359e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -350,6 +350,7 @@ namespace OpenSim.Region.Framework.Scenes protected int m_reprioritizationLastTime; protected bool m_reprioritizationBusy; protected Vector3 m_reprioritizationLastPosition; + protected float m_reprioritizationLastDrawDistance; private Quaternion m_headrotation = Quaternion.Identity; @@ -1047,6 +1048,8 @@ namespace OpenSim.Region.Framework.Scenes AbsolutePosition = posLastMove = posLastSignificantMove = CameraPosition = m_reprioritizationLastPosition = ControllingClient.StartPos; + m_reprioritizationLastDrawDistance = DrawDistance; + // disable updates workjobs for now childUpdatesBusy = true; m_reprioritizationBusy = true; @@ -2130,6 +2133,7 @@ namespace OpenSim.Region.Framework.Scenes // priority uses avatar position only m_reprioritizationLastPosition = AbsolutePosition; + m_reprioritizationLastDrawDistance = DrawDistance; m_reprioritizationLastTime = Util.EnvironmentTickCount() + 15000; // delay it m_reprioritizationBusy = false; @@ -3986,24 +3990,24 @@ namespace OpenSim.Region.Framework.Scenes if(m_reprioritizationBusy) return; + float limit = Scene.ReprioritizationDistance; + bool byDrawdistance = Scene.ObjectsCullingByDistance; + if(byDrawdistance) + byDrawdistance = (Math.Abs(DrawDistance-m_reprioritizationLastDrawDistance) > 0.5f * limit); + int tdiff = Util.EnvironmentTickCountSubtract(m_reprioritizationLastTime); - if(tdiff < Scene.ReprioritizationInterval) + if(!byDrawdistance && tdiff < Scene.ReprioritizationInterval) return; // priority uses avatar position Vector3 pos = AbsolutePosition; Vector3 diff = pos - m_reprioritizationLastPosition; - float limit; - if(IsChildAgent) - limit = (float)Scene.ChildReprioritizationDistance; - else - limit = (float)Scene.RootReprioritizationDistance; - limit *= limit; - if (diff.LengthSquared() < limit) + if (!byDrawdistance && diff.LengthSquared() < limit) return; m_reprioritizationBusy = true; m_reprioritizationLastPosition = pos; + m_reprioritizationLastDrawDistance = DrawDistance; Util.FireAndForget( o => diff --git a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs index db5c7eb8f4..cbb79d026d 100644 --- a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs +++ b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs @@ -156,7 +156,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments cdl.AddRow("active", m_scene.Active); cdl.AddRow("animations", m_scene.DebugAnimations); cdl.AddRow("appear-refresh", m_scene.SendPeriodicAppearanceUpdates); - cdl.AddRow("child-repri", m_scene.ChildReprioritizationDistance); cdl.AddRow("client-pos-upd", m_scene.RootPositionUpdateTolerance); cdl.AddRow("client-rot-upd", m_scene.RootRotationUpdateTolerance); cdl.AddRow("client-vel-upd", m_scene.RootVelocityUpdateTolerance); @@ -219,15 +218,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments m_scene.SendPeriodicAppearanceUpdates = newValue; } - if (options.ContainsKey("child-repri")) - { - double newValue; - - // FIXME: This can only come from the console at the moment but might not always be true. - if (ConsoleUtil.TryParseConsoleDouble(MainConsole.Instance, options["child-repri"], out newValue)) - m_scene.ChildReprioritizationDistance = (float)newValue; - } - if (options.ContainsKey("client-pos-upd")) { float newValue; diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 141c60804f..9d868a1d8e 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1122,6 +1122,9 @@ ;; SimpleAngularDistance, FrontBack ; UpdatePrioritizationScheme = BestAvatarResponsiveness + ; TEST OPTION KEEP AS FALSE + ; if true, don't send object updates if outside view range + ; ObjectsCullingByDistance = false [MediaOnAPrim] ;# {Enabled} {} {Enable Media-on-a-Prim (MOAP)} {true false} true diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 841a761a54..df92921a00 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -2016,6 +2016,10 @@ ReprioritizationInterval = 2000.0 RootReprioritizationDistance = 10.0 ChildReprioritizationDistance = 20.0 + + ; TEST OPTION KEEP AS FALSE + ; if true, don't send object updates if outside view range + ObjectsCullingByDistance = false ; If n > 1, only every n UDP terse updates will be sent to observers of an avatar that are in the same region ; Updates will always be sent to the avatar that the update addresses and if av velocity is effectively zero (to prevent drift due to missing updates).