feat(rendering): journal live scene projections
Mirror exact live-root and equipped-child lifetimes behind the non-drawing render-scene boundary. Ready, visibility, final-pose, rebucket, removal, and resource teardown edges retain canonical LiveEntityRuntime identity while active-only synchronization avoids resident-static scans. Co-authored-by: Erik Nilsson <erikn@users.noreply.github.com>
This commit is contained in:
parent
5d19c56d15
commit
58e7c2eb99
10 changed files with 949 additions and 148 deletions
|
|
@ -1,4 +1,3 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Rendering.Wb;
|
||||
using AcDream.App.Streaming;
|
||||
using AcDream.Core.World;
|
||||
|
|
@ -25,7 +24,6 @@ internal sealed class StaticRenderProjectionJournal :
|
|||
{
|
||||
private const byte StaticEntityDomain = 1;
|
||||
private const byte EnvCellShellDomain = 2;
|
||||
private const float DefaultAabbRadius = 5.0f;
|
||||
|
||||
private readonly RenderProjectionJournal _journal;
|
||||
private readonly Dictionary<uint, Dictionary<RenderProjectionId, TrackedProjection>>
|
||||
|
|
@ -115,7 +113,7 @@ internal sealed class StaticRenderProjectionJournal :
|
|||
|
||||
if (accepted != retained.Record)
|
||||
{
|
||||
AppendUpdates(retained.Record, accepted);
|
||||
_journal.AppendDifference(retained.Record, accepted);
|
||||
current[candidate.Id] = new TrackedProjection(accepted);
|
||||
}
|
||||
continue;
|
||||
|
|
@ -217,61 +215,18 @@ internal sealed class StaticRenderProjectionJournal :
|
|||
uint landblockId,
|
||||
WorldEntity entity)
|
||||
{
|
||||
CurrentRenderProjectionFingerprint fingerprint =
|
||||
CurrentRenderSceneOracle.CreateProjectionFingerprint(
|
||||
landblockId,
|
||||
entity);
|
||||
RenderProjectionFlags flags = RenderProjectionFlags.Selectable;
|
||||
if (entity.IsDrawVisible && entity.IsAncestorDrawVisible)
|
||||
flags |= RenderProjectionFlags.Draw;
|
||||
if (!entity.IsDrawVisible)
|
||||
flags |= RenderProjectionFlags.Hidden;
|
||||
if (!entity.IsAncestorDrawVisible)
|
||||
flags |= RenderProjectionFlags.AncestorHidden;
|
||||
|
||||
RenderTransform transform = RenderTransform.FromRoot(
|
||||
entity.Position,
|
||||
entity.Rotation,
|
||||
entity.Scale);
|
||||
(Vector3 minimum, Vector3 maximum) = CalculateBounds(entity);
|
||||
RenderProjectionId id = StaticEntityId(landblockId, entity.Id);
|
||||
uint fullCellId = entity.ParentCellId ?? landblockId;
|
||||
return new RenderProjectionRecord(
|
||||
return RenderProjectionRecordFactory.ProjectEntity(
|
||||
id,
|
||||
InteriorEntityPartition.IsIndoorCellId(entity.ParentCellId)
|
||||
? RenderProjectionClass.IndoorCellStatic
|
||||
: RenderProjectionClass.OutdoorStatic,
|
||||
default,
|
||||
transform,
|
||||
new PreviousRenderTransform(transform.LocalToWorld),
|
||||
new RenderMeshSet(
|
||||
RenderAssetHandle.FromRaw(
|
||||
fingerprint.Geometry.Low ^ fingerprint.Geometry.High),
|
||||
entity.MeshRefs.Count,
|
||||
0),
|
||||
new RenderMaterialVariant(
|
||||
fingerprint.Appearance.Low,
|
||||
fingerprint.Appearance.High,
|
||||
1.0f),
|
||||
new RenderSpatialResidency(
|
||||
RenderSpatialBucket.FromRaw(fullCellId),
|
||||
landblockId,
|
||||
fullCellId),
|
||||
new RenderWorldBounds(minimum, maximum),
|
||||
flags,
|
||||
default,
|
||||
id.ToSortKey(),
|
||||
RenderDirtyMask.All,
|
||||
new RenderSourceMetadata(
|
||||
entity.Id,
|
||||
entity.ServerGuid,
|
||||
entity.SourceGfxObjOrSetupId,
|
||||
entity.ParentCellId ?? 0,
|
||||
entity.EffectCellId ?? 0,
|
||||
entity.BuildingShellAnchorCellId ?? 0,
|
||||
fingerprint.Transform,
|
||||
fingerprint.Geometry,
|
||||
fingerprint.Appearance));
|
||||
landblockId,
|
||||
fullCellId,
|
||||
entity,
|
||||
spatiallyVisible: true);
|
||||
}
|
||||
|
||||
private static RenderProjectionRecord ProjectEnvCellShell(
|
||||
|
|
@ -332,95 +287,6 @@ internal sealed class StaticRenderProjectionJournal :
|
|||
RenderSceneHash128.Empty));
|
||||
}
|
||||
|
||||
private void AppendUpdates(
|
||||
in RenderProjectionRecord prior,
|
||||
in RenderProjectionRecord current)
|
||||
{
|
||||
if (prior.Transform != current.Transform
|
||||
|| prior.Bounds != current.Bounds
|
||||
|| prior.SortKey != current.SortKey
|
||||
|| prior.Source.TransformFingerprint
|
||||
!= current.Source.TransformFingerprint)
|
||||
{
|
||||
_journal.Update(
|
||||
RenderProjectionDeltaKind.UpdateTransform,
|
||||
in current);
|
||||
}
|
||||
|
||||
if (prior.MeshSet != current.MeshSet
|
||||
|| prior.Material != current.Material
|
||||
|| prior.DegradeState != current.DegradeState
|
||||
|| prior.Source.GeometryFingerprint != current.Source.GeometryFingerprint
|
||||
|| prior.Source.AppearanceFingerprint != current.Source.AppearanceFingerprint)
|
||||
{
|
||||
_journal.Update(
|
||||
RenderProjectionDeltaKind.UpdateAppearance,
|
||||
in current);
|
||||
}
|
||||
|
||||
if (prior.Residency != current.Residency)
|
||||
{
|
||||
_journal.Update(
|
||||
RenderProjectionDeltaKind.Rebucket,
|
||||
in current);
|
||||
}
|
||||
|
||||
if (prior.Flags != current.Flags)
|
||||
{
|
||||
_journal.Update(
|
||||
RenderProjectionDeltaKind.UpdateFlags,
|
||||
in current);
|
||||
}
|
||||
}
|
||||
|
||||
private static (Vector3 Minimum, Vector3 Maximum) CalculateBounds(
|
||||
WorldEntity entity)
|
||||
{
|
||||
Vector3 position = entity.Position;
|
||||
if (entity.HasLocalBounds)
|
||||
{
|
||||
Vector3 localMin = entity.LocalBoundMin;
|
||||
Vector3 localMax = entity.LocalBoundMax;
|
||||
Vector3 minimum = default;
|
||||
Vector3 maximum = default;
|
||||
for (int cornerIndex = 0; cornerIndex < 8; cornerIndex++)
|
||||
{
|
||||
Vector3 corner = new(
|
||||
(cornerIndex & 1) == 0 ? localMin.X : localMax.X,
|
||||
(cornerIndex & 2) == 0 ? localMin.Y : localMax.Y,
|
||||
(cornerIndex & 4) == 0 ? localMin.Z : localMax.Z);
|
||||
Vector3 transformed = Vector3.Transform(corner, entity.Rotation);
|
||||
if (cornerIndex == 0)
|
||||
{
|
||||
minimum = transformed;
|
||||
maximum = transformed;
|
||||
}
|
||||
else
|
||||
{
|
||||
minimum = Vector3.Min(minimum, transformed);
|
||||
maximum = Vector3.Max(maximum, transformed);
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 margin = new(DefaultAabbRadius);
|
||||
return (
|
||||
position + minimum - margin,
|
||||
position + maximum + margin);
|
||||
}
|
||||
|
||||
float radius = DefaultAabbRadius;
|
||||
for (int i = 0; i < entity.MeshRefs.Count; i++)
|
||||
{
|
||||
radius = MathF.Max(
|
||||
radius,
|
||||
DefaultAabbRadius
|
||||
+ entity.MeshRefs[i].PartTransform.Translation.Length());
|
||||
}
|
||||
|
||||
Vector3 extent = new(radius);
|
||||
return (position - extent, position + extent);
|
||||
}
|
||||
|
||||
private RenderOwnerIncarnation NextIncarnation()
|
||||
{
|
||||
if (_nextIncarnation == ulong.MaxValue)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue