add test option ObjectsCullingByDistance. In future, if true, it may

prevent sending objects outside view range to viewers. DO NOT SET TRUE
 unless testing it. Code still not completei!!!
LSLKeyTest
UbitUmarov 2016-07-06 16:10:44 +01:00
parent 259824fbc4
commit c02fe98b7d
7 changed files with 189 additions and 61 deletions

View File

@ -340,6 +340,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private Prioritizer m_prioritizer;
private bool m_disableFacelights = false;
// needs optimazation
private HashSet<SceneObjectGroup> GroupsInView = new HashSet<SceneObjectGroup>();
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<SceneObjectGroup> GroupsNeedFullUpdate = new HashSet<SceneObjectGroup>();
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<SceneObjectGroup> NewGroupsInView = new HashSet<SceneObjectGroup>();
HashSet<SceneObjectGroup> GroupsNeedFullUpdate = new HashSet<SceneObjectGroup>();
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)

View File

@ -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();

View File

@ -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;
}
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// When the physics engine has finished with it, the sculpt data is discarded to save memory.
/// </remarks>
/*
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();
}
*/
/// <summary>
/// Set the user group to which this scene object belongs.
/// </summary>

View File

@ -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 =>

View File

@ -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;

View File

@ -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

View File

@ -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).