Merge eureka/aetheria-gravity-stardust-bounds (closing verdicts cut-stardust-bounds.s1, cut-stardust-bounds.s2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
fdecde02d0
4 changed files with 120 additions and 29 deletions
|
|
@ -16461,7 +16461,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: 1537342003}
|
||||
--- !u!114 &1009503736
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
|
@ -140,6 +140,8 @@ namespace Aetheria.EditorTools
|
|||
Call(volume, "Update");
|
||||
if (Differing(flowing, Frame()) == 0) Fail("scene-stardust-run", "the particle buffer did not move while the zone ran");
|
||||
if (Shader.GetGlobalFloat("_NebulaNoiseTime") == noiseTime) Fail("scene-noise-clock", "_NebulaNoiseTime did not move while the zone ran");
|
||||
|
||||
CheckStardustUncullable(dust, bufferField);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -147,6 +149,88 @@ namespace Aetheria.EditorTools
|
|||
}
|
||||
}
|
||||
|
||||
// The dust is a command buffer on the target camera, which no culling sees: with every particle 10000 below the
|
||||
// camera (far past any box a hand could inflate round it) a render still shows dust, and shows none when the
|
||||
// same particles have no size.
|
||||
static void CheckStardustUncullable(Stardust dust, FieldInfo bufferField)
|
||||
{
|
||||
var camera = dust.TargetCamera;
|
||||
if (camera == null) { Fail("scene-stardust-uncullable", "Stardust has no TargetCamera"); return; }
|
||||
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, Vector3 centre, float below)
|
||||
{
|
||||
var data = new float[particles.count * 7];
|
||||
for (var i = 0; i < particles.count; i++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
var transform = camera.transform;
|
||||
var (position, rotation) = (transform.position, transform.rotation);
|
||||
var (far, flags, background, mask, target) = (camera.farClipPlane, camera.clearFlags, camera.backgroundColor, camera.cullingMask, camera.targetTexture);
|
||||
var texture = RenderTexture.GetTemporary(64, 64, 24, RenderTextureFormat.ARGB32);
|
||||
var readback = new Texture2D(64, 64, TextureFormat.RGBA32, false);
|
||||
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<MonoBehaviour>().Where(behaviour => behaviour.enabled).ToArray();
|
||||
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, centre, below));
|
||||
camera.Render();
|
||||
RenderTexture.active = texture;
|
||||
readback.ReadPixels(new Rect(0, 0, 64, 64), 0, 0);
|
||||
readback.Apply();
|
||||
return readback.GetPixels32();
|
||||
}
|
||||
try
|
||||
{
|
||||
foreach (var effect in effects) effect.enabled = false;
|
||||
camera.clearFlags = CameraClearFlags.SolidColor;
|
||||
camera.backgroundColor = Color.black;
|
||||
camera.cullingMask = 1;
|
||||
camera.targetTexture = texture;
|
||||
// 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++;
|
||||
if (differing == 0) Fail("scene-stardust-uncullable", "the dust 10000 below the camera drew no pixels");
|
||||
}
|
||||
finally
|
||||
{
|
||||
RenderTexture.active = previous;
|
||||
foreach (var effect in effects) effect.enabled = true;
|
||||
camera.targetTexture = target;
|
||||
camera.cullingMask = mask;
|
||||
camera.backgroundColor = background;
|
||||
camera.clearFlags = flags;
|
||||
camera.farClipPlane = far;
|
||||
transform.SetPositionAndRotation(position, rotation);
|
||||
RenderTexture.ReleaseTemporary(texture);
|
||||
UnityEngine.Object.DestroyImmediate(readback);
|
||||
}
|
||||
}
|
||||
|
||||
// CloudShader's pass 0 compiles with the flow keywords (it must #include_with_pragmas the shared include).
|
||||
static void CheckCloudKeywords()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ public class Stardust : MonoBehaviour
|
|||
public Texture Heightmap;
|
||||
public Texture2D ParticleColors;
|
||||
//public Transform TargetTransform;
|
||||
public Camera GravityCamera;
|
||||
|
||||
private const int GROUP_SIZE = 128;
|
||||
private int _updateParticlesKernel;
|
||||
|
|
@ -57,6 +56,11 @@ public class Stardust : MonoBehaviour
|
|||
private ComputeBuffer _quadPoints;
|
||||
private const int QUAD_STRIDE = 12;
|
||||
|
||||
// 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.BeforeForwardAlpha;
|
||||
|
||||
#endregion
|
||||
|
||||
#region setup
|
||||
|
|
@ -91,6 +95,33 @@ public class Stardust : MonoBehaviour
|
|||
new Vector3(-.5f, -.5f),
|
||||
new Vector3(-.5f, .5f)
|
||||
});
|
||||
|
||||
//The buffers never change after this, so the material is bound once
|
||||
ParticleMaterial.SetBuffer("particles", _particlesBuffer);
|
||||
ParticleMaterial.SetBuffer("quadPoints", _quadPoints);
|
||||
|
||||
//Start may run again (the scene harness calls it by hand): drop the previous draw before building the next
|
||||
DetachDraw();
|
||||
_draw?.Release();
|
||||
_draw = new CommandBuffer { name = "Stardust" };
|
||||
_draw.DrawProcedural(Matrix4x4.identity, ParticleMaterial, 0, MeshTopology.Triangles, 6, Span * Span);
|
||||
AttachDraw();
|
||||
}
|
||||
|
||||
void OnEnable() => AttachDraw();
|
||||
|
||||
void OnDisable() => DetachDraw();
|
||||
|
||||
void AttachDraw()
|
||||
{
|
||||
if (_draw != null && TargetCamera != null)
|
||||
TargetCamera.AddCommandBuffer(DrawEvent, _draw);
|
||||
}
|
||||
|
||||
void DetachDraw()
|
||||
{
|
||||
if (_draw != null && TargetCamera != null)
|
||||
TargetCamera.RemoveCommandBuffer(DrawEvent, _draw);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
|
@ -104,7 +135,6 @@ public class Stardust : MonoBehaviour
|
|||
// Particle lifetimes cycle on the flow clock (zone time), so the dust stops with the sim like everything the flow moves.
|
||||
ParticleCalculation.SetFloat("phase", FlowField.Cycle(VolumeSampling.FlowClock, Period));
|
||||
|
||||
var pos = GravityCamera.transform.position;
|
||||
ParticleCalculation.SetFloat("period", Period);
|
||||
ParticleCalculation.SetFloat("spacing", Spacing);
|
||||
ParticleCalculation.SetFloat("ceilingHeight", Ceiling);
|
||||
|
|
@ -121,38 +151,17 @@ public class Stardust : MonoBehaviour
|
|||
//Dispatch, launch threads on GPU
|
||||
int numberOfGroups = Mathf.CeilToInt((float)Span * Span / GROUP_SIZE);
|
||||
ParticleCalculation.Dispatch(_updateParticlesKernel, numberOfGroups, 1, 1);
|
||||
|
||||
ParticleMaterial.SetBuffer("particles", _particlesBuffer);
|
||||
ParticleMaterial.SetBuffer("quadPoints", _quadPoints);
|
||||
Graphics.DrawProcedural(ParticleMaterial, new Bounds(pos, new Vector3(Spacing * Span, 2048, Spacing * Span)), MeshTopology.Triangles, 6, Span * Span, TargetCamera, null, ShadowCastingMode.Off, false, 0);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region rendering
|
||||
// void OnRenderObject()
|
||||
// {
|
||||
// if (Camera.current == TargetCamera || Camera.current.name == "SceneCamera")
|
||||
// {
|
||||
// //Bind resources to material
|
||||
// ParticleMaterial.SetBuffer("particles", _particlesBuffer);
|
||||
// ParticleMaterial.SetBuffer("quadPoints", _quadPoints);
|
||||
// // ParticleMaterial.SetFloat("velocityStretch", ParticleVelocityStretch);
|
||||
// // ParticleMaterial.SetVector("velocity", PlayerVelocity);
|
||||
//
|
||||
// //Set the pass
|
||||
// ParticleMaterial.SetPass(0);
|
||||
//
|
||||
// //Draw
|
||||
// Graphics.DrawProceduralNow(MeshTopology.Triangles, 6, Span * Span);
|
||||
// }
|
||||
// }
|
||||
#endregion
|
||||
|
||||
#region cleanup
|
||||
void OnDestroy()
|
||||
{
|
||||
// m_emitterProxies.Release();
|
||||
// _temperature.Release();
|
||||
DetachDraw();
|
||||
_draw?.Release();
|
||||
_draw = null;
|
||||
if(_particlesBuffer!=null)
|
||||
{
|
||||
_particlesBuffer.Release();
|
||||
|
|
|
|||
Loading…
Reference in a new issue