fix #451: stabilize portal seam rendering
This commit is contained in:
parent
f6fe0f2a4f
commit
1d2f2f738f
29 changed files with 1650 additions and 239 deletions
|
|
@ -47,6 +47,7 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
public readonly uint ColorArgb;
|
||||
public readonly AcDream.App.Rendering.Gpu.GpuTextureSlot TextureSlot;
|
||||
public readonly float DistanceSq;
|
||||
public readonly uint ClipSlot;
|
||||
|
||||
public ParticleInstance(
|
||||
Vector3 position,
|
||||
|
|
@ -54,7 +55,8 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
Vector3 axisY,
|
||||
uint colorArgb,
|
||||
AcDream.App.Rendering.Gpu.GpuTextureSlot textureSlot,
|
||||
float distanceSq)
|
||||
float distanceSq,
|
||||
uint clipSlot)
|
||||
{
|
||||
Position = position;
|
||||
AxisX = axisX;
|
||||
|
|
@ -62,6 +64,7 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
ColorArgb = colorArgb;
|
||||
TextureSlot = textureSlot;
|
||||
DistanceSq = distanceSq;
|
||||
ClipSlot = clipSlot;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,6 +83,16 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
public Vector4 AxisY;
|
||||
public Vector4 Color;
|
||||
public uint TextureIndex;
|
||||
public uint ClipSlot;
|
||||
}
|
||||
|
||||
/// <summary>Vertex-instance ABI shared with particle_mesh.vert.</summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct MeshParticleGpuInstance
|
||||
{
|
||||
public Matrix4x4 Model;
|
||||
public Vector4 Color;
|
||||
public uint ClipSlot;
|
||||
}
|
||||
|
||||
private readonly struct MeshParticleInstance
|
||||
|
|
@ -87,12 +100,18 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
public readonly Matrix4x4 Model;
|
||||
public readonly uint ColorArgb;
|
||||
public readonly float DistanceSq;
|
||||
public readonly uint ClipSlot;
|
||||
|
||||
public MeshParticleInstance(Matrix4x4 model, uint colorArgb, float distanceSq)
|
||||
public MeshParticleInstance(
|
||||
Matrix4x4 model,
|
||||
uint colorArgb,
|
||||
float distanceSq,
|
||||
uint clipSlot)
|
||||
{
|
||||
Model = model;
|
||||
ColorArgb = colorArgb;
|
||||
DistanceSq = distanceSq;
|
||||
ClipSlot = clipSlot;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +143,7 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
internal (int SetCount, long CapacityBytes) DynamicBufferDiagnostics => (0, 0);
|
||||
|
||||
private BillboardGpuInstance[] _instanceScratch = new BillboardGpuInstance[256];
|
||||
private float[] _meshInstanceScratch = new float[256 * 20];
|
||||
private MeshParticleGpuInstance[] _meshInstanceScratch = new MeshParticleGpuInstance[256];
|
||||
|
||||
// MP-Alloc (2026-07-05): Draw() is called up to ~11 times per frame
|
||||
// (sky pre/post, scene, per-visible-cell, dynamics, unattached passes),
|
||||
|
|
@ -203,7 +222,8 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
cameraRight,
|
||||
cameraUp,
|
||||
emitterFilter,
|
||||
scopedEmitters: null);
|
||||
scopedEmitters: null,
|
||||
clipSlot: 0);
|
||||
FinishDraw(camera, renderPass);
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +233,8 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
ParticleRenderPass renderPass,
|
||||
IReadOnlySet<uint> attachedOwnerIds,
|
||||
bool includeUnattached = false,
|
||||
IReadOnlySet<uint>? excludedAttachedOwnerIds = null)
|
||||
IReadOnlySet<uint>? excludedAttachedOwnerIds = null,
|
||||
uint clipSlot = 0)
|
||||
{
|
||||
if (camera is null)
|
||||
return;
|
||||
|
|
@ -233,7 +254,8 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
cameraRight,
|
||||
cameraUp,
|
||||
emitterFilter: null,
|
||||
_scopedEmitterScratch);
|
||||
_scopedEmitterScratch,
|
||||
clipSlot);
|
||||
FinishDraw(camera, renderPass);
|
||||
}
|
||||
|
||||
|
|
@ -332,7 +354,8 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
Vector3 cameraRight,
|
||||
Vector3 cameraUp,
|
||||
Func<AcDream.Core.Vfx.ParticleEmitter, bool>? emitterFilter,
|
||||
IReadOnlyList<RuntimeParticleEmitter>? scopedEmitters)
|
||||
IReadOnlyList<RuntimeParticleEmitter>? scopedEmitters,
|
||||
uint clipSlot)
|
||||
{
|
||||
var draws = _drawListScratch;
|
||||
draws.Clear();
|
||||
|
|
@ -348,6 +371,7 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
cameraWorldPos,
|
||||
cameraRight,
|
||||
cameraUp,
|
||||
clipSlot,
|
||||
ref sequence);
|
||||
}
|
||||
return;
|
||||
|
|
@ -356,7 +380,13 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
foreach (RuntimeParticleEmitter emitter in _particles.EnumerateRenderableEmitters(renderPass))
|
||||
{
|
||||
if (emitterFilter is null || emitterFilter(emitter))
|
||||
AppendEmitterDraws(emitter, cameraWorldPos, cameraRight, cameraUp, ref sequence);
|
||||
AppendEmitterDraws(
|
||||
emitter,
|
||||
cameraWorldPos,
|
||||
cameraRight,
|
||||
cameraUp,
|
||||
clipSlot,
|
||||
ref sequence);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -365,6 +395,7 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
Vector3 cameraWorldPos,
|
||||
Vector3 cameraRight,
|
||||
Vector3 cameraUp,
|
||||
uint clipSlot,
|
||||
ref int sequence)
|
||||
{
|
||||
List<ParticleDraw> draws = _drawListScratch;
|
||||
|
|
@ -385,7 +416,13 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
uint gfxObjId = em.Desc.HwGfxObjId != 0 ? em.Desc.HwGfxObjId : em.Desc.GfxObjId;
|
||||
if (gfxObjId != 0
|
||||
&& ResolveGeometryKind(gfxObjId) == RetailParticleGeometryKind.FullMesh
|
||||
&& TryAppendMeshDraws(em, p, gfxObjId, cameraWorldPos, ref sequence))
|
||||
&& TryAppendMeshDraws(
|
||||
em,
|
||||
p,
|
||||
gfxObjId,
|
||||
cameraWorldPos,
|
||||
clipSlot,
|
||||
ref sequence))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -483,7 +520,8 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
axisY,
|
||||
p.ColorArgb,
|
||||
gfxInfo.TextureSlot,
|
||||
distSq)));
|
||||
distSq,
|
||||
clipSlot)));
|
||||
_submissionScratch.Add(new ParticleSubmission(
|
||||
ParticleSubmissionKind.Billboard,
|
||||
drawIndex,
|
||||
|
|
@ -497,6 +535,7 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
Particle particle,
|
||||
uint gfxObjId,
|
||||
Vector3 cameraWorldPosition,
|
||||
uint clipSlot,
|
||||
ref int sequence)
|
||||
{
|
||||
if (_meshAdapter is null || !MeshParticlesAvailable)
|
||||
|
|
@ -520,7 +559,11 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
model,
|
||||
cameraWorldPosition);
|
||||
float distanceSq = viewerDistance * viewerDistance;
|
||||
var instance = new MeshParticleInstance(model, particle.ColorArgb, distanceSq);
|
||||
var instance = new MeshParticleInstance(
|
||||
model,
|
||||
particle.ColorArgb,
|
||||
distanceSq,
|
||||
clipSlot);
|
||||
|
||||
for (int batchIndex = 0; batchIndex < renderData.Batches.Count; batchIndex++)
|
||||
{
|
||||
|
|
@ -581,35 +624,24 @@ public sealed unsafe partial class ParticleRenderer : IDisposable
|
|||
TextureIndex = particle.TextureSlot.IsAssigned
|
||||
? particle.TextureSlot.Index
|
||||
: NoTextureSlot,
|
||||
ClipSlot = particle.ClipSlot,
|
||||
};
|
||||
}
|
||||
|
||||
private static void WriteMeshGpuInstance(
|
||||
float[] destination,
|
||||
int offset,
|
||||
ref MeshParticleGpuInstance destination,
|
||||
MeshParticleInstance instance)
|
||||
{
|
||||
Matrix4x4 model = instance.Model;
|
||||
destination[offset + 0] = model.M11;
|
||||
destination[offset + 1] = model.M12;
|
||||
destination[offset + 2] = model.M13;
|
||||
destination[offset + 3] = model.M14;
|
||||
destination[offset + 4] = model.M21;
|
||||
destination[offset + 5] = model.M22;
|
||||
destination[offset + 6] = model.M23;
|
||||
destination[offset + 7] = model.M24;
|
||||
destination[offset + 8] = model.M31;
|
||||
destination[offset + 9] = model.M32;
|
||||
destination[offset + 10] = model.M33;
|
||||
destination[offset + 11] = model.M34;
|
||||
destination[offset + 12] = model.M41;
|
||||
destination[offset + 13] = model.M42;
|
||||
destination[offset + 14] = model.M43;
|
||||
destination[offset + 15] = model.M44;
|
||||
destination[offset + 16] = ((instance.ColorArgb >> 16) & 0xFF) / 255f;
|
||||
destination[offset + 17] = ((instance.ColorArgb >> 8) & 0xFF) / 255f;
|
||||
destination[offset + 18] = (instance.ColorArgb & 0xFF) / 255f;
|
||||
destination[offset + 19] = ((instance.ColorArgb >> 24) & 0xFF) / 255f;
|
||||
destination = new MeshParticleGpuInstance
|
||||
{
|
||||
Model = instance.Model,
|
||||
Color = new Vector4(
|
||||
((instance.ColorArgb >> 16) & 0xFF) / 255f,
|
||||
((instance.ColorArgb >> 8) & 0xFF) / 255f,
|
||||
(instance.ColorArgb & 0xFF) / 255f,
|
||||
((instance.ColorArgb >> 24) & 0xFF) / 255f),
|
||||
ClipSlot = instance.ClipSlot,
|
||||
};
|
||||
}
|
||||
|
||||
private TranslucencyKind ResolveMeshBlend(ObjectRenderBatch batch)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue