From 1973b6d22086f06c26a338fc15171f61e9a5f7d1 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 16 Oct 2026 05:46:50 +0200 Subject: [PATCH] Stardust: draw at BeforeForwardAlpha (deferred cameras never run AfterForwardOpaque); probe checks the event, culling mask 1 and a near control; Main Menu drops the stale GravityCamera Both target cameras are deferred, so the AfterForwardOpaque buffer never drew. The render half of scene-stardust-uncullable now attaches-checks BeforeForwardAlpha, renders with cullingMask 1 (DrawProcedural is layer 0), and requires a near control (dust 100 below, size 5) to draw before the far probe is read, so a miss at 10000 can only be culling. Builds: not compiled by this commit alone; verified in the Unity batchmode run reported with the cut. Co-Authored-By: Claude Opus 5.5 --- Assets/Scenes/Main Menu.unity | 1 - Assets/Scripts/Editor/FlowFieldSceneVerify.cs | 31 ++++++++++++------- Assets/Shaders/Compute/Stardust/Stardust.cs | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Assets/Scenes/Main Menu.unity b/Assets/Scenes/Main Menu.unity index c67fdb7cc..4fafe8336 100644 --- a/Assets/Scenes/Main Menu.unity +++ b/Assets/Scenes/Main Menu.unity @@ -892,7 +892,6 @@ MonoBehaviour: NebulaTint: {fileID: 8400000, guid: d196505464047f04a97f28689041209b, type: 2} Heightmap: {fileID: 8400000, guid: 2fc21a9d3e9647948b56e384cd9378b3, type: 2} ParticleColors: {fileID: 2800000, guid: 56db63da398b2d04394ddbccedce943c, type: 3} - GravityCamera: {fileID: 2103364771} --- !u!114 &750375536 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/Editor/FlowFieldSceneVerify.cs b/Assets/Scripts/Editor/FlowFieldSceneVerify.cs index ba1ca8ca3..771cd9396 100644 --- a/Assets/Scripts/Editor/FlowFieldSceneVerify.cs +++ b/Assets/Scripts/Editor/FlowFieldSceneVerify.cs @@ -156,19 +156,19 @@ namespace Aetheria.EditorTools { var camera = dust.TargetCamera; if (camera == null) { Fail("scene-stardust-uncullable", "Stardust has no TargetCamera"); return; } - var attached = camera.GetCommandBuffers(CameraEvent.AfterForwardOpaque).Count(buffer => buffer.name == "Stardust"); + var attached = camera.GetCommandBuffers(CameraEvent.BeforeForwardAlpha).Count(buffer => buffer.name == "Stardust"); if (attached != 1) Fail("scene-stardust-uncullable", $"{attached} Stardust command buffers on the target camera, expected 1"); var particles = (ComputeBuffer) bufferField.GetValue(dust); var side = Mathf.RoundToInt(Mathf.Sqrt(particles.count)); - float[] Layout(float size) + float[] Layout(float size, Vector3 centre, float below) { var data = new float[particles.count * 7]; for (var i = 0; i < particles.count; i++) { - data[i * 7 + 0] = ((i % side) - side / 2f) * 4f; - data[i * 7 + 1] = -50000f; - data[i * 7 + 2] = ((i / side) - side / 2f) * 4f; + data[i * 7 + 0] = centre.x + ((i % side) - side / 2f) * 4f; + data[i * 7 + 1] = centre.y - below; + data[i * 7 + 2] = centre.z + ((i / side) - side / 2f) * 4f; data[i * 7 + 3] = data[i * 7 + 4] = data[i * 7 + 5] = 1f; data[i * 7 + 6] = size; } @@ -183,10 +183,10 @@ namespace Aetheria.EditorTools var previous = RenderTexture.active; // Image effects on the camera would write their own frame over the dust; only the dust draw is under test. var effects = camera.GetComponents().Where(behaviour => behaviour.enabled).ToArray(); - Color32[] Render(float size) + Color32[] Render(float size, Vector3 centre, float below) { Call(dust, "Update"); // on a bounded draw this queues the draw for the camera; here it dispatches the compute - particles.SetData(Layout(size)); + particles.SetData(Layout(size, centre, below)); camera.Render(); RenderTexture.active = texture; readback.ReadPixels(new Rect(0, 0, 64, 64), 0, 0); @@ -196,14 +196,21 @@ namespace Aetheria.EditorTools try { foreach (var effect in effects) effect.enabled = false; - transform.SetPositionAndRotation(new Vector3(0f, -40000f, 0f), Quaternion.Euler(90f, 0f, 0f)); - camera.farClipPlane = 30000f; camera.clearFlags = CameraClearFlags.SolidColor; camera.backgroundColor = Color.black; - camera.cullingMask = 0; + camera.cullingMask = 1; camera.targetTexture = texture; - var withDust = Render(400f); // the material scales a quad by distance^.33, so at this range it needs this size to cover pixels - var without = Render(0f); + // control: the camera where the scene put it, dust 100 below, inside any box a hand-set extent would give + transform.SetPositionAndRotation(position, Quaternion.Euler(90f, 0f, 0f)); + camera.farClipPlane = 1000f; + var nearWith = Render(5f, position, 100f); var nearWithout = Render(0f, position, 100f); + var nearDiff = 0; for (var i = 0; i < nearWith.Length; i++) if (!nearWith[i].Equals(nearWithout[i])) nearDiff++; + Debug.Log($"{Tag} stardust near-control differing pixels={nearDiff}"); + if (nearDiff == 0) Fail("scene-stardust-uncullable", "control: dust 100 below the camera drew no pixels"); + transform.SetPositionAndRotation(new Vector3(0f, -40000f, 0f), Quaternion.Euler(90f, 0f, 0f)); + camera.farClipPlane = 30000f; + var withDust = Render(400f, transform.position, 10000f); // the material scales a quad by distance^.33, so at this range it needs this size to cover pixels + var without = Render(0f, transform.position, 10000f); var differing = 0; for (var i = 0; i < withDust.Length; i++) if (!withDust[i].Equals(without[i])) differing++; diff --git a/Assets/Shaders/Compute/Stardust/Stardust.cs b/Assets/Shaders/Compute/Stardust/Stardust.cs index 793154e3f..8b8b45c22 100644 --- a/Assets/Shaders/Compute/Stardust/Stardust.cs +++ b/Assets/Shaders/Compute/Stardust/Stardust.cs @@ -59,7 +59,7 @@ public class Stardust : MonoBehaviour // The dust is drawn by a command buffer on TargetCamera: a camera replays its buffers at their event and never culls them, // so the draw needs no bounds and no extent can fall short of how deep the field is. private CommandBuffer _draw; - private const CameraEvent DrawEvent = CameraEvent.AfterForwardOpaque; + private const CameraEvent DrawEvent = CameraEvent.BeforeForwardAlpha; #endregion