public sealed class ParticleRenderFeatureDraws the particles of VfxSystems: the second concrete renderable, and the first one whose geometry is rebuilt every frame.
Remarks
A mesh arrives as buffers that already exist and the feature's job is to bind them. An effect arrives as a few thousand positions that were different last frame, so the feature's job is to make the geometry — expand each particle into a camera-facing quad, append it to one buffer shared by every effect in the frame, and record the run. One upload, one vertex buffer, one index buffer, and a draw per effect.
The expansion is on the CPU, and that is the temporary half of this. Doc 06 wants the simulation on the GPU with an indirect draw, at which point the vertex shader expands from a particle buffer and this uploads a quarter of the bytes. What is here works everywhere, needs no compute, and — because Vixen.Vfx owns the expansion and knows nothing about graphics — is checked against numbers rather than against a screenshot.
One expansion, one view. A camera-facing quad faces a camera, so an effect drawn into two views would need expanding twice. It is expanded once, against View or the first view if that is not set, and every other view draws the same quads — which is right for a reflection nobody inspects closely and wrong for a shadow caster, so particles should not be in a shadow stage. The GPU path removes the limitation rather than working around it, which is why it is not worked around here.
⚠ Once per frame, and it has been described as "once per view" — including in the issue tracking the fix. The difference is the whole symptom: a second view does not pay for a second expansion, it draws the first view's geometry. Every draw involved is valid, so no command, counter or validation message distinguished the two cases until ViewsFacingElsewhere, which is what says the limitation is biting this frame.
Fields and properties (18)
public override string NameThe feature's name, for logging and profiling.
public RenderDataKey<ParticleDraw> DrawsWhere each effect's run is. One entry per object.
public RenderDataKey<int> SystemIndicesEach object's index into Systems, or -1 for none.
public RenderDataKey<MeshDraw> MeshesThe mesh a Mesh effect draws an instance of, per object.
public IReadOnlyList<VfxSystem?> SystemsThe effects this feature knows about.
public IGraphicsDevice? DeviceThe device the buffers live on. Set before the first frame that draws.
public PipelineCache? PipelinesWhere pipelines come from. Set before the first frame that draws.
public IPipelineDescriber? DescriberHow a pipeline is described for a given effect, stage and output.
public RenderView? ViewThe view the quads are built to face, or null for the first one.
public RenderView? ExpandedForWhich view this frame's quads were actually built to face, or null if none were.
public int ViewsFacingElsewhereHow many other views will draw this frame's quads, which face ExpandedFor and not them.
public int VertexLayoutWhich vertex layout ParticleVertex is, as an index into the describer's table.
public int LastParticleCountHow many particles the last frame expanded, across every effect.
public IList<RenderLight>? LightsWhere a Light effect's particles go, or null for a host that does not light its scene with particles.
public int MaxLightsHow many lights every light effect in the frame may contribute between them.
public int RefusedLightsHow many particle lights the budget refused, the last time lights were collected.
public int CollectedLightsHow many particle lights the last collection actually contributed.
public int LightEffectsHow many light effects the last prepared frame held.
Methods (7)
public int CollectLights()Hands every light effect's particles to Lights, up to MaxLights.
public void SetSystem(RenderObjectId id, VfxSystem? system)Attaches an effect to an object.
public void SetMesh(RenderObjectId id, MeshDraw mesh)Says which mesh an instanced effect draws.
protected internal override void Initialize(RenderSystem system)Registers this feature's own per-object data. Called once, when it is added.
protected internal override void Prepare(RenderSystem system)protected internal override void Draw(RenderSystem system, RenderDrawContext context, ReadOnlySpan<RenderNode> nodes)Records this feature's share of one stage's work into a command list.
public void Dispose()Frees the buffers.
Used by (11)
- ArenaThirdPersonShooter
- HarnessVixen.Rendering.Tests
- HarnessVixen.Rendering.Tests
- ParticleLightFeatureTestsVixen.Rendering.Tests
- ParticleMeshDeviceTestsVixen.Graphics.Golden.Tests
- ParticleRenderFeatureTestsVixen.Rendering.Tests
- ParticleSpriteDeviceTestsVixen.Graphics.Golden.Tests
- VfxExtractionSystemVixen.Rendering
- VfxExtractionTestsVixen.Rendering.Tests
- WorldRendererVixen.Engine.Renderer
- EditorWorldRendererVixen.Editor.App