From 0f2676af970e38502dfddfe04cbd68b946f3205b Mon Sep 17 00:00:00 2001 From: jcant0n Date: Tue, 11 Aug 2026 20:04:47 +0200 Subject: [PATCH 1/5] Add an occlusion culling benchmark sample Measures what a CPU visibility pass costs over a thousand boxes, two ways and at two ray widths, with the accuracy of each. No shading: this measures visibility. The per-object pass runs at 0.16 ms and removes two thirds of the draw calls, about 1% of a 16.6 ms frame. The visibility buffer is four times dearer, culls less, and is far more accurate. Both numbers come with what they get wrong. Three things this turned up that are worth having written down: Packet width has to be asked of the device. rtcIntersect16/rtcOccluded16 may only be called when RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED says so, and calling them anyway is undefined behaviour: the first version of this sample used 16 and corrupted the heap, surfacing as a crash inside AlignedFree with no hint of the real cause. The shipped binaries are AVX2, which tops out at 8. Packets are not automatically faster. They lose the per-object early exit -- once one sample proves a box visible the rest are wasted, but the lanes are already committed -- and 9,000 rays with SIMD come out slower than 7,165 without. For the visibility buffer, where every ray is needed anyway, they draw level. The obvious per-object test is wrong. An occlusion ray stopping just short of a sample point on the box has the box occlude itself, since the point sits on its own surface. Asking what the ray hits first costs more and answers the question actually being asked. Accuracy is reported weighted by screen area, not by object count. In a grid this dense most of what is technically visible is visible through a gap a pixel or two wide, so a raw count of missed objects reads as alarming while the pass is fine: 163 boxes missed, 3% of the screen. --- .gitignore | 5 + Embree.sln | 14 + OcclusionCulling/Camera.cs | 98 ++++++ OcclusionCulling/Culling.cs | 400 +++++++++++++++++++++++ OcclusionCulling/OcclusionCulling.csproj | 17 + OcclusionCulling/Png.cs | 137 ++++++++ OcclusionCulling/Program.cs | 356 ++++++++++++++++++++ OcclusionCulling/README.md | 92 ++++++ OcclusionCulling/Scene.cs | 166 ++++++++++ OcclusionCulling/docs/scene.png | Bin 0 -> 49477 bytes OcclusionCulling/docs/slice.png | Bin 0 -> 21709 bytes OcclusionCulling/docs/verdict.png | Bin 0 -> 26236 bytes README.md | 6 + 13 files changed, 1291 insertions(+) create mode 100644 OcclusionCulling/Camera.cs create mode 100644 OcclusionCulling/Culling.cs create mode 100644 OcclusionCulling/OcclusionCulling.csproj create mode 100644 OcclusionCulling/Png.cs create mode 100644 OcclusionCulling/Program.cs create mode 100644 OcclusionCulling/README.md create mode 100644 OcclusionCulling/Scene.cs create mode 100644 OcclusionCulling/docs/scene.png create mode 100644 OcclusionCulling/docs/slice.png create mode 100644 OcclusionCulling/docs/verdict.png diff --git a/.gitignore b/.gitignore index 56107a5..7c6c08c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,8 @@ # Screenshot produced by the sample at runtime (docs/ holds the committed ones). HelloEmbree/screenshot.png + +# Images the sample writes at runtime (docs/ holds the committed ones). +OcclusionCulling/scene.png +OcclusionCulling/verdict.png +OcclusionCulling/slice.png diff --git a/Embree.sln b/Embree.sln index 0d0b98c..675577f 100644 --- a/Embree.sln +++ b/Embree.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Evergine.Bindings.Embree", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloEmbree", "HelloEmbree\HelloEmbree.csproj", "{E4461EA5-FD21-4449-A493-7BF77E32C8D2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OcclusionCulling", "OcclusionCulling\OcclusionCulling.csproj", "{9D90D092-3E99-429C-8657-C4809D72375B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -55,6 +57,18 @@ Global {E4461EA5-FD21-4449-A493-7BF77E32C8D2}.Release|x64.Build.0 = Release|Any CPU {E4461EA5-FD21-4449-A493-7BF77E32C8D2}.Release|x86.ActiveCfg = Release|Any CPU {E4461EA5-FD21-4449-A493-7BF77E32C8D2}.Release|x86.Build.0 = Release|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Debug|x64.ActiveCfg = Debug|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Debug|x64.Build.0 = Debug|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Debug|x86.ActiveCfg = Debug|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Debug|x86.Build.0 = Debug|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Release|Any CPU.Build.0 = Release|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Release|x64.ActiveCfg = Release|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Release|x64.Build.0 = Release|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Release|x86.ActiveCfg = Release|Any CPU + {9D90D092-3E99-429C-8657-C4809D72375B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/OcclusionCulling/Camera.cs b/OcclusionCulling/Camera.cs new file mode 100644 index 0000000..3adbbcf --- /dev/null +++ b/OcclusionCulling/Camera.cs @@ -0,0 +1,98 @@ +using System; +using System.Numerics; + +namespace OcclusionCulling +{ + /// + /// A pinhole camera plus the six frustum planes derived from it. + /// + /// + /// The AABB test is the same scalar six-plane centre/half-extent form Evergine's + /// BoundingFrustum.Intersects(ref BoundingBox, out bool) uses, reproduced here so the + /// sample stays free of engine dependencies and runs on every RID the binding ships. + /// + internal sealed class Camera + { + private readonly Vector4[] planes = new Vector4[6]; + + public Camera(Vector3 position, Vector3 target, float fovDegrees, float aspect, float near, float far) + { + this.Position = position; + this.Forward = Vector3.Normalize(target - position); + this.Right = Vector3.Normalize(Vector3.Cross(this.Forward, Vector3.UnitY)); + this.Up = Vector3.Cross(this.Right, this.Forward); + + this.TanHalfFov = MathF.Tan(fovDegrees * MathF.PI / 180.0f * 0.5f); + this.Aspect = aspect; + + var view = Matrix4x4.CreateLookAt(position, target, Vector3.UnitY); + var projection = Matrix4x4.CreatePerspectiveFieldOfView( + fovDegrees * MathF.PI / 180.0f, aspect, near, far); + this.ExtractPlanes(view * projection); + } + + public Vector3 Position { get; } + + public Vector3 Forward { get; } + + public Vector3 Right { get; } + + public Vector3 Up { get; } + + public float TanHalfFov { get; } + + public float Aspect { get; } + + /// + /// Ray direction through a normalised screen position, both in [0, 1]. + /// + public Vector3 RayDirection(float u, float v) + { + float x = ((u * 2.0f) - 1.0f) * this.TanHalfFov * this.Aspect; + float y = (1.0f - (v * 2.0f)) * this.TanHalfFov; + return Vector3.Normalize(this.Forward + (this.Right * x) + (this.Up * y)); + } + + /// + /// Tests an AABB against the six planes. Conservative: a box straddling a plane counts + /// as inside. + /// + public bool Intersects(in Vector3 min, in Vector3 max) + { + Vector3 centre = (min + max) * 0.5f; + Vector3 extent = (max - min) * 0.5f; + + for (int i = 0; i < 6; i++) + { + Vector4 p = this.planes[i]; + var normal = new Vector3(p.X, p.Y, p.Z); + + float distance = Vector3.Dot(normal, centre) + p.W; + float radius = Vector3.Dot(Vector3.Abs(normal), extent); + + if (distance + radius < 0.0f) + { + return false; + } + } + + return true; + } + + private void ExtractPlanes(Matrix4x4 m) + { + this.planes[0] = Normalize(new Vector4(m.M14 + m.M11, m.M24 + m.M21, m.M34 + m.M31, m.M44 + m.M41)); // left + this.planes[1] = Normalize(new Vector4(m.M14 - m.M11, m.M24 - m.M21, m.M34 - m.M31, m.M44 - m.M41)); // right + this.planes[2] = Normalize(new Vector4(m.M14 + m.M12, m.M24 + m.M22, m.M34 + m.M32, m.M44 + m.M42)); // bottom + this.planes[3] = Normalize(new Vector4(m.M14 - m.M12, m.M24 - m.M22, m.M34 - m.M32, m.M44 - m.M42)); // top + this.planes[4] = Normalize(new Vector4(m.M13, m.M23, m.M33, m.M43)); // near + this.planes[5] = Normalize(new Vector4(m.M14 - m.M13, m.M24 - m.M23, m.M34 - m.M33, m.M44 - m.M43)); // far + } + + private static Vector4 Normalize(Vector4 plane) + { + float length = new Vector3(plane.X, plane.Y, plane.Z).Length(); + return length > 0.0f ? plane / length : plane; + } + } +} diff --git a/OcclusionCulling/Culling.cs b/OcclusionCulling/Culling.cs new file mode 100644 index 0000000..1d854dc --- /dev/null +++ b/OcclusionCulling/Culling.cs @@ -0,0 +1,400 @@ +using Evergine.Bindings.Embree; +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using EmbreeScene = Evergine.Bindings.Embree.Scene; + +namespace OcclusionCulling +{ + /// + /// The occlusion culling passes under measurement. + /// + /// + /// Two families, because they answer different questions and their cost scales with + /// different things: + /// + /// Per-object rays scale with the object count. This is what an engine runs to decide + /// which draw calls to submit. + /// A visibility buffer scales with resolution. It is exact up to its sampling density + /// and does not care how many objects there are. + /// + /// Each comes in a single-ray and a 16-wide packet form. + /// + internal static unsafe class Culling + { + /// Sample points shot at each box: eight corners and the centre. + public const int SamplesPerBox = 9; + + private const float TargetEpsilon = 1e-3f; + + /// + /// Frustum stage. Fills with the boxes that survive and + /// returns how many there are. + /// + public static int Frustum(Scene scene, Camera camera, int[] candidates) + { + int count = 0; + for (int i = 0; i < scene.BoxCount; i++) + { + if (camera.Intersects(scene.Min[i], scene.Max[i])) + { + candidates[count++] = i; + } + } + + return count; + } + + // ----------------------------------------------------------------------------------- + // A — per-object rays + // ----------------------------------------------------------------------------------- + + /// + /// One occlusion ray per sample point, stopping at the first sample that gets through. + /// + public static long PerObjectSingle(Scene scene, Camera camera, int[] candidates, int candidateCount, bool[] visible) + { + Array.Clear(visible); + long rays = 0; + + EmbreeScene handle = scene.Handle; + Vector3 origin = camera.Position; + + object counterLock = new(); + + Parallel.For( + 0, + candidateCount, + () => (Buffer: (IntPtr)NativeMemory.AlignedAlloc((nuint)sizeof(RayHit), 64), Rays: 0L), + (index, _, state) => + { + RayHit* rayhit = (RayHit*)state.Buffer; + IntersectArguments args; + Embree.InitIntersectArguments(&args); + args.Flags = RayQueryFlags.Coherent; + + int box = candidates[index]; + Span points = stackalloc Vector3[SamplesPerBox]; + scene.GetSamplePoints(box, points); + + long local = state.Rays; + + for (int s = 0; s < SamplesPerBox; s++) + { + local++; + if (ReachesBox(handle, rayhit, &args, origin, points[s], (uint)box)) + { + visible[box] = true; + break; + } + } + + return (state.Buffer, local); + }, + state => + { + NativeMemory.AlignedFree((void*)state.Buffer); + lock (counterLock) + { + rays += state.Rays; + } + }); + + return rays; + } + + /// + /// The same test, eight rays at a time. + /// + /// + /// Packets cost the early exit: every sample of every candidate is traced, because the + /// lanes are filled before any of them is known to have got through. That is the trade + /// this benchmark exists to measure — more rays, but each one much cheaper. + /// + public static long PerObjectPacket(Scene scene, Camera camera, int[] candidates, int candidateCount, bool[] visible) + { + Array.Clear(visible); + + int total = candidateCount * SamplesPerBox; + int packets = (total + 7) / 8; + + EmbreeScene handle = scene.Handle; + Vector3 origin = camera.Position; + + Parallel.For( + 0, + packets, + // Rays and mask in separate allocations. Packing the mask after the packet in one + // block put it exactly at the end of the reservation, and anything overrunning + // the packet by a byte then corrupted the allocator's bookkeeping instead of + // failing where the mistake was. + () => (Rays: (IntPtr)NativeMemory.AlignedAlloc((nuint)sizeof(RayHit8), 32), + Valid: (IntPtr)NativeMemory.AlignedAlloc(8 * sizeof(int), 32)), + (packet, _, buffers) => + { + RayHit8* rays = (RayHit8*)buffers.Rays; + int* valid = (int*)buffers.Valid; + + IntersectArguments args; + Embree.InitIntersectArguments(&args); + args.Flags = RayQueryFlags.Coherent; + + // The buffer is reused across packets and starts uninitialised. Every lane + // has to hold a well-formed ray even when it is masked off: the traversal + // works on all eight lanes at once, and garbage in a disabled lane + // becomes a NaN in the SIMD maths that takes the whole packet down. + *rays = default; + + int start = packet * 8; + Span points = stackalloc Vector3[SamplesPerBox]; + int lastBox = -1; + + for (int lane = 0; lane < 8; lane++) + { + int flat = start + lane; + if (flat >= total) + { + // Disabled, and empty: tnear > tfar leaves nothing to intersect. + valid[lane] = 0; + rays->Ray.DirZ[lane] = 1.0f; + rays->Ray.Tnear[lane] = 1.0f; + rays->Ray.Tfar[lane] = 0.0f; + continue; + } + + int box = candidates[flat / SamplesPerBox]; + if (box != lastBox) + { + scene.GetSamplePoints(box, points); + lastBox = box; + } + + Vector3 direction = Vector3.Normalize(points[flat % SamplesPerBox] - origin); + + valid[lane] = -1; + rays->Ray.OrgX[lane] = origin.X; + rays->Ray.OrgY[lane] = origin.Y; + rays->Ray.OrgZ[lane] = origin.Z; + rays->Ray.DirX[lane] = direction.X; + rays->Ray.DirY[lane] = direction.Y; + rays->Ray.DirZ[lane] = direction.Z; + rays->Ray.Tnear[lane] = 0.0f; + rays->Ray.Tfar[lane] = float.PositiveInfinity; + rays->Ray.Mask[lane] = uint.MaxValue; + rays->Hit.GeomID[lane] = Embree.INVALID_GEOMETRY_ID; + } + + Embree.Intersect8(valid, handle, rays, &args); + + for (int lane = 0; lane < 8; lane++) + { + int flat = start + lane; + if (flat >= total || valid[lane] == 0) + { + continue; + } + + // This sample reached the box before anything else, so it is visible. + int box = candidates[flat / SamplesPerBox]; + if (rays->Hit.GeomID[lane] == (uint)box) + { + visible[box] = true; + } + } + + return buffers; + }, + buffers => + { + NativeMemory.AlignedFree((void*)buffers.Rays); + NativeMemory.AlignedFree((void*)buffers.Valid); + }); + + return total; + } + + // ----------------------------------------------------------------------------------- + // B — visibility buffer + // ----------------------------------------------------------------------------------- + + /// + /// Casts a primary ray per sample and marks whatever geometry it lands on. Exact up to + /// the sampling density. + /// + public static long VisibilityBufferSingle(Scene scene, Camera camera, int width, int height, bool[] visible, uint[] ids = null) + { + Array.Clear(visible); + + EmbreeScene handle = scene.Handle; + Vector3 origin = camera.Position; + + Parallel.For( + 0, + height, + () => (IntPtr)NativeMemory.AlignedAlloc((nuint)sizeof(RayHit), 64), + (y, _, buffer) => + { + RayHit* rayhit = (RayHit*)buffer; + IntersectArguments args; + Embree.InitIntersectArguments(&args); + args.Flags = RayQueryFlags.Coherent; + + for (int x = 0; x < width; x++) + { + Vector3 direction = camera.RayDirection((x + 0.5f) / width, (y + 0.5f) / height); + + *rayhit = default; + rayhit->Ray.OrgX = origin.X; + rayhit->Ray.OrgY = origin.Y; + rayhit->Ray.OrgZ = origin.Z; + rayhit->Ray.DirX = direction.X; + rayhit->Ray.DirY = direction.Y; + rayhit->Ray.DirZ = direction.Z; + rayhit->Ray.Tnear = 0.0f; + rayhit->Ray.Tfar = float.PositiveInfinity; + rayhit->Ray.Mask = uint.MaxValue; + rayhit->Hit.GeomID = Embree.INVALID_GEOMETRY_ID; + + Embree.Intersect1(handle, rayhit, &args); + + uint id = rayhit->Hit.GeomID; + if (ids != null) + { + ids[(y * width) + x] = id; + } + + if (id != Embree.INVALID_GEOMETRY_ID) + { + visible[id] = true; + } + } + + return buffer; + }, + buffer => NativeMemory.AlignedFree((void*)buffer)); + + return (long)width * height; + } + + /// + /// The same buffer, eight pixels at a time. Consecutive pixels of a row share almost all of + /// their traversal, which is what the packet path is built for. + /// + public static long VisibilityBufferPacket(Scene scene, Camera camera, int width, int height, bool[] visible) + { + Array.Clear(visible); + + EmbreeScene handle = scene.Handle; + Vector3 origin = camera.Position; + int packetsPerRow = (width + 7) / 8; + + Parallel.For( + 0, + height, + () => (Rays: (IntPtr)NativeMemory.AlignedAlloc((nuint)sizeof(RayHit8), 32), + Valid: (IntPtr)NativeMemory.AlignedAlloc(8 * sizeof(int), 32)), + (y, _, buffers) => + { + RayHit8* rayhit = (RayHit8*)buffers.Rays; + int* valid = (int*)buffers.Valid; + + IntersectArguments args; + Embree.InitIntersectArguments(&args); + args.Flags = RayQueryFlags.Coherent; + + for (int packet = 0; packet < packetsPerRow; packet++) + { + *rayhit = default; + + for (int lane = 0; lane < 8; lane++) + { + int x = (packet * 8) + lane; + if (x >= width) + { + // See the comment in PerObjectPacket: a disabled lane still has + // to hold a well-formed, empty ray. + valid[lane] = 0; + rayhit->Ray.DirZ[lane] = 1.0f; + rayhit->Ray.Tnear[lane] = 1.0f; + rayhit->Ray.Tfar[lane] = 0.0f; + continue; + } + + Vector3 direction = camera.RayDirection((x + 0.5f) / width, (y + 0.5f) / height); + + valid[lane] = -1; + rayhit->Ray.OrgX[lane] = origin.X; + rayhit->Ray.OrgY[lane] = origin.Y; + rayhit->Ray.OrgZ[lane] = origin.Z; + rayhit->Ray.DirX[lane] = direction.X; + rayhit->Ray.DirY[lane] = direction.Y; + rayhit->Ray.DirZ[lane] = direction.Z; + rayhit->Ray.Tnear[lane] = 0.0f; + rayhit->Ray.Tfar[lane] = float.PositiveInfinity; + rayhit->Ray.Mask[lane] = uint.MaxValue; + rayhit->Hit.GeomID[lane] = Embree.INVALID_GEOMETRY_ID; + } + + Embree.Intersect8(valid, handle, rayhit, &args); + + for (int lane = 0; lane < 8; lane++) + { + if (valid[lane] == 0) + { + continue; + } + + uint id = rayhit->Hit.GeomID[lane]; + if (id != Embree.INVALID_GEOMETRY_ID) + { + visible[id] = true; + } + } + } + + return buffers; + }, + buffers => + { + NativeMemory.AlignedFree((void*)buffers.Rays); + NativeMemory.AlignedFree((void*)buffers.Valid); + }); + + return (long)width * height; + } + + /// + /// Whether a ray aimed at reaches box + /// before anything else. + /// + /// + /// Closest-hit, not the cheaper any-hit. The obvious formulation — an occlusion ray that + /// stops just short of the sample point — has the box occlude itself: the point sits on + /// its surface, so its own front face is in the way for every sample except the few + /// silhouette corners. Measured on this scene that answered "hidden" for a quarter of the + /// boxes that were plainly visible. Asking what the ray hits first costs more per ray and + /// is the question actually being asked. + /// + private static bool ReachesBox(EmbreeScene scene, RayHit* rayhit, IntersectArguments* args, Vector3 origin, Vector3 target, uint box) + { + Vector3 direction = Vector3.Normalize(target - origin); + + *rayhit = default; + rayhit->Ray.OrgX = origin.X; + rayhit->Ray.OrgY = origin.Y; + rayhit->Ray.OrgZ = origin.Z; + rayhit->Ray.DirX = direction.X; + rayhit->Ray.DirY = direction.Y; + rayhit->Ray.DirZ = direction.Z; + rayhit->Ray.Tnear = 0.0f; + rayhit->Ray.Tfar = float.PositiveInfinity; + rayhit->Ray.Mask = uint.MaxValue; + rayhit->Hit.GeomID = Embree.INVALID_GEOMETRY_ID; + + Embree.Intersect1(scene, rayhit, args); + + return rayhit->Hit.GeomID == box; + } + } +} diff --git a/OcclusionCulling/OcclusionCulling.csproj b/OcclusionCulling/OcclusionCulling.csproj new file mode 100644 index 0000000..b047f87 --- /dev/null +++ b/OcclusionCulling/OcclusionCulling.csproj @@ -0,0 +1,17 @@ + + + + Exe + net10.0 + True + disable + true + true + OcclusionCulling + + + + + + + diff --git a/OcclusionCulling/Png.cs b/OcclusionCulling/Png.cs new file mode 100644 index 0000000..daaf600 --- /dev/null +++ b/OcclusionCulling/Png.cs @@ -0,0 +1,137 @@ +using System; +using System.IO; +using System.IO.Compression; + +namespace OcclusionCulling +{ + /// + /// A minimal PNG writer, so the sample stays dependency-free and runs on every RID the + /// binding ships. System.Drawing would not do: it is Windows-only on modern .NET. + /// + internal static class Png + { + /// + /// Writes an RGB image. is three bytes per pixel, row-major. + /// + public static void Write(string path, int width, int height, byte[] rgb) + { + // PNG wants a filter byte at the start of every scanline; 0 means "no filter". + var raw = new byte[height * ((width * 3) + 1)]; + for (int y = 0; y < height; y++) + { + int source = y * width * 3; + int destination = y * ((width * 3) + 1); + raw[destination] = 0; + Array.Copy(rgb, source, raw, destination + 1, width * 3); + } + + using var file = File.Create(path); + file.Write(new byte[] { 0x89, (byte)'P', (byte)'N', (byte)'G', 0x0D, 0x0A, 0x1A, 0x0A }); + + var header = new byte[13]; + WriteBigEndian(header, 0, (uint)width); + WriteBigEndian(header, 4, (uint)height); + header[8] = 8; // bit depth + header[9] = 2; // colour type: truecolour + WriteChunk(file, "IHDR", header); + + WriteChunk(file, "IDAT", Deflate(raw)); + WriteChunk(file, "IEND", Array.Empty()); + } + + /// + /// zlib stream: a two-byte header, raw deflate, and an Adler-32 of the uncompressed + /// data. DeflateStream produces the middle part; the wrapper has to be added by hand + /// because ZLibStream's header bytes are not what every decoder expects from a PNG. + /// + private static byte[] Deflate(byte[] data) + { + using var output = new MemoryStream(); + output.WriteByte(0x78); // CM = deflate, CINFO = 32K window + output.WriteByte(0x01); // no preset dictionary, fastest compression + + using (var deflate = new DeflateStream(output, CompressionLevel.Fastest, leaveOpen: true)) + { + deflate.Write(data, 0, data.Length); + } + + uint adler = Adler32(data); + output.WriteByte((byte)(adler >> 24)); + output.WriteByte((byte)(adler >> 16)); + output.WriteByte((byte)(adler >> 8)); + output.WriteByte((byte)adler); + + return output.ToArray(); + } + + private static void WriteChunk(Stream stream, string type, byte[] data) + { + var length = new byte[4]; + WriteBigEndian(length, 0, (uint)data.Length); + stream.Write(length); + + var payload = new byte[4 + data.Length]; + for (int i = 0; i < 4; i++) + { + payload[i] = (byte)type[i]; + } + + Array.Copy(data, 0, payload, 4, data.Length); + stream.Write(payload); + + var crc = new byte[4]; + WriteBigEndian(crc, 0, Crc32(payload)); + stream.Write(crc); + } + + private static void WriteBigEndian(byte[] buffer, int offset, uint value) + { + buffer[offset + 0] = (byte)(value >> 24); + buffer[offset + 1] = (byte)(value >> 16); + buffer[offset + 2] = (byte)(value >> 8); + buffer[offset + 3] = (byte)value; + } + + private static uint Adler32(byte[] data) + { + uint a = 1, b = 0; + foreach (byte value in data) + { + a = (a + value) % 65521; + b = (b + a) % 65521; + } + + return (b << 16) | a; + } + + private static readonly uint[] CrcTable = BuildCrcTable(); + + private static uint[] BuildCrcTable() + { + var table = new uint[256]; + for (uint n = 0; n < 256; n++) + { + uint c = n; + for (int k = 0; k < 8; k++) + { + c = (c & 1) != 0 ? 0xEDB88320u ^ (c >> 1) : c >> 1; + } + + table[n] = c; + } + + return table; + } + + private static uint Crc32(byte[] data) + { + uint c = 0xFFFFFFFFu; + foreach (byte value in data) + { + c = CrcTable[(c ^ value) & 0xFF] ^ (c >> 8); + } + + return c ^ 0xFFFFFFFFu; + } + } +} diff --git a/OcclusionCulling/Program.cs b/OcclusionCulling/Program.cs new file mode 100644 index 0000000..6a72eb6 --- /dev/null +++ b/OcclusionCulling/Program.cs @@ -0,0 +1,356 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Numerics; + +namespace OcclusionCulling +{ + /// + /// Measures what a CPU occlusion culling pass costs over a thousand boxes, with Embree + /// doing the visibility queries. + /// + internal static class Program + { + private const int SideCount = 10; // 10^3 = 1000 boxes + private const float BoxSize = 1.0f; + private const float Spacing = 1.8f; // centre-to-centre, in box sizes + + private const int CullWidth = 320; // resolution of the visibility-buffer pass + private const int CullHeight = 180; + private const int TruthWidth = 1280; // ground truth, far denser + private const int TruthHeight = 720; + + private const int WarmupIterations = 20; + private const int MeasuredIterations = 100; + + private static int Main(string[] args) + { + bool images = args.Contains("--images"); + + using var scene = new Scene(SideCount, BoxSize, Spacing); + + // Outside the grid, looking at its centre, close enough that the near faces hide + // most of the interior. That is the situation occlusion culling exists for. + float extent = BoxSize * Spacing * (SideCount - 1) * 0.5f; + var camera = new Camera( + position: new Vector3(extent * 2.5f, extent * 1.4f, extent * 2.9f), + target: Vector3.Zero, + fovDegrees: 55.0f, + aspect: (float)CullWidth / CullHeight, + near: 0.1f, + far: extent * 20.0f); + + Console.WriteLine($"Scene : {scene.BoxCount:N0} boxes ({SideCount}x{SideCount}x{SideCount}), {scene.TriangleCount:N0} triangles, one geometry each"); + Console.WriteLine($"Logical cores : {Environment.ProcessorCount}"); + Console.WriteLine($"Widest packet : {scene.MaxPacketWidth} rays (asked of the device, not assumed)"); + Console.WriteLine(); + + var candidates = new int[scene.BoxCount]; + var visible = new bool[scene.BoxCount]; + var truth = new bool[scene.BoxCount]; + + // Ground truth: a visibility buffer far denser than any of the passes below. What it + // finds is what is genuinely visible; everything else is a sampling artefact. + // + // Its per-box pixel counts matter as much as the visibility flags. In a grid this + // dense most of what is "visible" is visible through a gap a pixel or two wide, and + // counting those the same as a box filling a quarter of the screen would make the + // accuracy column say nothing useful. + var truthIds = new uint[TruthWidth * TruthHeight]; + Culling.VisibilityBufferSingle(scene, camera, TruthWidth, TruthHeight, truth, truthIds); + int trulyVisible = truth.Count(v => v); + + var pixelsPerBox = new long[scene.BoxCount]; + long coveredPixels = 0; + foreach (uint id in truthIds) + { + if (id != Embree_INVALID) + { + pixelsPerBox[id]++; + coveredPixels++; + } + } + + int frustumCount = Culling.Frustum(scene, camera, candidates); + Console.WriteLine($"Frustum pass : {frustumCount:N0} of {scene.BoxCount:N0} boxes survive"); + Console.WriteLine($"Ground truth : {trulyVisible:N0} boxes actually visible at {TruthWidth}x{TruthHeight}"); + Console.WriteLine(); + + var results = new[] + { + Measure("frustum only", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => { Array.Clear(vis); for (int i = 0; i < n; i++) { vis[cand[i]] = true; } return 0; }), + + Measure("per-object, single ray", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => Culling.PerObjectSingle(s, c, cand, n, vis)), + + Measure("per-object, 8-wide packets", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => Culling.PerObjectPacket(s, c, cand, n, vis)), + + Measure($"visibility buffer {CullWidth}x{CullHeight}, single ray", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => Culling.VisibilityBufferSingle(s, c, CullWidth, CullHeight, vis)), + + Measure($"visibility buffer {CullWidth}x{CullHeight}, 8-wide packets", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => Culling.VisibilityBufferPacket(s, c, CullWidth, CullHeight, vis)), + }; + + Console.WriteLine("Method median mean min max rays visible culled miss screen extra"); + foreach (var r in results) + { + Console.WriteLine( + $"{r.Name,-42} {r.Median,7:F3}ms {r.Mean,7:F3}ms {r.Min,7:F3}ms {r.Max,7:F3}ms {r.Rays,9:N0} {r.Visible,9:N0} {r.CulledPercent,6:F1}% {r.FalseNegatives,6:N0} {r.MissedScreenPercent,6:F2}% {r.FalsePositives,6:N0}"); + } + + Console.WriteLine(); + Console.WriteLine("miss = visible boxes the pass discarded (these pop on screen)"); + Console.WriteLine("screen = how much of the covered screen area those discarded boxes actually held"); + Console.WriteLine("extra = hidden boxes the pass kept (these only cost draw calls)"); + + if (images) + { + WriteImages(scene, camera, candidates, frustumCount); + } + + return 0; + } + + private delegate long Pass(Scene scene, Camera camera, int[] candidates, int candidateCount, bool[] visible); + + private static Result Measure(string name, Scene scene, Camera camera, int[] candidates, bool[] visible, bool[] truth, long[] pixelsPerBox, long coveredPixels, Pass pass) + { + int candidateCount = Culling.Frustum(scene, camera, candidates); + + for (int i = 0; i < WarmupIterations; i++) + { + pass(scene, camera, candidates, candidateCount, visible); + } + + var samples = new double[MeasuredIterations]; + long rays = 0; + + for (int i = 0; i < MeasuredIterations; i++) + { + long start = Stopwatch.GetTimestamp(); + rays = pass(scene, camera, candidates, candidateCount, visible); + samples[i] = (Stopwatch.GetTimestamp() - start) * 1000.0 / Stopwatch.Frequency; + } + + int visibleCount = 0, falseNegatives = 0, falsePositives = 0; + long missedPixels = 0; + for (int i = 0; i < visible.Length; i++) + { + if (visible[i]) + { + visibleCount++; + if (!truth[i]) + { + falsePositives++; + } + } + else if (truth[i]) + { + falseNegatives++; + missedPixels += pixelsPerBox[i]; + } + } + + Array.Sort(samples); + + return new Result + { + Name = name, + Median = samples[samples.Length / 2], + Mean = samples.Average(), + Min = samples[0], + Max = samples[^1], + Rays = rays, + Visible = visibleCount, + CulledPercent = 100.0 * (scene.BoxCount - visibleCount) / scene.BoxCount, + FalseNegatives = falseNegatives, + FalsePositives = falsePositives, + MissedScreenPercent = coveredPixels > 0 ? 100.0 * missedPixels / coveredPixels : 0.0, + }; + } + + private static void WriteImages(Scene scene, Camera camera, int[] candidates, int candidateCount) + { + const int Width = 960; + const int Height = 540; + + var ids = new uint[Width * Height]; + var seen = new bool[scene.BoxCount]; + Culling.VisibilityBufferSingle(scene, camera, Width, Height, seen, ids); + + var verdict = new bool[scene.BoxCount]; + Culling.PerObjectSingle(scene, camera, candidates, candidateCount, verdict); + + var truth = new bool[scene.BoxCount]; + Culling.VisibilityBufferSingle(scene, camera, TruthWidth, TruthHeight, truth); + + // 1. The scene itself, flat-coloured per object. + var scenePixels = new byte[Width * Height * 3]; + for (int i = 0; i < ids.Length; i++) + { + Colour(ids[i], out byte r, out byte g, out byte b); + scenePixels[(i * 3) + 0] = r; + scenePixels[(i * 3) + 1] = g; + scenePixels[(i * 3) + 2] = b; + } + + Png.Write("scene.png", Width, Height, scenePixels); + + // 2. The same view, coloured by what the per-object pass decided. Red on screen is a + // box the pass discarded while it was in fact visible: that is popping. + var verdictPixels = new byte[Width * Height * 3]; + for (int i = 0; i < ids.Length; i++) + { + uint id = ids[i]; + byte r, g, b; + if (id == Embree_INVALID) + { + r = 24; g = 28; b = 36; + } + else if (verdict[id]) + { + r = 60; g = 190; b = 90; + } + else + { + r = 220; g = 60; b = 60; + } + + verdictPixels[(i * 3) + 0] = r; + verdictPixels[(i * 3) + 1] = g; + verdictPixels[(i * 3) + 2] = b; + } + + Png.Write("verdict.png", Width, Height, verdictPixels); + + // 3. A side view of the grid: what got kept, and what got thrown away. + WriteSlice(scene, camera, verdict, "slice.png"); + + Console.WriteLine(); + Console.WriteLine($"Wrote scene.png, verdict.png and slice.png to {Directory.GetCurrentDirectory()}"); + } + + private const uint Embree_INVALID = uint.MaxValue; + + /// + /// A horizontal slice through the middle layer of the grid, seen from above. Boxes the + /// pass kept are bright, boxes it discarded are dark, and the camera is the cross. + /// + /// + /// One layer, not all ten. Projecting the whole grid onto the ground plane stacks every + /// layer into the same cell, so the picture would show one arbitrary layer's verdict and + /// look like the culling was deciding at random. + /// + private static void WriteSlice(Scene scene, Camera camera, bool[] visible, string path) + { + const int Width = 720; + const int Height = 720; + + float extent = BoxSize * Spacing * (SideCount - 1) * 0.5f; + float span = extent * 3.2f; + + var pixels = new byte[Width * Height * 3]; + for (int i = 0; i < pixels.Length; i += 3) + { + pixels[i] = 18; pixels[i + 1] = 20; pixels[i + 2] = 26; + } + + // Only the middle layer: geomIDs run x fastest, then y, then z. + int layer = SideCount / 2; + int perLayer = SideCount; + + for (int box = 0; box < scene.BoxCount; box++) + { + if ((box / perLayer) % SideCount != layer) + { + continue; + } + + Vector3 lo = scene.Min[box]; + Vector3 hi = scene.Max[box]; + + int x0 = ToPixel(lo.X, span, Width); + int x1 = ToPixel(hi.X, span, Width); + int y0 = ToPixel(-hi.Z, span, Height); + int y1 = ToPixel(-lo.Z, span, Height); + + byte r, g, b; + if (visible[box]) + { + r = 235; g = 235; b = 245; + } + else + { + r = 52; g = 56; b = 68; + } + + for (int y = Math.Max(y0, 0); y <= Math.Min(y1, Height - 1); y++) + { + for (int x = Math.Max(x0, 0); x <= Math.Min(x1, Width - 1); x++) + { + int p = ((y * Width) + x) * 3; + pixels[p] = r; pixels[p + 1] = g; pixels[p + 2] = b; + } + } + } + + int cx = ToPixel(camera.Position.X, span, Width); + int cy = ToPixel(-camera.Position.Z, span, Height); + for (int d = -9; d <= 9; d++) + { + Plot(pixels, Width, Height, cx + d, cy, 255, 170, 40); + Plot(pixels, Width, Height, cx, cy + d, 255, 170, 40); + } + + Png.Write(path, Width, Height, pixels); + } + + private static int ToPixel(float world, float span, int size) => + (int)MathF.Round((world + span) / (span * 2.0f) * size); + + private static void Plot(byte[] pixels, int width, int height, int x, int y, byte r, byte g, byte b) + { + if (x < 0 || y < 0 || x >= width || y >= height) + { + return; + } + + int p = ((y * width) + x) * 3; + pixels[p] = r; pixels[p + 1] = g; pixels[p + 2] = b; + } + + /// A stable, well-spread colour per geomID; grey for "nothing was hit". + private static void Colour(uint id, out byte r, out byte g, out byte b) + { + if (id == Embree_INVALID) + { + r = 24; g = 28; b = 36; + return; + } + + uint h = (id * 2654435761u) ^ (id << 13); + r = (byte)(80 + (h & 0x7F)); + g = (byte)(80 + ((h >> 8) & 0x7F)); + b = (byte)(80 + ((h >> 16) & 0x7F)); + } + + private sealed class Result + { + public string Name; + public double Median; + public double Mean; + public double Min; + public double Max; + public long Rays; + public int Visible; + public double CulledPercent; + public int FalseNegatives; + public int FalsePositives; + public double MissedScreenPercent; + } + } +} diff --git a/OcclusionCulling/README.md b/OcclusionCulling/README.md new file mode 100644 index 0000000..30fa734 --- /dev/null +++ b/OcclusionCulling/README.md @@ -0,0 +1,92 @@ +# OcclusionCulling + +What a CPU occlusion culling pass costs over a thousand objects, with Embree answering the +visibility queries. No shading, no lighting, no shadows: this measures visibility and nothing +else. + +![The scene](docs/scene.png) + +A 10×10×10 grid of boxes — 1,000 objects, 12,000 triangles, one Embree geometry each so every +box has its own `geomID`. The camera sits outside looking in, which is the situation occlusion +culling exists for: the outer shell hides most of the interior. + +## The two passes + +Both run after a frustum pass, which is the order a real engine uses. They answer different +questions and their cost scales with different things. + +**Per-object rays.** Nine sample points per box (eight AABB corners and the centre), one ray +each, stopping at the first sample that reaches the box. Cost scales with the object count. This +is what an engine runs to decide which draw calls to submit. + +**Visibility buffer.** A 320×180 grid of primary rays; whatever geometry they land on is +visible. Cost scales with resolution and does not care how many objects there are. + +Each comes in a single-ray and an 8-wide packet form. + +## Results + +24 logical cores, Embree 4.4.1 built with `EMBREE_MAX_ISA=AVX2`: + +``` +Method median mean rays visible culled miss screen +frustum only 0.004ms 0.004ms 0 1,000 0.0% 0 0.00% +per-object, single ray 0.158ms 0.155ms 7,165 342 65.8% 163 3.07% +per-object, 8-wide packets 0.218ms 0.217ms 9,000 342 65.8% 163 3.07% +visibility buffer 320x180, single ray 0.623ms 0.636ms 57,600 457 54.3% 48 0.16% +visibility buffer 320x180, 8-wide packets 0.626ms 0.636ms 57,600 457 54.3% 48 0.16% +``` + +`miss` counts visible boxes the pass discarded — the ones that would pop. `screen` is how much +of the covered screen area those boxes actually held, which is the number that matters: in a +grid this dense most of what is technically visible is visible through a gap a pixel or two +wide. + +**The per-object pass costs 0.16 ms and removes two thirds of the draw calls.** Against a 16.6 ms +frame that is about 1%, so it pays for itself as soon as the objects it removes cost more than +that to draw. + +![Which boxes survived](docs/verdict.png) + +Green is a box the per-object pass kept, red one it discarded. The red is all slivers showing +through gaps — 163 boxes, but 3% of the screen. + +![A slice through the middle layer](docs/slice.png) + +The middle layer seen from above, camera at the cross. The shell facing the camera survives, the +interior does not. + +## Things worth knowing before copying this + +**Ask the device how wide a packet it supports.** `rtcIntersect16`/`rtcOccluded16` may only be +called when `RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED` says so; calling them anyway is +undefined behaviour, and in practice it corrupts the heap and takes the process down somewhere +unrelated with no hint of the real cause. The binaries this package ships are built with +`EMBREE_MAX_ISA=AVX2`, which tops out at 8 — 16 needs AVX-512. The sample prints the width it +found. + +**Packets are not automatically faster.** Here they are slower for the per-object pass, because +filling eight lanes means giving up the early exit: the moment one sample proves a box visible +the rest are pointless, but the lanes are already committed. 9,000 rays instead of 7,165, and +the SIMD saving does not cover the difference. For the visibility buffer, where all rays are +needed anyway, they come out level. Both results are worth having; neither was obvious in +advance. + +**The obvious formulation of the per-object test is wrong.** Aiming an occlusion ray at a sample +point on a box and stopping just short of it has the box occlude itself: the point is on its +surface, so its own front face is in the way for all but a few silhouette corners. This asks +what the ray hits *first* instead, which costs more per ray and answers the question actually +being asked. + +**Ray structures must be aligned.** `RTCRay8` wants 32 bytes, `RTCRay16` wants 64, and a C# +local guarantees neither. Every buffer here comes from `NativeMemory.AlignedAlloc`. + +## Running it + +```bash +dotnet run --project OcclusionCulling -c Release +``` + +`--images` also writes `scene.png`, `verdict.png` and `slice.png` to the working directory. The +PNG writer is about sixty lines in `Png.cs`, which keeps the sample free of dependencies and +able to run on every RID the binding ships; `System.Drawing` would have pinned it to Windows. diff --git a/OcclusionCulling/Scene.cs b/OcclusionCulling/Scene.cs new file mode 100644 index 0000000..24fe9e5 --- /dev/null +++ b/OcclusionCulling/Scene.cs @@ -0,0 +1,166 @@ +using Evergine.Bindings.Embree; +using System; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace OcclusionCulling +{ + /// + /// A grid of axis-aligned boxes, one Embree geometry each so every box gets its own + /// geomID. That identity is the whole point: occlusion culling answers "which objects do + /// I still have to draw", which needs per-object granularity, not per-triangle. + /// + internal sealed unsafe class Scene : IDisposable + { + private Device device; + + public Scene(int sideCount, float boxSize, float spacing) + { + this.SideCount = sideCount; + this.BoxCount = sideCount * sideCount * sideCount; + this.Min = new Vector3[this.BoxCount]; + this.Max = new Vector3[this.BoxCount]; + + this.device = Embree.NewDevice(null); + if (this.device.IsNull) + { + throw new InvalidOperationException($"rtcNewDevice failed: {Embree.GetDeviceError(Device.Null)}"); + } + + this.Handle = Embree.NewScene(this.device); + + // The fastest traversal configuration: a high-quality static BVH, and none of + // Dynamic, Compact or Robust, each of which trades traversal speed for something + // this benchmark does not need. + Embree.SetSceneFlags(this.Handle, SceneFlags.None); + Embree.SetSceneBuildQuality(this.Handle, BuildQuality.High); + + float half = boxSize * 0.5f; + float step = boxSize * spacing; + float origin = -step * (sideCount - 1) * 0.5f; + + int index = 0; + for (int z = 0; z < sideCount; z++) + { + for (int y = 0; y < sideCount; y++) + { + for (int x = 0; x < sideCount; x++) + { + var center = new Vector3(origin + (x * step), origin + (y * step), origin + (z * step)); + this.Min[index] = center - new Vector3(half); + this.Max[index] = center + new Vector3(half); + this.AddBox(this.Min[index], this.Max[index]); + index++; + } + } + } + + Embree.CommitScene(this.Handle); + + Error error = Embree.GetDeviceError(this.device); + if (error != Error.None) + { + throw new InvalidOperationException($"Embree scene setup failed: {error}"); + } + } + + /// Gets the Embree scene. + public Evergine.Bindings.Embree.Scene Handle { get; } + + /// + /// The widest ray packet this device actually supports. + /// + /// + /// This has to be asked, not assumed. Embree only allows rtcIntersectN/rtcOccludedN when + /// the matching property is set, and calling a wider one anyway is undefined behaviour — + /// in practice it corrupts the heap and takes the process down somewhere unrelated. The + /// binaries this package ships are built with EMBREE_MAX_ISA=AVX2, which tops out at 8; + /// 16 needs AVX-512. + /// + public int MaxPacketWidth => + Embree.GetDeviceProperty(this.device, DeviceProperty.NativeRay16Supported) != 0 ? 16 + : Embree.GetDeviceProperty(this.device, DeviceProperty.NativeRay8Supported) != 0 ? 8 + : Embree.GetDeviceProperty(this.device, DeviceProperty.NativeRay4Supported) != 0 ? 4 + : 1; + + /// Gets the number of boxes per axis. + public int SideCount { get; } + + /// Gets the total number of boxes, which is also the number of geomIDs. + public int BoxCount { get; } + + /// Gets the lower corner of each box's AABB, indexed by geomID. + public Vector3[] Min { get; } + + /// Gets the upper corner of each box's AABB, indexed by geomID. + public Vector3[] Max { get; } + + /// Gets the total triangle count. + public int TriangleCount => this.BoxCount * 12; + + public void Dispose() + { + Embree.ReleaseScene(this.Handle); + Embree.ReleaseDevice(this.device); + } + + /// + /// The eight corners of a box, plus its centre. These are the sample points the + /// per-object method shoots at. + /// + public void GetSamplePoints(int box, Span points) + { + Vector3 lo = this.Min[box]; + Vector3 hi = this.Max[box]; + + points[0] = new Vector3(lo.X, lo.Y, lo.Z); + points[1] = new Vector3(hi.X, lo.Y, lo.Z); + points[2] = new Vector3(lo.X, hi.Y, lo.Z); + points[3] = new Vector3(hi.X, hi.Y, lo.Z); + points[4] = new Vector3(lo.X, lo.Y, hi.Z); + points[5] = new Vector3(hi.X, lo.Y, hi.Z); + points[6] = new Vector3(lo.X, hi.Y, hi.Z); + points[7] = new Vector3(hi.X, hi.Y, hi.Z); + points[8] = (lo + hi) * 0.5f; + } + + private void AddBox(Vector3 lo, Vector3 hi) + { + Geometry geometry = Embree.NewGeometry(this.device, GeometryType.Triangle); + + float* vertices = (float*)Embree.SetNewGeometryBuffer( + geometry, BufferType.Vertex, 0, Format.Float3, 3 * sizeof(float), 8); + + int v = 0; + for (int corner = 0; corner < 8; corner++) + { + vertices[v++] = (corner & 1) == 0 ? lo.X : hi.X; + vertices[v++] = (corner & 2) == 0 ? lo.Y : hi.Y; + vertices[v++] = (corner & 4) == 0 ? lo.Z : hi.Z; + } + + uint* indices = (uint*)Embree.SetNewGeometryBuffer( + geometry, BufferType.Index, 0, Format.Uint3, 3 * sizeof(uint), 12); + + // Corner bit 0 is X, bit 1 is Y, bit 2 is Z, so 0..7 indexes the cube corners. + ReadOnlySpan box = stackalloc uint[36] + { + 0, 2, 1, 1, 2, 3, // -Z + 4, 5, 6, 5, 7, 6, // +Z + 0, 1, 4, 1, 5, 4, // -Y + 2, 6, 3, 3, 6, 7, // +Y + 0, 4, 2, 2, 4, 6, // -X + 1, 3, 5, 3, 7, 5, // +X + }; + + for (int i = 0; i < box.Length; i++) + { + indices[i] = box[i]; + } + + Embree.CommitGeometry(geometry); + Embree.AttachGeometry(this.Handle, geometry); + Embree.ReleaseGeometry(geometry); + } + } +} diff --git a/OcclusionCulling/docs/scene.png b/OcclusionCulling/docs/scene.png new file mode 100644 index 0000000000000000000000000000000000000000..dc2740167dec0aeecbc3143c42d37f00f1ef983b GIT binary patch literal 49477 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 literal 0 HcmV?d00001 diff --git a/OcclusionCulling/docs/slice.png b/OcclusionCulling/docs/slice.png new file mode 100644 index 0000000000000000000000000000000000000000..a35279dff791d717d69867a4eed188970c96a5f3 GIT binary patch literal 21709 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 Date: Tue, 11 Aug 2026 20:12:58 +0200 Subject: [PATCH 2/5] Scatter the boxes at random, with varied sizes A regular grid flatters occlusion culling: every occluder is the same size and sits exactly behind the one in front, which is the easiest case there is. A thousand boxes at random positions with random per-axis sizes gives irregular gaps, and those are what the technique actually has to cope with. The seed is fixed, because the benchmark compares medians between runs and a clock-seeded layout would move the numbers with no way to tell that from a real change. It changes the picture in both directions. There is more mutual occlusion, so the per-object pass now culls 77% rather than 66%. But irregular sizes make nine corner samples a worse proxy for a box, so what it wrongly discards goes from 3% of the screen to 7.5%, and each pass costs about a third more because fewer samples exit early and the BVH is less tidy. The slab view replaces the old middle-layer one, which indexed geomIDs assuming a grid and means nothing now; it takes the boxes whose centre falls in a band around the middle instead. One thing this scene surfaced that the grid did not: the single-ray and 8-wide paths disagree, reproducibly, on two boxes out of a thousand. They are separate kernels inside Embree and they differ on grazing hits. It does not matter for culling, but the packet path is not a drop-in replacement where the answer has to be bit-identical. --- OcclusionCulling/Program.cs | 39 ++++++++------- OcclusionCulling/README.md | 79 ++++++++++++++++++------------ OcclusionCulling/Scene.cs | 61 ++++++++++++++--------- OcclusionCulling/docs/scene.png | Bin 49477 -> 42155 bytes OcclusionCulling/docs/slice.png | Bin 21709 -> 24447 bytes OcclusionCulling/docs/verdict.png | Bin 26236 -> 26127 bytes README.md | 2 +- 7 files changed, 106 insertions(+), 75 deletions(-) diff --git a/OcclusionCulling/Program.cs b/OcclusionCulling/Program.cs index 6a72eb6..19348fa 100644 --- a/OcclusionCulling/Program.cs +++ b/OcclusionCulling/Program.cs @@ -12,9 +12,11 @@ namespace OcclusionCulling /// internal static class Program { - private const int SideCount = 10; // 10^3 = 1000 boxes - private const float BoxSize = 1.0f; - private const float Spacing = 1.8f; // centre-to-centre, in box sizes + private const int BoxCount = 1000; + private const float VolumeExtent = 9.0f; // half the side of the cube they fill + private const float MinBoxSize = 0.4f; + private const float MaxBoxSize = 2.4f; + private const int Seed = 20260811; // fixed, so the scene is the same every run private const int CullWidth = 320; // resolution of the visibility-buffer pass private const int CullHeight = 180; @@ -28,11 +30,11 @@ private static int Main(string[] args) { bool images = args.Contains("--images"); - using var scene = new Scene(SideCount, BoxSize, Spacing); + using var scene = new Scene(BoxCount, VolumeExtent, MinBoxSize, MaxBoxSize, Seed); - // Outside the grid, looking at its centre, close enough that the near faces hide - // most of the interior. That is the situation occlusion culling exists for. - float extent = BoxSize * Spacing * (SideCount - 1) * 0.5f; + // Outside the cloud, looking at its centre, close enough that the near boxes hide + // much of what is behind them. That is the situation occlusion culling exists for. + float extent = VolumeExtent; var camera = new Camera( position: new Vector3(extent * 2.5f, extent * 1.4f, extent * 2.9f), target: Vector3.Zero, @@ -41,7 +43,7 @@ private static int Main(string[] args) near: 0.1f, far: extent * 20.0f); - Console.WriteLine($"Scene : {scene.BoxCount:N0} boxes ({SideCount}x{SideCount}x{SideCount}), {scene.TriangleCount:N0} triangles, one geometry each"); + Console.WriteLine($"Scene : {scene.BoxCount:N0} boxes scattered at random, sizes {MinBoxSize}..{MaxBoxSize}, {scene.TriangleCount:N0} triangles, one geometry each"); Console.WriteLine($"Logical cores : {Environment.ProcessorCount}"); Console.WriteLine($"Widest packet : {scene.MaxPacketWidth} rays (asked of the device, not assumed)"); Console.WriteLine(); @@ -237,21 +239,20 @@ private static void WriteImages(Scene scene, Camera camera, int[] candidates, in private const uint Embree_INVALID = uint.MaxValue; /// - /// A horizontal slice through the middle layer of the grid, seen from above. Boxes the - /// pass kept are bright, boxes it discarded are dark, and the camera is the cross. + /// A horizontal slab through the middle of the cloud, seen from above. Boxes the pass + /// kept are bright, boxes it discarded are dark, and the camera is the cross. /// /// - /// One layer, not all ten. Projecting the whole grid onto the ground plane stacks every - /// layer into the same cell, so the picture would show one arbitrary layer's verdict and - /// look like the culling was deciding at random. + /// A slab rather than everything: projecting the whole cloud onto the ground plane piles + /// boxes from every height into the same pixels, and the picture would look like the + /// culling was deciding at random. /// private static void WriteSlice(Scene scene, Camera camera, bool[] visible, string path) { const int Width = 720; const int Height = 720; - float extent = BoxSize * Spacing * (SideCount - 1) * 0.5f; - float span = extent * 3.2f; + float span = scene.Extent * 3.2f; var pixels = new byte[Width * Height * 3]; for (int i = 0; i < pixels.Length; i += 3) @@ -259,13 +260,13 @@ private static void WriteSlice(Scene scene, Camera camera, bool[] visible, strin pixels[i] = 18; pixels[i + 1] = 20; pixels[i + 2] = 26; } - // Only the middle layer: geomIDs run x fastest, then y, then z. - int layer = SideCount / 2; - int perLayer = SideCount; + // Only boxes whose centre falls in the middle band of the volume. + float band = scene.Extent * 0.18f; for (int box = 0; box < scene.BoxCount; box++) { - if ((box / perLayer) % SideCount != layer) + float centreY = (scene.Min[box].Y + scene.Max[box].Y) * 0.5f; + if (MathF.Abs(centreY) > band) { continue; } diff --git a/OcclusionCulling/README.md b/OcclusionCulling/README.md index 30fa734..558e1c2 100644 --- a/OcclusionCulling/README.md +++ b/OcclusionCulling/README.md @@ -6,9 +6,16 @@ else. ![The scene](docs/scene.png) -A 10×10×10 grid of boxes — 1,000 objects, 12,000 triangles, one Embree geometry each so every -box has its own `geomID`. The camera sits outside looking in, which is the situation occlusion -culling exists for: the outer shell hides most of the interior. +A thousand boxes scattered at random through a cube, each with its own size on each axis, 12,000 +triangles, one Embree geometry per box so every one has its own `geomID`. The layout comes from a +fixed seed, so the scene is the same scene on every run — the benchmark compares medians between +runs and a clock-seeded layout would move the numbers with no way to tell that from a real +change. + +Scattered rather than gridded on purpose. A regular grid flatters occlusion culling: every +occluder is the same size and sits exactly behind the one in front, which is the easiest case +there is. Random sizes and positions give irregular gaps, and those are what the technique +actually has to cope with. ## The two passes @@ -31,30 +38,34 @@ Each comes in a single-ray and an 8-wide packet form. ``` Method median mean rays visible culled miss screen frustum only 0.004ms 0.004ms 0 1,000 0.0% 0 0.00% -per-object, single ray 0.158ms 0.155ms 7,165 342 65.8% 163 3.07% -per-object, 8-wide packets 0.218ms 0.217ms 9,000 342 65.8% 163 3.07% -visibility buffer 320x180, single ray 0.623ms 0.636ms 57,600 457 54.3% 48 0.16% -visibility buffer 320x180, 8-wide packets 0.626ms 0.636ms 57,600 457 54.3% 48 0.16% +per-object, single ray 0.205ms 0.204ms 7,861 229 77.1% 119 7.45% +per-object, 8-wide packets 0.349ms 0.373ms 9,000 231 76.9% 117 7.14% +visibility buffer 320x180, single ray 0.644ms 0.652ms 57,600 316 68.4% 30 0.15% +visibility buffer 320x180, 8-wide packets 0.661ms 0.680ms 57,600 316 68.4% 30 0.15% ``` -`miss` counts visible boxes the pass discarded — the ones that would pop. `screen` is how much -of the covered screen area those boxes actually held, which is the number that matters: in a -grid this dense most of what is technically visible is visible through a gap a pixel or two -wide. +`miss` counts visible boxes the pass discarded — the ones that would pop. `screen` is how much of +the covered screen area those boxes actually held, which is the number that matters: much of what +is technically visible is visible through a gap a pixel or two wide. + +**The per-object pass costs 0.21 ms and removes three quarters of the draw calls.** Against a +16.6 ms frame that is a bit over 1%, so it pays for itself as soon as the objects it removes cost +more than that to draw. -**The per-object pass costs 0.16 ms and removes two thirds of the draw calls.** Against a 16.6 ms -frame that is about 1%, so it pays for itself as soon as the objects it removes cost more than -that to draw. +The two passes trade against each other rather than one being better. Per-object is three times +cheaper and culls more (77% against 68%), but discards boxes holding 7.5% of the screen. The +visibility buffer misses almost nothing — 0.15% — and is the one to reach for if popping matters +more than the milliseconds. ![Which boxes survived](docs/verdict.png) -Green is a box the per-object pass kept, red one it discarded. The red is all slivers showing -through gaps — 163 boxes, but 3% of the screen. +Green is a box the per-object pass kept, red one it discarded. Every red patch is a fragment +showing through a gap between nearer boxes. -![A slice through the middle layer](docs/slice.png) +![A slab through the middle of the cloud](docs/slice.png) -The middle layer seen from above, camera at the cross. The shell facing the camera survives, the -interior does not. +The middle slab seen from above, camera at the cross. Bright boxes survived, dark ones did not: +the culling keeps the side facing the camera and throws away what is behind it. ## Things worth knowing before copying this @@ -65,21 +76,25 @@ unrelated with no hint of the real cause. The binaries this package ships are bu `EMBREE_MAX_ISA=AVX2`, which tops out at 8 — 16 needs AVX-512. The sample prints the width it found. -**Packets are not automatically faster.** Here they are slower for the per-object pass, because -filling eight lanes means giving up the early exit: the moment one sample proves a box visible -the rest are pointless, but the lanes are already committed. 9,000 rays instead of 7,165, and -the SIMD saving does not cover the difference. For the visibility buffer, where all rays are -needed anyway, they come out level. Both results are worth having; neither was obvious in -advance. +**Packets are not automatically faster.** Here they are 70% *slower* for the per-object pass, +because filling eight lanes means giving up the early exit: the moment one sample proves a box +visible the rest are pointless, but the lanes are already committed. 9,000 rays instead of 7,861, +and the SIMD saving does not cover the difference. For the visibility buffer, where all the rays +are needed anyway, the two come out level. Neither result was obvious in advance. + +**The two traversal paths do not agree exactly.** Single-ray finds 229 boxes visible, 8-wide +finds 231, reproducibly. They are separate kernels inside Embree and they disagree on grazing +hits. Two boxes in a thousand does not matter for culling, but it does mean the packet path is +not a drop-in replacement anywhere the answer has to be bit-identical. **The obvious formulation of the per-object test is wrong.** Aiming an occlusion ray at a sample point on a box and stopping just short of it has the box occlude itself: the point is on its -surface, so its own front face is in the way for all but a few silhouette corners. This asks -what the ray hits *first* instead, which costs more per ray and answers the question actually -being asked. +surface, so its own front face is in the way for all but a few silhouette corners. This asks what +the ray hits *first* instead, which costs more per ray and answers the question actually being +asked. -**Ray structures must be aligned.** `RTCRay8` wants 32 bytes, `RTCRay16` wants 64, and a C# -local guarantees neither. Every buffer here comes from `NativeMemory.AlignedAlloc`. +**Ray structures must be aligned.** `RTCRay8` wants 32 bytes, `RTCRay16` wants 64, and a C# local +guarantees neither. Every buffer here comes from `NativeMemory.AlignedAlloc`. ## Running it @@ -88,5 +103,5 @@ dotnet run --project OcclusionCulling -c Release ``` `--images` also writes `scene.png`, `verdict.png` and `slice.png` to the working directory. The -PNG writer is about sixty lines in `Png.cs`, which keeps the sample free of dependencies and -able to run on every RID the binding ships; `System.Drawing` would have pinned it to Windows. +PNG writer is about sixty lines in `Png.cs`, which keeps the sample free of dependencies and able +to run on every RID the binding ships; `System.Drawing` would have pinned it to Windows. diff --git a/OcclusionCulling/Scene.cs b/OcclusionCulling/Scene.cs index 24fe9e5..63e7b60 100644 --- a/OcclusionCulling/Scene.cs +++ b/OcclusionCulling/Scene.cs @@ -14,12 +14,21 @@ internal sealed unsafe class Scene : IDisposable { private Device device; - public Scene(int sideCount, float boxSize, float spacing) + /// How many boxes to scatter. + /// Half the side of the cube they are scattered in. + /// Smallest box edge. + /// Largest box edge. + /// + /// Fixed, and it has to be. The benchmark compares medians between runs, so the scene + /// must be the same scene every time; a clock-seeded layout would move the numbers around + /// and there would be no way to tell that from a real change. + /// + public Scene(int boxCount, float extent, float minSize, float maxSize, int seed) { - this.SideCount = sideCount; - this.BoxCount = sideCount * sideCount * sideCount; - this.Min = new Vector3[this.BoxCount]; - this.Max = new Vector3[this.BoxCount]; + this.BoxCount = boxCount; + this.Extent = extent; + this.Min = new Vector3[boxCount]; + this.Max = new Vector3[boxCount]; this.device = Embree.NewDevice(null); if (this.device.IsNull) @@ -35,24 +44,27 @@ public Scene(int sideCount, float boxSize, float spacing) Embree.SetSceneFlags(this.Handle, SceneFlags.None); Embree.SetSceneBuildQuality(this.Handle, BuildQuality.High); - float half = boxSize * 0.5f; - float step = boxSize * spacing; - float origin = -step * (sideCount - 1) * 0.5f; + // Scattered at random through the volume, each with its own size along each axis, so + // no two boxes are alike and nothing lines up. A regular grid makes occlusion culling + // look better than it is: every occluder is the same size and sits exactly behind the + // one in front, which is the easiest case there is. + var random = new Random(seed); - int index = 0; - for (int z = 0; z < sideCount; z++) + for (int i = 0; i < boxCount; i++) { - for (int y = 0; y < sideCount; y++) - { - for (int x = 0; x < sideCount; x++) - { - var center = new Vector3(origin + (x * step), origin + (y * step), origin + (z * step)); - this.Min[index] = center - new Vector3(half); - this.Max[index] = center + new Vector3(half); - this.AddBox(this.Min[index], this.Max[index]); - index++; - } - } + var centre = new Vector3( + Lerp(random, -extent, extent), + Lerp(random, -extent, extent), + Lerp(random, -extent, extent)); + + var half = new Vector3( + Lerp(random, minSize, maxSize), + Lerp(random, minSize, maxSize), + Lerp(random, minSize, maxSize)) * 0.5f; + + this.Min[i] = centre - half; + this.Max[i] = centre + half; + this.AddBox(this.Min[i], this.Max[i]); } Embree.CommitScene(this.Handle); @@ -83,8 +95,8 @@ public Scene(int sideCount, float boxSize, float spacing) : Embree.GetDeviceProperty(this.device, DeviceProperty.NativeRay4Supported) != 0 ? 4 : 1; - /// Gets the number of boxes per axis. - public int SideCount { get; } + /// Gets half the side of the cube the boxes are scattered in. + public float Extent { get; } /// Gets the total number of boxes, which is also the number of geomIDs. public int BoxCount { get; } @@ -98,6 +110,9 @@ public Scene(int sideCount, float boxSize, float spacing) /// Gets the total triangle count. public int TriangleCount => this.BoxCount * 12; + private static float Lerp(Random random, float min, float max) => + min + ((max - min) * (float)random.NextDouble()); + public void Dispose() { Embree.ReleaseScene(this.Handle); diff --git a/OcclusionCulling/docs/scene.png b/OcclusionCulling/docs/scene.png index dc2740167dec0aeecbc3143c42d37f00f1ef983b..c6f2c164361da139b57d41f8cdc866af60318dce 100644 GIT binary patch literal 42155 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

|g?AKb#E~8#x#AGp1Z1Gm0;4G*$0pb! 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 diff --git a/OcclusionCulling/docs/slice.png b/OcclusionCulling/docs/slice.png index a35279dff791d717d69867a4eed188970c96a5f3..bb06aa5493e87aaa0f401be88b6ee30a229676da 100644 GIT binary patch literal 24447 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 Date: Tue, 11 Aug 2026 20:24:01 +0200 Subject: [PATCH 3/5] Add a scene-size sweep and the scaling chart --sweep repeats the measurement at 10, 50, 100, 200, 500 and 1,000 boxes. The volume grows with the cube root of the count so density stays constant and the curve isolates the object count instead of mixing it with how much the boxes occlude each other. The two families scale differently, which is the reason to keep both. Per-object tracks the object count, 0.009 ms at ten boxes to 0.21 ms at a thousand. The visibility buffer is flat near 0.6 ms whatever the count -- it pays for 57,600 rays and does not care what they hit -- and drifts slightly cheaper as boxes are added, because a denser scene stops rays sooner. Per-object therefore wins comfortably up to a thousand objects, with the crossing somewhere past that. Each size runs in a process of its own. Measuring all six in a row inside one process moved the later numbers by half: the thousand-box scene reports 0.21 ms measured alone and 0.33 ms measured sixth. Every rtcNewDevice brings its own worker threads under EMBREE_TASKING_SYSTEM=INTERNAL, and six devices' worth leaves the machine in a state the first measurement never saw. A sweep exists to show the shape of a curve, so it cannot be built out of numbers that drift with their position in the list. --- OcclusionCulling/Program.cs | 131 ++++++++++++++++++++++++++++-- OcclusionCulling/README.md | 35 ++++++++ OcclusionCulling/docs/scaling.png | Bin 0 -> 119685 bytes 3 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 OcclusionCulling/docs/scaling.png diff --git a/OcclusionCulling/Program.cs b/OcclusionCulling/Program.cs index 19348fa..bbbbaba 100644 --- a/OcclusionCulling/Program.cs +++ b/OcclusionCulling/Program.cs @@ -30,18 +30,28 @@ private static int Main(string[] args) { bool images = args.Contains("--images"); + string sweep = args.FirstOrDefault(a => a.StartsWith("--sweep", StringComparison.Ordinal)); + if (sweep != null) + { + if (sweep.Contains('=')) + { + // A child, measuring exactly one size and printing its row. + Sweep(sweep.Split('=')[1].Split(',').Select(int.Parse).ToArray(), header: false); + } + else + { + SweepInChildProcesses(new[] { 10, 50, 100, 200, 500, 1000 }); + } + + return 0; + } + using var scene = new Scene(BoxCount, VolumeExtent, MinBoxSize, MaxBoxSize, Seed); // Outside the cloud, looking at its centre, close enough that the near boxes hide // much of what is behind them. That is the situation occlusion culling exists for. float extent = VolumeExtent; - var camera = new Camera( - position: new Vector3(extent * 2.5f, extent * 1.4f, extent * 2.9f), - target: Vector3.Zero, - fovDegrees: 55.0f, - aspect: (float)CullWidth / CullHeight, - near: 0.1f, - far: extent * 20.0f); + var camera = MakeCamera(extent); Console.WriteLine($"Scene : {scene.BoxCount:N0} boxes scattered at random, sizes {MinBoxSize}..{MaxBoxSize}, {scene.TriangleCount:N0} triangles, one geometry each"); Console.WriteLine($"Logical cores : {Environment.ProcessorCount}"); @@ -117,6 +127,113 @@ private static int Main(string[] args) return 0; } + ///

+ /// The same measurement at a range of scene sizes, to show how the cost scales. + /// + /// + /// The volume grows with the cube root of the box count, so density stays constant and + /// the camera pulls back with it. Holding the volume fixed instead would vary two things + /// at once — how many objects there are and how much they occlude each other — and the + /// curve would not say which of them moved the cost. + /// + /// + /// Runs each scene size in a process of its own and collects the rows. + /// + /// + /// One process per size, which looks like overkill and is not. Measuring six scenes in a + /// row inside one process moved the later numbers by half: with EMBREE_TASKING_SYSTEM + /// =INTERNAL every rtcNewDevice brings its own worker threads, and six devices' worth of + /// them leaves the machine in a different state from the one the first measurement saw. + /// Measured alone, the thousand-box scene reports 0.21 ms; measured sixth, 0.33 ms. The + /// shape of the curve is the whole point of a sweep, so it cannot be built out of numbers + /// that drift with their position in the list. + /// + private static void SweepInChildProcesses(int[] sizes) + { + Console.WriteLine("Constant density: the volume grows with the cube root of the box count."); + Console.WriteLine("Each size runs in its own process; see the remarks on SweepInChildProcesses."); + Console.WriteLine(); + Console.WriteLine("boxes frustum per-object per-object visbuffer visbuffer culled miss"); + Console.WriteLine(" single 8-packet single 8-packet screen"); + + foreach (int count in sizes) + { + var info = new ProcessStartInfo(Environment.ProcessPath) + { + RedirectStandardOutput = true, + UseShellExecute = false, + }; + + foreach (string argument in Environment.GetCommandLineArgs().Skip(1).Where(a => !a.StartsWith("--sweep", StringComparison.Ordinal))) + { + info.ArgumentList.Add(argument); + } + + info.ArgumentList.Add($"--sweep={count}"); + + using var child = Process.Start(info); + Console.Write(child.StandardOutput.ReadToEnd()); + child.WaitForExit(); + } + } + + private static void Sweep(int[] sizes, bool header) + { + if (header) + { + Console.WriteLine("boxes frustum per-object per-object visbuffer visbuffer culled miss"); + Console.WriteLine(" single 8-packet single 8-packet screen"); + } + + foreach (int count in sizes) + { + float extent = VolumeExtent * MathF.Cbrt(count / (float)BoxCount); + + using var scene = new Scene(count, extent, MinBoxSize, MaxBoxSize, Seed); + var camera = MakeCamera(extent); + + var candidates = new int[count]; + var visible = new bool[count]; + var truth = new bool[count]; + + var truthIds = new uint[TruthWidth * TruthHeight]; + Culling.VisibilityBufferSingle(scene, camera, TruthWidth, TruthHeight, truth, truthIds); + + var pixelsPerBox = new long[count]; + long coveredPixels = 0; + foreach (uint id in truthIds) + { + if (id != Embree_INVALID) + { + pixelsPerBox[id]++; + coveredPixels++; + } + } + + var frustum = Measure("f", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => { Array.Clear(vis); for (int i = 0; i < n; i++) { vis[cand[i]] = true; } return 0; }); + var single = Measure("s", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => Culling.PerObjectSingle(s, c, cand, n, vis)); + var packet = Measure("p", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => Culling.PerObjectPacket(s, c, cand, n, vis)); + var buffer = Measure("b", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => Culling.VisibilityBufferSingle(s, c, CullWidth, CullHeight, vis)); + var bufferPacket = Measure("bp", scene, camera, candidates, visible, truth, pixelsPerBox, coveredPixels, + (s, c, cand, n, vis) => Culling.VisibilityBufferPacket(s, c, CullWidth, CullHeight, vis)); + + Console.WriteLine( + $"{count,5:N0} {frustum.Median,8:F4} {single.Median,11:F4} {packet.Median,11:F4} {buffer.Median,11:F4} {bufferPacket.Median,11:F4} {single.CulledPercent,8:F1}% {single.MissedScreenPercent,6:F2}%"); + } + } + + private static Camera MakeCamera(float extent) => new Camera( + position: new Vector3(extent * 2.5f, extent * 1.4f, extent * 2.9f), + target: Vector3.Zero, + fovDegrees: 55.0f, + aspect: (float)CullWidth / CullHeight, + near: 0.1f, + far: extent * 20.0f); + private delegate long Pass(Scene scene, Camera camera, int[] candidates, int candidateCount, bool[] visible); private static Result Measure(string name, Scene scene, Camera camera, int[] candidates, bool[] visible, bool[] truth, long[] pixelsPerBox, long coveredPixels, Pass pass) diff --git a/OcclusionCulling/README.md b/OcclusionCulling/README.md index 558e1c2..84b2c7c 100644 --- a/OcclusionCulling/README.md +++ b/OcclusionCulling/README.md @@ -57,6 +57,41 @@ cheaper and culls more (77% against 68%), but discards boxes holding 7.5% of the visibility buffer misses almost nothing — 0.15% — and is the one to reach for if popping matters more than the milliseconds. +## How it scales + +`--sweep` repeats the measurement at 10, 50, 100, 200, 500 and 1,000 boxes, growing the volume +with the cube root of the count so density stays constant and only the object count varies. + +``` +boxes frustum per-object per-object visbuffer visbuffer culled miss + single 8-packet single 8-packet screen + 10 0.0001 0.0092 0.0111 0.6522 0.5490 0.0% 0.00% + 50 0.0003 0.0203 0.0241 0.6140 0.5953 42.0% 7.87% + 100 0.0005 0.0258 0.0431 0.6238 0.5538 43.0% 5.93% + 200 0.0010 0.0487 0.0899 0.6219 0.6095 59.5% 4.97% + 500 0.0017 0.1218 0.2098 0.5709 0.5541 72.6% 8.39% +1,000 0.0030 0.2077 0.3377 0.5793 0.5372 77.1% 7.45% +``` + +![Cost against scene size](docs/scaling.png) + +The two families scale differently, which is the whole reason to have both. Per-object cost +tracks the object count, from 0.009 ms at ten boxes to 0.21 ms at a thousand. The visibility +buffer sits flat around 0.6 ms whatever the object count — it is paying for 57,600 rays and does +not care how many things they hit. It even drifts slightly cheaper as boxes are added, because a +denser scene stops rays sooner. + +So per-object wins by a wide margin up to about a thousand objects, and the curves are heading +for a crossing somewhere past that. Below a few hundred boxes it is nearly free: at 200 objects +the pass costs 0.05 ms and removes 60% of the draw calls. + +**Each size runs in its own process, and that is not fussiness.** Measuring all six in a row +inside one process moved the later numbers by half — the thousand-box scene reports 0.21 ms +measured alone and 0.33 ms measured sixth. With `EMBREE_TASKING_SYSTEM=INTERNAL` every +`rtcNewDevice` brings its own worker threads, and six devices' worth leaves the machine in a +different state from the one the first measurement saw. A sweep is about the shape of the curve, +so it cannot be built from numbers that drift with their position in the list. + ![Which boxes survived](docs/verdict.png) Green is a box the per-object pass kept, red one it discarded. Every red patch is a fragment diff --git a/OcclusionCulling/docs/scaling.png b/OcclusionCulling/docs/scaling.png new file mode 100644 index 0000000000000000000000000000000000000000..cc7f43097f10ab0c6618c412fffbe738d4412db6 GIT binary patch literal 119685 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�i{jP5XEmzP z`c96%JEDBtk{mX5b#(3x{5eGIxhf;$3Dy68J^B7}t1813_LoZMtWa*}_I=6=lC0?_ z=G@9z1$t9%BHAXVTn$F?{CE!T=R(db(h1&Qk4)_M+-}{{i0mvZCwKy;(rtYu+w=SW z{gU)X=DpKE4aXdXXr;s*;-%drDGOQ384rk`^Rr{F#&xx>v6d#@@xs1Au0@lKSVod8 zHYXAGpOrBL@IcK_BJPqY22up8Dxb*8JA=9k4o0aasJ;1;%|f(1H0Uq%OK* zt_A^G-_~1Ewh<04XEJ_>);-f39eHQ(yvsJcXuV_4S*^oq4tyIVT6`x+*(s{fr}l4uPuCxaK> z?_~_`R!rxY)!JHtR5Kk(&I*9mxa$npUE_0g6-cK5NkTv%MB-OsUVxw0?`yVXc{POj zPP-yZYx6pvSIY~dX24oxT+^%i-~$5h#7~)E0|}0m+r3ioebOOQ7d%-FtQNUCHqF&9 zfh0p%%kGNc_U|bV`hEn0FVg#jglgvOt3#O5gALAEN8cz0FF(>x^TUgh8Z>|1wq2kH zb#E(^o`l34;1{JOBx&)y#<(Tslu4hO2Mu7!E*ak^XM1|xm{X^sEacf=#D&_+#**~F z4(sjf8+QpKn7~of<*ZMwNw{J-i Date: Tue, 11 Aug 2026 22:05:42 +0200 Subject: [PATCH 4/5] Add the CityCulling sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A city of primitives drawn through the Evergine low-level API, with Embree deciding each frame which objects reach the GPU. At street level, with a camera orbiting at eye height, it issues 56 draw calls instead of 1000: the frustum takes it to 538 and the occlusion pass removes 482 more, which is the part frustum culling cannot do. What it wrongly discards holds 1.56% of the screen. One draw call per object rather than instancing the lot, because that is the number occlusion culling exists to reduce. Per-object data still rides in a per-instance vertex buffer selected with startInstanceLocation: the validation layer rejects updating a buffer inside a render pass, and although DX11 lets it through with a trace, Vulkan and DX12 do not. Three things cost a wrong answer before this worked: Evergine's depth is reversed -- ReadWrite compares GreaterEqual and ClearValue.Default clears depth to 0 -- so the projection needs reverseDepthBuffer: true, which only Evergine.Mathematics offers. The sample keeps System.Numerics for the culling, which only needs the six frustum planes. The Embree geometry is baked into world space by hand and must use the same rotation sense as Evergine's CreateRotationY, which under the row-vector convention is x' = x·cos + z·sin. Baking the textbook form instead rotates what Embree sees away from what the GPU draws, and objects in plain view get discarded with no other symptom. Buildings must not interpenetrate. Placing them at random put the wrongly discarded screen area at 3.83%, because a discarded object growing through a kept one paints over it; rejecting overlapping footprints took it to 0.31% on the same layout, and stopped the debug view from showing red where the culling was right. embree.png is in the captures for that last class of bug: the same view traced against the Embree scene, so any drift between the two representations is visible at a glance. Nothing else in the sample would notice. --- .gitignore | 6 + CityCulling/Camera.cs | 85 +++++++ CityCulling/City.cs | 309 ++++++++++++++++++++++++ CityCulling/CityCulling.csproj | 23 ++ CityCulling/Culling.cs | 130 ++++++++++ CityCulling/MainForm.cs | 89 +++++++ CityCulling/Meshes.cs | 212 +++++++++++++++++ CityCulling/Png.cs | 137 +++++++++++ CityCulling/Program.cs | 423 +++++++++++++++++++++++++++++++++ CityCulling/README.md | 107 +++++++++ CityCulling/Renderer.cs | 350 +++++++++++++++++++++++++++ CityCulling/docs/city.png | Bin 0 -> 51768 bytes CityCulling/docs/culled.png | Bin 0 -> 51951 bytes CityCulling/docs/embree.png | Bin 0 -> 44065 bytes CityCulling/docs/topdown.png | Bin 0 -> 67644 bytes Embree.sln | 14 ++ README.md | 7 + 17 files changed, 1892 insertions(+) create mode 100644 CityCulling/Camera.cs create mode 100644 CityCulling/City.cs create mode 100644 CityCulling/CityCulling.csproj create mode 100644 CityCulling/Culling.cs create mode 100644 CityCulling/MainForm.cs create mode 100644 CityCulling/Meshes.cs create mode 100644 CityCulling/Png.cs create mode 100644 CityCulling/Program.cs create mode 100644 CityCulling/README.md create mode 100644 CityCulling/Renderer.cs create mode 100644 CityCulling/docs/city.png create mode 100644 CityCulling/docs/culled.png create mode 100644 CityCulling/docs/embree.png create mode 100644 CityCulling/docs/topdown.png diff --git a/.gitignore b/.gitignore index 7c6c08c..96ab7b8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,9 @@ HelloEmbree/screenshot.png OcclusionCulling/scene.png OcclusionCulling/verdict.png OcclusionCulling/slice.png + +# Captures the CityCulling sample writes at runtime (docs/ holds the committed ones). +CityCulling/city.png +CityCulling/culled.png +CityCulling/topdown.png +CityCulling/embree.png diff --git a/CityCulling/Camera.cs b/CityCulling/Camera.cs new file mode 100644 index 0000000..50eed10 --- /dev/null +++ b/CityCulling/Camera.cs @@ -0,0 +1,85 @@ +using System; +using System.Numerics; + +namespace CityCulling +{ + /// + /// The camera, in two flavours of maths on purpose. + /// + /// + /// The frustum planes come from a projection, because culling + /// only needs the six planes and does not care about the depth convention. The matrix that + /// goes to the GPU is built separately in the renderer with Evergine.Mathematics and + /// reverseDepthBuffer: true, because Evergine's depth is reversed. Keeping the two + /// apart avoids converting vector types on the hot path, and the two describe the same view + /// volume either way. + /// + internal sealed class Camera + { + private readonly Vector4[] planes = new Vector4[6]; + + public Camera(Vector3 position, Vector3 target, float fovDegrees, float aspect, float near, float far) + { + this.Position = position; + this.Target = target; + this.FovDegrees = fovDegrees; + this.Aspect = aspect; + this.Near = near; + this.Far = far; + + var view = Matrix4x4.CreateLookAt(position, target, Vector3.UnitY); + var projection = Matrix4x4.CreatePerspectiveFieldOfView( + fovDegrees * MathF.PI / 180.0f, aspect, near, far); + + this.ExtractPlanes(view * projection); + } + + public Vector3 Position { get; } + + public Vector3 Target { get; } + + public float FovDegrees { get; } + + public float Aspect { get; } + + public float Near { get; } + + public float Far { get; } + + /// Conservative AABB test: a box straddling a plane counts as inside. + public bool Intersects(in Vector3 min, in Vector3 max) + { + Vector3 centre = (min + max) * 0.5f; + Vector3 extent = (max - min) * 0.5f; + + for (int i = 0; i < 6; i++) + { + Vector4 p = this.planes[i]; + var normal = new Vector3(p.X, p.Y, p.Z); + + if (Vector3.Dot(normal, centre) + p.W + Vector3.Dot(Vector3.Abs(normal), extent) < 0.0f) + { + return false; + } + } + + return true; + } + + private void ExtractPlanes(Matrix4x4 m) + { + this.planes[0] = Normalize(new Vector4(m.M14 + m.M11, m.M24 + m.M21, m.M34 + m.M31, m.M44 + m.M41)); + this.planes[1] = Normalize(new Vector4(m.M14 - m.M11, m.M24 - m.M21, m.M34 - m.M31, m.M44 - m.M41)); + this.planes[2] = Normalize(new Vector4(m.M14 + m.M12, m.M24 + m.M22, m.M34 + m.M32, m.M44 + m.M42)); + this.planes[3] = Normalize(new Vector4(m.M14 - m.M12, m.M24 - m.M22, m.M34 - m.M32, m.M44 - m.M42)); + this.planes[4] = Normalize(new Vector4(m.M13, m.M23, m.M33, m.M43)); + this.planes[5] = Normalize(new Vector4(m.M14 - m.M13, m.M24 - m.M23, m.M34 - m.M33, m.M44 - m.M43)); + } + + private static Vector4 Normalize(Vector4 plane) + { + float length = new Vector3(plane.X, plane.Y, plane.Z).Length(); + return length > 0.0f ? plane / length : plane; + } + } +} diff --git a/CityCulling/City.cs b/CityCulling/City.cs new file mode 100644 index 0000000..52106aa --- /dev/null +++ b/CityCulling/City.cs @@ -0,0 +1,309 @@ +using Evergine.Bindings.Embree; +using System; +using System.Collections.Generic; +using System.Numerics; +using EmbreeScene = Evergine.Bindings.Embree.Scene; + +namespace CityCulling +{ + /// Which mesh an object draws. + internal enum Primitive + { + Box, + Cylinder, + Cone, + Wedge, + } + + /// One drawable object: a primitive, a placement, and a colour. + internal struct CityObject + { + public Primitive Primitive; + public Vector3 Centre; + public Vector3 HalfExtent; + public float Rotation; + public uint Colour; + } + + /// + /// A city of primitives on a ground plane, and the Embree scene that mirrors it. + /// + /// + /// One Embree geometry per object, so every building has its own geomID and the occlusion + /// pass can answer per object rather than per triangle. The triangles go in already + /// transformed: the city never moves, so there is nothing to gain from instancing them on + /// the Embree side, and world-space geometry keeps the culling code free of transforms. + /// + internal sealed unsafe class City : IDisposable + { + /// geomID of the ground plane. It is in the scene so rays can be stopped by it, + /// but it is never culled — it is always drawn. + public const uint GroundGeomID = 0; + + private Device device; + + public City(int objectCount, float blockSize, int blocksPerSide, int seed) + { + this.device = Embree.NewDevice(null); + if (this.device.IsNull) + { + throw new InvalidOperationException($"rtcNewDevice failed: {Embree.GetDeviceError(Device.Null)}"); + } + + this.Handle = Embree.NewScene(this.device); + Embree.SetSceneFlags(this.Handle, SceneFlags.None); + Embree.SetSceneBuildQuality(this.Handle, BuildQuality.High); + + this.Extent = blockSize * blocksPerSide * 0.5f; + + // Ground first, so it takes geomID 0. + this.AddGround(this.Extent * 1.6f); + + var random = new Random(seed); + var objects = new List(objectCount); + var min = new List(objectCount); + var max = new List(objectCount); + + // Blocks with streets between them: buildings cluster inside a block and the gaps + // line up into corridors. At eye level those corridors are the only places you can + // see far, which is exactly the structure that makes occlusion culling worth doing. + float street = blockSize * 0.32f; + float usable = blockSize - street; + + // Footprints already placed, so buildings do not grow through each other. Overlap is + // not just ugly: two objects sharing space fight for the same pixels, and a discarded + // one interpenetrating a kept one paints over it, which reads as a culling error in + // the debug view when the culling was right. + var placed = new List<(Vector3 Centre, float Radius)>(objectCount); + + for (int i = 0; i < objectCount; i++) + { + float footprint = 0.0f; + float height = 0.0f; + Vector3 centre = default; + bool free = false; + + for (int attempt = 0; attempt < 24 && !free; attempt++) + { + int bx = random.Next(blocksPerSide); + int bz = random.Next(blocksPerSide); + + float blockX = (bx - ((blocksPerSide - 1) * 0.5f)) * blockSize; + float blockZ = (bz - ((blocksPerSide - 1) * 0.5f)) * blockSize; + + footprint = Lerp(random, blockSize * 0.10f, blockSize * 0.22f); + height = MathF.Pow(Lerp(random, 0.0f, 1.0f), 2.2f); + height = Lerp2(4.0f, 46.0f, height); + + centre = new Vector3( + blockX + Lerp(random, -usable * 0.5f, usable * 0.5f), + height * 0.5f, + blockZ + Lerp(random, -usable * 0.5f, usable * 0.5f)); + + float radius = footprint * 0.71f; + free = true; + + foreach ((Vector3 other, float otherRadius) in placed) + { + float dx = other.X - centre.X; + float dz = other.Z - centre.Z; + if ((dx * dx) + (dz * dz) < (radius + otherRadius) * (radius + otherRadius)) + { + free = false; + break; + } + } + } + + if (!free) + { + // The blocks are full. Stop rather than start stacking buildings inside one + // another; the object count is a target, not a promise. + break; + } + + placed.Add((centre, footprint * 0.71f)); + + var half = new Vector3(footprint * 0.5f, height * 0.5f, footprint * 0.5f); + + var primitive = (Primitive)random.Next(4); + + // A cool grey-blue palette with the occasional warm one, so the render reads as + // a city rather than confetti. + byte tone = (byte)random.Next(110, 210); + uint colour = random.Next(10) == 0 + ? Pack((byte)(tone + 40), (byte)(tone * 0.72f), (byte)(tone * 0.45f)) + : Pack((byte)(tone * 0.86f), (byte)(tone * 0.92f), tone); + + objects.Add(new CityObject + { + Primitive = primitive, + Centre = centre, + HalfExtent = half, + Rotation = (float)random.NextDouble() * MathF.PI, + Colour = colour, + }); + + // The tight bound of the rotated footprint, not the circumscribed circle. The + // loose one puts every sample corner outside the solid, where the ray sails past + // and hits whatever is behind — which reads as "occluded" for an object in plain + // view. + float c = MathF.Abs(MathF.Cos(objects[i].Rotation)); + float s2 = MathF.Abs(MathF.Sin(objects[i].Rotation)); + float ex = (c * half.X) + (s2 * half.Z); + float ez = (s2 * half.X) + (c * half.Z); + min.Add(new Vector3(centre.X - ex, centre.Y - half.Y, centre.Z - ez)); + max.Add(new Vector3(centre.X + ex, centre.Y + half.Y, centre.Z + ez)); + + this.AddObject(objects[i]); + } + + this.Objects = objects.ToArray(); + this.Min = min.ToArray(); + this.Max = max.ToArray(); + + Embree.CommitScene(this.Handle); + + Error error = Embree.GetDeviceError(this.device); + if (error != Error.None) + { + throw new InvalidOperationException($"Embree scene setup failed: {error}"); + } + } + + public EmbreeScene Handle { get; } + + public CityObject[] Objects { get; } + + /// Lower corner of each object's world AABB, indexed the same as Objects. + public Vector3[] Min { get; } + + /// Upper corner of each object's world AABB. + public Vector3[] Max { get; } + + /// Half the side of the ground the city sits on. + public float Extent { get; } + + public int Count => this.Objects.Length; + + /// + /// geomID of an object. Index 0 is the ground, so the objects start at 1. + /// + public uint GeomIDOf(int index) => (uint)index + 1; + + public void Dispose() + { + Embree.ReleaseScene(this.Handle); + Embree.ReleaseDevice(this.device); + } + + /// + /// Eight corners and the centre: the points the occlusion pass aims at. + /// + /// + /// Pulled 12% in from the AABB corners so they land inside the solid. A ray aimed exactly + /// at a corner grazes the surface at best, and for a cylinder or a cone the corner is + /// outside the shape altogether, so the ray misses and reports whatever stands behind. + /// Inside the volume the ray meets the object's own front face, which is the answer the + /// test is after. + /// + public void GetSamplePoints(int index, Span points) + { + Vector3 centre = (this.Min[index] + this.Max[index]) * 0.5f; + Vector3 lo = centre + ((this.Min[index] - centre) * 0.88f); + Vector3 hi = centre + ((this.Max[index] - centre) * 0.88f); + + points[0] = new Vector3(lo.X, lo.Y, lo.Z); + points[1] = new Vector3(hi.X, lo.Y, lo.Z); + points[2] = new Vector3(lo.X, hi.Y, lo.Z); + points[3] = new Vector3(hi.X, hi.Y, lo.Z); + points[4] = new Vector3(lo.X, lo.Y, hi.Z); + points[5] = new Vector3(hi.X, lo.Y, hi.Z); + points[6] = new Vector3(lo.X, hi.Y, hi.Z); + points[7] = new Vector3(hi.X, hi.Y, hi.Z); + points[8] = (lo + hi) * 0.5f; + } + + private static float Lerp(Random random, float min, float max) => + min + ((max - min) * (float)random.NextDouble()); + + private static float Lerp2(float min, float max, float t) => min + ((max - min) * t); + + private static uint Pack(byte r, byte g, byte b) => + ((uint)r << 16) | ((uint)g << 8) | b; + + private void AddGround(float extent) + { + Geometry geometry = Embree.NewGeometry(this.device, GeometryType.Triangle); + + float* vertices = (float*)Embree.SetNewGeometryBuffer( + geometry, BufferType.Vertex, 0, Format.Float3, 3 * sizeof(float), 4); + + ReadOnlySpan corners = stackalloc float[12] + { + -extent, 0, -extent, + extent, 0, -extent, + extent, 0, extent, + -extent, 0, extent, + }; + + for (int i = 0; i < corners.Length; i++) + { + vertices[i] = corners[i]; + } + + uint* indices = (uint*)Embree.SetNewGeometryBuffer( + geometry, BufferType.Index, 0, Format.Uint3, 3 * sizeof(uint), 2); + + indices[0] = 0; indices[1] = 2; indices[2] = 1; + indices[3] = 0; indices[4] = 3; indices[5] = 2; + + Embree.CommitGeometry(geometry); + Embree.AttachGeometry(this.Handle, geometry); + Embree.ReleaseGeometry(geometry); + } + + private void AddObject(in CityObject o) + { + Mesh mesh = Meshes.Get(o.Primitive); + + Geometry geometry = Embree.NewGeometry(this.device, GeometryType.Triangle); + + float* vertices = (float*)Embree.SetNewGeometryBuffer( + geometry, BufferType.Vertex, 0, Format.Float3, 3 * sizeof(float), (nuint)mesh.Positions.Length); + + float cos = MathF.Cos(o.Rotation); + float sin = MathF.Sin(o.Rotation); + + for (int i = 0; i < mesh.Positions.Length; i++) + { + Vector3 p = mesh.Positions[i] * o.HalfExtent; + // Must match Evergine.Mathematics.Matrix4x4.CreateRotationY exactly. With the + // row-vector convention the shader uses, that is x' = x·cos + z·sin and + // z' = -x·sin + z·cos — the opposite sense to the textbook column-vector form. + // Getting this backwards rotates the geometry Embree sees away from the geometry + // the GPU draws, and the culling then discards objects that are plainly on screen. + var world = new Vector3( + (p.X * cos) + (p.Z * sin), + p.Y, + (-p.X * sin) + (p.Z * cos)) + o.Centre; + + vertices[(i * 3) + 0] = world.X; + vertices[(i * 3) + 1] = world.Y; + vertices[(i * 3) + 2] = world.Z; + } + + uint* indices = (uint*)Embree.SetNewGeometryBuffer( + geometry, BufferType.Index, 0, Format.Uint3, 3 * sizeof(uint), (nuint)(mesh.Indices.Length / 3)); + + for (int i = 0; i < mesh.Indices.Length; i++) + { + indices[i] = mesh.Indices[i]; + } + + Embree.CommitGeometry(geometry); + Embree.AttachGeometry(this.Handle, geometry); + Embree.ReleaseGeometry(geometry); + } + } +} diff --git a/CityCulling/CityCulling.csproj b/CityCulling/CityCulling.csproj new file mode 100644 index 0000000..272ef78 --- /dev/null +++ b/CityCulling/CityCulling.csproj @@ -0,0 +1,23 @@ + + + + WinExe + net10.0-windows + true + True + disable + CityCulling + + + + + + + + + + + + + + diff --git a/CityCulling/Culling.cs b/CityCulling/Culling.cs new file mode 100644 index 0000000..f44b829 --- /dev/null +++ b/CityCulling/Culling.cs @@ -0,0 +1,130 @@ +using Evergine.Bindings.Embree; +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using EmbreeScene = Evergine.Bindings.Embree.Scene; + +namespace CityCulling +{ + /// + /// The occlusion pass: for each object that survives the frustum, decide whether anything + /// in the city hides it. + /// + /// + /// Per-object rays with a single-ray query, which is what the OcclusionCulling benchmark in + /// this repository picked as the winner. On a thousand objects it came out at about 0.2 ms + /// against 0.6 ms for a visibility buffer, and it discarded more. Packets lost here because + /// filling eight lanes means giving up the early exit, and rays aimed at eight different + /// buildings diverge immediately, which is the case packet traversal is worst at. + /// + internal static unsafe class Culling + { + private const int SamplesPerObject = 9; + + /// + /// Frustum stage: fills with surviving indices. + /// + public static int Frustum(City city, Camera camera, int[] candidates) + { + int count = 0; + for (int i = 0; i < city.Count; i++) + { + if (camera.Intersects(city.Min[i], city.Max[i])) + { + candidates[count++] = i; + } + } + + return count; + } + + /// + /// Occlusion stage. Marks for every candidate that at least + /// one sample ray reaches before anything else, and returns how many rays that took. + /// + public static long Occlusion(City city, Camera camera, int[] candidates, int candidateCount, bool[] visible) + { + Array.Clear(visible); + + EmbreeScene handle = city.Handle; + Vector3 origin = camera.Position; + long rays = 0; + object counterLock = new(); + + Parallel.For( + 0, + candidateCount, + () => (Buffer: (IntPtr)NativeMemory.AlignedAlloc((nuint)sizeof(RayHit), 64), Rays: 0L), + (index, _, state) => + { + RayHit* rayhit = (RayHit*)state.Buffer; + + IntersectArguments args; + Embree.InitIntersectArguments(&args); + args.Flags = RayQueryFlags.Coherent; + + int obj = candidates[index]; + uint geomID = city.GeomIDOf(obj); + + Span points = stackalloc Vector3[SamplesPerObject]; + city.GetSamplePoints(obj, points); + + long local = state.Rays; + + for (int s = 0; s < SamplesPerObject; s++) + { + local++; + if (ReachesObject(handle, rayhit, &args, origin, points[s], geomID)) + { + visible[obj] = true; + break; + } + } + + return (state.Buffer, local); + }, + state => + { + NativeMemory.AlignedFree((void*)state.Buffer); + lock (counterLock) + { + rays += state.Rays; + } + }); + + return rays; + } + + /// + /// Whether a ray aimed at reaches + /// before anything else. + /// + /// + /// Closest-hit rather than the cheaper any-hit. An occlusion ray that stops just short of + /// the sample point has the object occlude itself, because the point sits on its own + /// surface — measured on a thousand boxes that called a quarter of the plainly visible + /// ones hidden. + /// + private static bool ReachesObject(EmbreeScene scene, RayHit* rayhit, IntersectArguments* args, Vector3 origin, Vector3 target, uint geomID) + { + Vector3 direction = Vector3.Normalize(target - origin); + + *rayhit = default; + rayhit->Ray.OrgX = origin.X; + rayhit->Ray.OrgY = origin.Y; + rayhit->Ray.OrgZ = origin.Z; + rayhit->Ray.DirX = direction.X; + rayhit->Ray.DirY = direction.Y; + rayhit->Ray.DirZ = direction.Z; + rayhit->Ray.Tnear = 0.0f; + rayhit->Ray.Tfar = float.PositiveInfinity; + rayhit->Ray.Mask = uint.MaxValue; + rayhit->Hit.GeomID = Embree.INVALID_GEOMETRY_ID; + + Embree.Intersect1(scene, rayhit, args); + + return rayhit->Hit.GeomID == geomID; + } + } +} diff --git a/CityCulling/MainForm.cs b/CityCulling/MainForm.cs new file mode 100644 index 0000000..eb342fa --- /dev/null +++ b/CityCulling/MainForm.cs @@ -0,0 +1,89 @@ +using Evergine.Forms; +using System.Drawing; +using System.Windows.Forms; + +namespace CityCulling +{ + /// + /// A plain Windows Forms window with an to render into and a + /// status bar showing what the culling did this frame. + /// + internal sealed class MainForm : Form + { + private readonly ToolStripStatusLabel cullingLabel; + private readonly ToolStripStatusLabel sceneLabel; + + public MainForm(int width, int height) + { + this.Text = "CityCulling - Embree occlusion culling on the Evergine low-level API"; + this.StartPosition = FormStartPosition.CenterScreen; + this.ClientSize = new Size(width, height + 60); + this.MinimumSize = new Size(640, 400); + + this.RenderControl = new EvergineControl { Dock = DockStyle.Fill }; + + this.ShowCulledButton = new ToolStripButton("Show discarded in red") + { + CheckOnClick = true, + DisplayStyle = ToolStripItemDisplayStyle.Text, + }; + + this.PauseButton = new ToolStripButton("Pause camera") + { + CheckOnClick = true, + DisplayStyle = ToolStripItemDisplayStyle.Text, + }; + + this.CaptureButton = new ToolStripButton("Save captures") + { + DisplayStyle = ToolStripItemDisplayStyle.Text, + }; + + var toolStrip = new ToolStrip + { + GripStyle = ToolStripGripStyle.Hidden, + RenderMode = ToolStripRenderMode.System, + }; + + toolStrip.Items.Add(this.PauseButton); + toolStrip.Items.Add(new ToolStripSeparator()); + toolStrip.Items.Add(this.ShowCulledButton); + toolStrip.Items.Add(new ToolStripSeparator()); + toolStrip.Items.Add(this.CaptureButton); + + this.cullingLabel = new ToolStripStatusLabel(string.Empty) + { + Spring = true, + TextAlign = ContentAlignment.MiddleLeft, + }; + + this.sceneLabel = new ToolStripStatusLabel(string.Empty); + + var statusStrip = new StatusStrip(); + statusStrip.Items.Add(this.cullingLabel); + statusStrip.Items.Add(this.sceneLabel); + + this.Controls.Add(this.RenderControl); + this.Controls.Add(toolStrip); + this.Controls.Add(statusStrip); + } + + public EvergineControl RenderControl { get; } + + public ToolStripButton ShowCulledButton { get; } + + public ToolStripButton PauseButton { get; } + + public ToolStripButton CaptureButton { get; } + + public void SetSceneInfo(int objects, int triangles) => + this.sceneLabel.Text = $"{objects:N0} objects | {triangles:N0} triangles"; + + public void SetFrameInfo(int drawn, int total, double cullMs, double frameMs) + { + double culled = 100.0 * (total - drawn) / total; + this.cullingLabel.Text = + $"draw calls {drawn,5:N0} / {total,5:N0} | culled {culled,5:F1}% | culling {cullMs,5:F2} ms | frame {frameMs,5:F2} ms"; + } + } +} diff --git a/CityCulling/Meshes.cs b/CityCulling/Meshes.cs new file mode 100644 index 0000000..cdcb10e --- /dev/null +++ b/CityCulling/Meshes.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace CityCulling +{ + /// A unit mesh: positions in [-1, 1] on each axis, scaled per object. + internal sealed class Mesh + { + public Vector3[] Positions; + public Vector3[] Normals; + public uint[] Indices; + } + + /// + /// The four primitives the city is built from, generated once and shared. + /// + /// + /// Unit-sized and centred, so one mesh serves every object of that kind: the GPU scales it + /// with the per-instance matrix, and the Embree side bakes the same scale into world-space + /// triangles. Faces are not shared between sides, because each needs its own normal for the + /// flat shading to read as edges. + /// + internal static class Meshes + { + private static readonly Dictionary Cache = new(); + + public static Mesh Get(Primitive primitive) + { + if (!Cache.TryGetValue(primitive, out Mesh mesh)) + { + mesh = primitive switch + { + Primitive.Box => Box(), + Primitive.Cylinder => Cylinder(12), + Primitive.Cone => Cone(12), + Primitive.Wedge => Wedge(), + _ => Box(), + }; + + Cache[primitive] = mesh; + } + + return mesh; + } + + private static Mesh Box() + { + var positions = new List(); + var normals = new List(); + var indices = new List(); + + Span faceNormals = stackalloc Vector3[6] + { + new(0, 0, -1), new(0, 0, 1), new(0, -1, 0), + new(0, 1, 0), new(-1, 0, 0), new(1, 0, 0), + }; + + foreach (Vector3 n in faceNormals) + { + // Two vectors spanning the face, chosen so the winding comes out clockwise when + // seen from outside, which is what CullBack expects. + Vector3 u = MathF.Abs(n.Y) > 0.5f ? new Vector3(1, 0, 0) : new Vector3(0, 1, 0); + Vector3 v = Vector3.Cross(n, u); + + uint b = (uint)positions.Count; + positions.Add(n - u - v); + positions.Add(n - u + v); + positions.Add(n + u + v); + positions.Add(n + u - v); + + for (int i = 0; i < 4; i++) + { + normals.Add(n); + } + + indices.Add(b); indices.Add(b + 1); indices.Add(b + 2); + indices.Add(b); indices.Add(b + 2); indices.Add(b + 3); + } + + return Build(positions, normals, indices); + } + + private static Mesh Cylinder(int segments) + { + var positions = new List(); + var normals = new List(); + var indices = new List(); + + for (int i = 0; i < segments; i++) + { + float a0 = i / (float)segments * MathF.Tau; + float a1 = (i + 1) / (float)segments * MathF.Tau; + + var d0 = new Vector3(MathF.Cos(a0), 0, MathF.Sin(a0)); + var d1 = new Vector3(MathF.Cos(a1), 0, MathF.Sin(a1)); + Vector3 n = Vector3.Normalize(d0 + d1); + + uint b = (uint)positions.Count; + positions.Add(new Vector3(d0.X, -1, d0.Z)); + positions.Add(new Vector3(d0.X, 1, d0.Z)); + positions.Add(new Vector3(d1.X, 1, d1.Z)); + positions.Add(new Vector3(d1.X, -1, d1.Z)); + + for (int k = 0; k < 4; k++) + { + normals.Add(n); + } + + indices.Add(b); indices.Add(b + 1); indices.Add(b + 2); + indices.Add(b); indices.Add(b + 2); indices.Add(b + 3); + + // Cap, as a fan around the centre. + uint c = (uint)positions.Count; + positions.Add(new Vector3(0, 1, 0)); + positions.Add(new Vector3(d0.X, 1, d0.Z)); + positions.Add(new Vector3(d1.X, 1, d1.Z)); + normals.Add(Vector3.UnitY); normals.Add(Vector3.UnitY); normals.Add(Vector3.UnitY); + indices.Add(c); indices.Add(c + 2); indices.Add(c + 1); + } + + return Build(positions, normals, indices); + } + + private static Mesh Cone(int segments) + { + var positions = new List(); + var normals = new List(); + var indices = new List(); + + for (int i = 0; i < segments; i++) + { + float a0 = i / (float)segments * MathF.Tau; + float a1 = (i + 1) / (float)segments * MathF.Tau; + + var d0 = new Vector3(MathF.Cos(a0), -1, MathF.Sin(a0)); + var d1 = new Vector3(MathF.Cos(a1), -1, MathF.Sin(a1)); + var apex = new Vector3(0, 1, 0); + + Vector3 n = Vector3.Normalize(Vector3.Cross(d1 - d0, apex - d0)); + + uint b = (uint)positions.Count; + positions.Add(d0); positions.Add(apex); positions.Add(d1); + normals.Add(n); normals.Add(n); normals.Add(n); + indices.Add(b); indices.Add(b + 1); indices.Add(b + 2); + + uint c = (uint)positions.Count; + positions.Add(new Vector3(0, -1, 0)); positions.Add(d0); positions.Add(d1); + normals.Add(-Vector3.UnitY); normals.Add(-Vector3.UnitY); normals.Add(-Vector3.UnitY); + indices.Add(c); indices.Add(c + 1); indices.Add(c + 2); + } + + return Build(positions, normals, indices); + } + + /// A box with a sloped roof — a house shape, to break up the skyline. + private static Mesh Wedge() + { + var positions = new List(); + var normals = new List(); + var indices = new List(); + + void Quad(Vector3 a, Vector3 b, Vector3 c, Vector3 d) + { + Vector3 n = Vector3.Normalize(Vector3.Cross(b - a, c - a)); + uint i0 = (uint)positions.Count; + positions.Add(a); positions.Add(b); positions.Add(c); positions.Add(d); + for (int k = 0; k < 4; k++) { normals.Add(n); } + indices.Add(i0); indices.Add(i0 + 1); indices.Add(i0 + 2); + indices.Add(i0); indices.Add(i0 + 2); indices.Add(i0 + 3); + } + + void Tri(Vector3 a, Vector3 b, Vector3 c) + { + Vector3 n = Vector3.Normalize(Vector3.Cross(b - a, c - a)); + uint i0 = (uint)positions.Count; + positions.Add(a); positions.Add(b); positions.Add(c); + normals.Add(n); normals.Add(n); normals.Add(n); + indices.Add(i0); indices.Add(i0 + 1); indices.Add(i0 + 2); + } + + const float Eaves = 0.45f; + var ridgeBack = new Vector3(0, 1, -1); + var ridgeFront = new Vector3(0, 1, 1); + + var blb = new Vector3(-1, -1, -1); var brb = new Vector3(1, -1, -1); + var blf = new Vector3(-1, -1, 1); var brf = new Vector3(1, -1, 1); + var tlb = new Vector3(-1, Eaves, -1); var trb = new Vector3(1, Eaves, -1); + var tlf = new Vector3(-1, Eaves, 1); var trf = new Vector3(1, Eaves, 1); + + Quad(brb, trb, tlb, blb); // -Z wall + Quad(blf, tlf, trf, brf); // +Z wall + Quad(blb, tlb, tlf, blf); // -X wall + Quad(brf, trf, trb, brb); // +X wall + Quad(blb, blf, brf, brb); // floor + Quad(tlb, ridgeBack, ridgeFront, tlf); // -X roof slope + Quad(trf, ridgeFront, ridgeBack, trb); // +X roof slope + Tri(tlb, trb, ridgeBack); // back gable + Tri(trf, tlf, ridgeFront); // front gable + + return Build(positions, normals, indices); + } + + private static Mesh Build(List positions, List normals, List indices) => + new() + { + Positions = positions.ToArray(), + Normals = normals.ToArray(), + Indices = indices.ToArray(), + }; + } +} diff --git a/CityCulling/Png.cs b/CityCulling/Png.cs new file mode 100644 index 0000000..8b40aa7 --- /dev/null +++ b/CityCulling/Png.cs @@ -0,0 +1,137 @@ +using System; +using System.IO; +using System.IO.Compression; + +namespace CityCulling +{ + /// + /// A minimal PNG writer, so the sample stays dependency-free and runs on every RID the + /// binding ships. System.Drawing would not do: it is Windows-only on modern .NET. + /// + internal static class Png + { + /// + /// Writes an RGB image. is three bytes per pixel, row-major. + /// + public static void Write(string path, int width, int height, byte[] rgb) + { + // PNG wants a filter byte at the start of every scanline; 0 means "no filter". + var raw = new byte[height * ((width * 3) + 1)]; + for (int y = 0; y < height; y++) + { + int source = y * width * 3; + int destination = y * ((width * 3) + 1); + raw[destination] = 0; + Array.Copy(rgb, source, raw, destination + 1, width * 3); + } + + using var file = File.Create(path); + file.Write(new byte[] { 0x89, (byte)'P', (byte)'N', (byte)'G', 0x0D, 0x0A, 0x1A, 0x0A }); + + var header = new byte[13]; + WriteBigEndian(header, 0, (uint)width); + WriteBigEndian(header, 4, (uint)height); + header[8] = 8; // bit depth + header[9] = 2; // colour type: truecolour + WriteChunk(file, "IHDR", header); + + WriteChunk(file, "IDAT", Deflate(raw)); + WriteChunk(file, "IEND", Array.Empty()); + } + + /// + /// zlib stream: a two-byte header, raw deflate, and an Adler-32 of the uncompressed + /// data. DeflateStream produces the middle part; the wrapper has to be added by hand + /// because ZLibStream's header bytes are not what every decoder expects from a PNG. + /// + private static byte[] Deflate(byte[] data) + { + using var output = new MemoryStream(); + output.WriteByte(0x78); // CM = deflate, CINFO = 32K window + output.WriteByte(0x01); // no preset dictionary, fastest compression + + using (var deflate = new DeflateStream(output, CompressionLevel.Fastest, leaveOpen: true)) + { + deflate.Write(data, 0, data.Length); + } + + uint adler = Adler32(data); + output.WriteByte((byte)(adler >> 24)); + output.WriteByte((byte)(adler >> 16)); + output.WriteByte((byte)(adler >> 8)); + output.WriteByte((byte)adler); + + return output.ToArray(); + } + + private static void WriteChunk(Stream stream, string type, byte[] data) + { + var length = new byte[4]; + WriteBigEndian(length, 0, (uint)data.Length); + stream.Write(length); + + var payload = new byte[4 + data.Length]; + for (int i = 0; i < 4; i++) + { + payload[i] = (byte)type[i]; + } + + Array.Copy(data, 0, payload, 4, data.Length); + stream.Write(payload); + + var crc = new byte[4]; + WriteBigEndian(crc, 0, Crc32(payload)); + stream.Write(crc); + } + + private static void WriteBigEndian(byte[] buffer, int offset, uint value) + { + buffer[offset + 0] = (byte)(value >> 24); + buffer[offset + 1] = (byte)(value >> 16); + buffer[offset + 2] = (byte)(value >> 8); + buffer[offset + 3] = (byte)value; + } + + private static uint Adler32(byte[] data) + { + uint a = 1, b = 0; + foreach (byte value in data) + { + a = (a + value) % 65521; + b = (b + a) % 65521; + } + + return (b << 16) | a; + } + + private static readonly uint[] CrcTable = BuildCrcTable(); + + private static uint[] BuildCrcTable() + { + var table = new uint[256]; + for (uint n = 0; n < 256; n++) + { + uint c = n; + for (int k = 0; k < 8; k++) + { + c = (c & 1) != 0 ? 0xEDB88320u ^ (c >> 1) : c >> 1; + } + + table[n] = c; + } + + return table; + } + + private static uint Crc32(byte[] data) + { + uint c = 0xFFFFFFFFu; + foreach (byte value in data) + { + c = CrcTable[(c ^ value) & 0xFF] ^ (c >> 8); + } + + return c ^ 0xFFFFFFFFu; + } + } +} diff --git a/CityCulling/Program.cs b/CityCulling/Program.cs new file mode 100644 index 0000000..c91b163 --- /dev/null +++ b/CityCulling/Program.cs @@ -0,0 +1,423 @@ +using Evergine.Common.Graphics; +using Evergine.DirectX11; +using Evergine.Forms; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using EvergineMath = Evergine.Mathematics; +using Vector3 = System.Numerics.Vector3; + +namespace CityCulling +{ + /// + /// A city of primitives drawn with the Evergine low-level API, with Embree deciding which + /// objects reach the GPU. + /// + internal static class Program + { + private const uint Width = 1280; + private const uint Height = 720; + + private const int ObjectCount = 1000; + private const float BlockSize = 34.0f; + private const int BlocksPerSide = 15; + private const int Seed = 20260811; + + private const float EyeHeight = 2.2f; // street level, against buildings 4 to 46 tall + private const float OrbitRadius = 0.62f; // as a fraction of the city half-extent + private const float CaptureAngle = 0.9f; // fixed, so the captures are reproducible + + private static GraphicsContext graphicsContext; + private static SwapChain swapChain; + private static CommandQueue commandQueue; + private static MainForm form; + private static City city; + private static Renderer renderer; + + private static int[] candidates; + private static bool[] visible; + private static bool[] everything; + + private static Stopwatch clock; + private static float cameraAngle = CaptureAngle; + private static bool captureRequested; + private static bool exitAfterCapture; + private static string outputDirectory; + private static int lastCandidateCount; + private static double lastMissedScreen; + + [STAThread] + private static int Main(string[] args) + { + bool capture = args.Contains("--capture"); + exitAfterCapture = args.Contains("--exit"); + captureRequested = capture; + + outputDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..")); + + System.Windows.Forms.Application.EnableVisualStyles(); + System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false); + + form = new MainForm((int)Width, (int)Height); + form.CaptureButton.Click += (s, e) => captureRequested = true; + form.CreateControl(); + + graphicsContext = new DX11GraphicsContext(); + graphicsContext.CreateDevice(); + + var swapChainDescription = new SwapChainDescription() + { + Width = (uint)form.RenderControl.ClientSize.Width, + Height = (uint)form.RenderControl.ClientSize.Height, + SurfaceInfo = new SurfaceInfo(form.RenderControl.Handle, SurfaceInfo.SurfaceTypes.Forms), + ColorTargetFormat = PixelFormat.R8G8B8A8_UNorm, + ColorTargetFlags = TextureFlags.RenderTarget | TextureFlags.ShaderResource, + DepthStencilTargetFormat = PixelFormat.D24_UNorm_S8_UInt, + DepthStencilTargetFlags = TextureFlags.DepthStencil, + SampleCount = TextureSampleCount.None, + IsWindowed = true, + RefreshRate = 60, + }; + + swapChain = graphicsContext.CreateSwapChain(swapChainDescription); + swapChain.VerticalSync = true; + + var windowSystem = new FormsWindowsSystem { AutoRegisterWindow = false }; + windowSystem.RegisterLoopThreadControl(form); + windowSystem.Run(Load, Draw); + + return 0; + } + + private static void Load() + { + city = new City(ObjectCount, BlockSize, BlocksPerSide, Seed); + renderer = new Renderer(graphicsContext, city, swapChain.FrameBuffer); + + candidates = new int[city.Count]; + visible = new bool[city.Count]; + everything = new bool[city.Count]; + Array.Fill(everything, true); + + commandQueue = graphicsContext.Factory.CreateCommandQueue(); + clock = Stopwatch.StartNew(); + + int triangles = city.Objects.Sum(o => Meshes.Get(o.Primitive).Indices.Length / 3) + 2; + form.SetSceneInfo(city.Count, triangles); + } + + private static void Draw() + { + long frameStart = Stopwatch.GetTimestamp(); + + if (!form.PauseButton.Checked && !captureRequested) + { + cameraAngle = CaptureAngle + ((float)clock.Elapsed.TotalSeconds * 0.16f); + } + + uint width = (uint)Math.Max(form.RenderControl.ClientSize.Width, 1); + uint height = (uint)Math.Max(form.RenderControl.ClientSize.Height, 1); + + Camera camera = MakeCamera(cameraAngle, (float)width / height); + + // The culling pass: frustum, then Embree occlusion. This is the whole point of the + // sample and the only part that is measured. + long cullStart = Stopwatch.GetTimestamp(); + int candidateCount = Culling.Frustum(city, camera, candidates); + lastCandidateCount = candidateCount; + Culling.Occlusion(city, camera, candidates, candidateCount, visible); + double cullMs = Milliseconds(Stopwatch.GetTimestamp() - cullStart); + + swapChain.InitFrame(); + + var viewProjection = ViewProjection(camera); + var light = new EvergineMath.Vector3(-0.42f, -0.78f, -0.46f); + light.Normalize(); + + var commandBuffer = commandQueue.CommandBuffer(); + commandBuffer.Begin(); + commandBuffer.SetViewports(new[] { new Viewport(0, 0, width, height) }); + commandBuffer.SetScissorRectangles(new[] { new EvergineMath.Rectangle(0, 0, (int)width, (int)height) }); + + int drawn = renderer.Draw(commandBuffer, city, viewProjection, light, visible, form.ShowCulledButton.Checked); + + commandBuffer.End(); + commandBuffer.Commit(); + commandQueue.Submit(); + commandQueue.WaitIdle(); + + if (captureRequested) + { + captureRequested = false; + WriteCaptures(camera, viewProjection, light, width, height); + + if (exitAfterCapture) + { + Environment.Exit(0); + } + } + + swapChain.Present(); + + form.SetFrameInfo(drawn, city.Count + 1, cullMs, Milliseconds(Stopwatch.GetTimestamp() - frameStart)); + } + + /// + /// The camera orbits the city centre at street level, looking horizontally across it. + /// + /// + /// The eye height is the whole reason this scene culls well. Lift it above the rooftops + /// and almost everything is visible at once; at 2.2 units, with buildings from 4 to 46, + /// the first row of facades hides most of what is behind it. + /// + private static Camera MakeCamera(float angle, float aspect) + { + float radius = city.Extent * OrbitRadius; + var position = new Vector3(MathF.Cos(angle) * radius, EyeHeight, MathF.Sin(angle) * radius); + var target = new Vector3(MathF.Cos(angle + 2.2f) * radius * 0.35f, EyeHeight * 2.4f, MathF.Sin(angle + 2.2f) * radius * 0.35f); + + return new Camera(position, target, 62.0f, aspect, 0.25f, city.Extent * 6.0f); + } + + /// + /// The matrix that goes to the GPU, built with Evergine.Mathematics because Evergine's + /// depth is reversed and only its projection takes reverseDepthBuffer. + /// + private static EvergineMath.Matrix4x4 ViewProjection(Camera camera) + { + var view = EvergineMath.Matrix4x4.CreateLookAt( + new EvergineMath.Vector3(camera.Position.X, camera.Position.Y, camera.Position.Z), + new EvergineMath.Vector3(camera.Target.X, camera.Target.Y, camera.Target.Z), + EvergineMath.Vector3.Up); + + var projection = EvergineMath.Matrix4x4.CreatePerspectiveFieldOfView( + camera.FovDegrees * MathF.PI / 180.0f, camera.Aspect, camera.Near, camera.Far, reverseDepthBuffer: true); + + return view * projection; + } + + private static double Milliseconds(long ticks) => ticks * 1000.0 / Stopwatch.Frequency; + + /// + /// Three views of the same frame: what was drawn, what was thrown away, and the whole + /// city from above so the occlusion shadows behind each building are visible. + /// + private static void WriteCaptures(Camera camera, EvergineMath.Matrix4x4 viewProjection, EvergineMath.Vector3 light, uint width, uint height) + { + var lightForTopDown = new EvergineMath.Vector3(-0.35f, -0.9f, -0.25f); + lightForTopDown.Normalize(); + + RenderTo(viewProjection, light, visible, drawCulled: false, width, height, "city.png"); + RenderTo(viewProjection, light, visible, drawCulled: true, width, height, "culled.png"); + RenderTo(TopDown(camera), lightForTopDown, visible, drawCulled: true, width, height, "topdown.png", CameraMarkers(camera)); + RayTraceEmbree(camera, width, height, "embree.png"); + + int visibleCount = 0; + for (int i = 0; i < visible.Length; i++) + { + if (visible[i]) { visibleCount++; } + } + + Console.WriteLine($"objects {city.Count}, frustum candidates {lastCandidateCount}, visible {visibleCount}, culled {100.0 * (city.Count - visibleCount) / city.Count:F1}%"); + Console.WriteLine($"screen area held by discarded objects (from Embree's own geometry): {lastMissedScreen:F2}%"); + Console.WriteLine($"Wrote city.png, culled.png, topdown.png and embree.png to {outputDirectory}"); + } + + /// + /// The same view, but traced against the Embree scene and coloured per geomID. + /// + /// + /// A diagnostic, not a feature. The culling can only be as right as the agreement between + /// the triangles the GPU draws and the triangles Embree holds, and nothing else in the + /// sample would notice if the two drifted apart: the render would look fine and objects + /// would simply be culled for no visible reason. Put this next to city.png and any + /// disagreement is obvious. + /// + private static unsafe void RayTraceEmbree(Camera camera, uint width, uint height, string fileName) + { + var pixels = new byte[width * height * 3]; + var counters = new int[2]; // 0 = pixels on objects, 1 = pixels on discarded objects + + Vector3 forward = Vector3.Normalize(camera.Target - camera.Position); + Vector3 right = Vector3.Normalize(Vector3.Cross(forward, Vector3.UnitY)); + Vector3 up = Vector3.Cross(right, forward); + float tanHalf = MathF.Tan(camera.FovDegrees * MathF.PI / 180.0f * 0.5f); + + System.Threading.Tasks.Parallel.For( + 0, + (int)height, + () => (IntPtr)System.Runtime.InteropServices.NativeMemory.AlignedAlloc((nuint)sizeof(Evergine.Bindings.Embree.RayHit), 64), + (y, _, buffer) => + { + var rayhit = (Evergine.Bindings.Embree.RayHit*)buffer; + Evergine.Bindings.Embree.IntersectArguments args; + Evergine.Bindings.Embree.Embree.InitIntersectArguments(&args); + + for (int x = 0; x < width; x++) + { + float ndcX = (((x + 0.5f) / width * 2.0f) - 1.0f) * tanHalf * camera.Aspect; + float ndcY = (1.0f - ((y + 0.5f) / height * 2.0f)) * tanHalf; + Vector3 direction = Vector3.Normalize(forward + (right * ndcX) + (up * ndcY)); + + *rayhit = default; + rayhit->Ray.OrgX = camera.Position.X; + rayhit->Ray.OrgY = camera.Position.Y; + rayhit->Ray.OrgZ = camera.Position.Z; + rayhit->Ray.DirX = direction.X; + rayhit->Ray.DirY = direction.Y; + rayhit->Ray.DirZ = direction.Z; + rayhit->Ray.Tnear = 0.0f; + rayhit->Ray.Tfar = float.PositiveInfinity; + rayhit->Ray.Mask = uint.MaxValue; + rayhit->Hit.GeomID = Evergine.Bindings.Embree.Embree.INVALID_GEOMETRY_ID; + + Evergine.Bindings.Embree.Embree.Intersect1(city.Handle, rayhit, &args); + + uint id = rayhit->Hit.GeomID; + int p = (int)(((y * width) + x) * 3); + + if (id == Evergine.Bindings.Embree.Embree.INVALID_GEOMETRY_ID) + { + pixels[p] = 100; pixels[p + 1] = 140; pixels[p + 2] = 240; + } + else if (id == City.GroundGeomID) + { + pixels[p] = 52; pixels[p + 1] = 54; pixels[p + 2] = 60; + } + else + { + // Green when the culling kept it, red when it did not: the same verdict + // as culled.png, but on Embree's own geometry. + bool kept = visible[id - 1]; + if (!kept) { System.Threading.Interlocked.Increment(ref counters[1]); } + System.Threading.Interlocked.Increment(ref counters[0]); + pixels[p] = (byte)(kept ? 70 : 215); + pixels[p + 1] = (byte)(kept ? 190 : 55); + pixels[p + 2] = (byte)(kept ? 95 : 55); + } + } + + return buffer; + }, + buffer => System.Runtime.InteropServices.NativeMemory.AlignedFree((void*)buffer)); + + lastMissedScreen = counters[0] > 0 ? 100.0 * counters[1] / counters[0] : 0.0; + Png.Write(Path.Combine(outputDirectory, fileName), (int)width, (int)height, pixels); + } + + private static EvergineMath.Matrix4x4 TopDown(Camera camera) + { + float span = city.Extent * 1.15f; + + var view = EvergineMath.Matrix4x4.CreateLookAt( + new EvergineMath.Vector3(0, city.Extent * 3.0f, 0.01f), + EvergineMath.Vector3.Zero, + EvergineMath.Vector3.Up); + + var projection = EvergineMath.Matrix4x4.CreateOrthographic( + span * 2.0f * ((float)Width / Height), span * 2.0f, 0.1f, city.Extent * 8.0f, reverseDepthBuffer: true); + + return view * projection; + } + + /// + /// The camera and its two horizontal frustum edges, as boxes, so the top-down view shows + /// where the viewer is and which wedge of the city it can see at all. + /// + private static System.Collections.Generic.List<(EvergineMath.Matrix4x4 World, EvergineMath.Vector4 Colour)> CameraMarkers(Camera camera) + { + var markers = new System.Collections.Generic.List<(EvergineMath.Matrix4x4, EvergineMath.Vector4)>(); + var amber = new EvergineMath.Vector4(1.0f, 0.72f, 0.16f, 1.0f); + + float marker = city.Extent * 0.02f; + markers.Add(( + EvergineMath.Matrix4x4.CreateScale(marker, marker * 8.0f, marker) * + EvergineMath.Matrix4x4.CreateTranslation(camera.Position.X, marker * 8.0f, camera.Position.Z), + amber)); + + Vector3 forward = Vector3.Normalize(camera.Target - camera.Position); + Vector3 right = Vector3.Normalize(Vector3.Cross(forward, Vector3.UnitY)); + float tanHalf = MathF.Tan(camera.FovDegrees * MathF.PI / 180.0f * 0.5f) * camera.Aspect; + float length = city.Extent * 2.2f; + + foreach (float side in new[] { -1.0f, 1.0f }) + { + Vector3 edge = Vector3.Normalize(forward + (right * tanHalf * side)); + Vector3 mid = camera.Position + (edge * length * 0.5f); + float yaw = MathF.Atan2(edge.X, edge.Z); + + markers.Add(( + EvergineMath.Matrix4x4.CreateScale(marker * 0.22f, marker * 0.22f, length * 0.5f) * + EvergineMath.Matrix4x4.CreateRotationY(yaw) * + EvergineMath.Matrix4x4.CreateTranslation(mid.X, marker, mid.Z), + amber)); + } + + return markers; + } + + private static unsafe void RenderTo(EvergineMath.Matrix4x4 viewProjection, EvergineMath.Vector3 light, bool[] set, bool drawCulled, uint width, uint height, string fileName, System.Collections.Generic.List<(EvergineMath.Matrix4x4 World, EvergineMath.Vector4 Colour)> markers = null) + { + var commandBuffer = commandQueue.CommandBuffer(); + commandBuffer.Begin(); + commandBuffer.SetViewports(new[] { new Viewport(0, 0, width, height) }); + commandBuffer.SetScissorRectangles(new[] { new EvergineMath.Rectangle(0, 0, (int)width, (int)height) }); + renderer.Draw(commandBuffer, city, viewProjection, light, set, drawCulled, markers); + commandBuffer.End(); + commandBuffer.Commit(); + commandQueue.Submit(); + commandQueue.WaitIdle(); + + SaveColorTarget(Path.Combine(outputDirectory, fileName), width, height); + } + + /// + /// Copies the swapchain colour target into a staging texture and writes it out — the same + /// staging plus MapMemory pattern Evergine's own SnapShoter uses. + /// + private static unsafe void SaveColorTarget(string path, uint width, uint height) + { + Texture source = swapChain.FrameBuffer.ColorTargets[0].Texture; + + var stagingDescription = source.Description; + stagingDescription.Flags = TextureFlags.None; + stagingDescription.CpuAccess = ResourceCpuAccess.Read; + stagingDescription.Usage = ResourceUsage.Staging; + var staging = graphicsContext.Factory.CreateTexture(ref stagingDescription); + + var commandBuffer = commandQueue.CommandBuffer(); + commandBuffer.Begin(); + commandBuffer.CopyTextureDataTo(source, staging); + commandBuffer.End(); + commandBuffer.Commit(); + commandQueue.Submit(); + commandQueue.WaitIdle(); + + MappedResource mapped = graphicsContext.MapMemory(staging, MapMode.Read); + + try + { + var pixels = new byte[width * height * 3]; + for (int y = 0; y < height; y++) + { + byte* row = (byte*)mapped.Data + (y * mapped.RowPitch); + for (int x = 0; x < width; x++) + { + int destination = (int)(((y * width) + x) * 3); + pixels[destination + 0] = row[(x * 4) + 0]; + pixels[destination + 1] = row[(x * 4) + 1]; + pixels[destination + 2] = row[(x * 4) + 2]; + } + } + + Png.Write(path, (int)width, (int)height, pixels); + } + finally + { + graphicsContext.UnmapMemory(staging); + staging.Dispose(); + } + } + } +} diff --git a/CityCulling/README.md b/CityCulling/README.md new file mode 100644 index 0000000..e0b9adc --- /dev/null +++ b/CityCulling/README.md @@ -0,0 +1,107 @@ +# CityCulling + +A city of primitives drawn with the **Evergine low-level graphics API**, with **Embree deciding +which objects reach the GPU**. The GPU draws; the CPU works out what is worth drawing. + +![The city from street level](docs/city.png) + +A thousand buildings — boxes, cylinders, cones and gabled wedges — laid out in blocks with +streets between them, on a ground plane, and a camera orbiting at **street level**. The eye +height is the whole point: at 2.2 units against buildings 4 to 46 tall, the first row of facades +hides nearly everything behind it. Lift the camera above the rooftops and there is almost +nothing left to cull. + +## What it does per frame + +1. **Frustum**, six planes against each object's world AABB. +2. **Occlusion with Embree**: nine sample points per surviving object, one closest-hit ray each, + and the object is visible if any ray reaches it before anything else. Early exit on the first + sample that gets through. +3. **One draw call per visible object.** + +The occlusion strategy is the winner from the +[OcclusionCulling](../OcclusionCulling/README.md) benchmark in this repository: per-object rays, +single-ray queries. There it came out three times cheaper than a visibility buffer and discarded +more; packets lost because filling eight lanes gives up the early exit and rays aimed at eight +different buildings diverge immediately. + +## Results at the capture angle + +``` +objects 1000, frustum candidates 538, visible 56, culled 94.4% +screen area held by discarded objects: 1.56% +``` + +**56 draw calls instead of 1000.** The frustum alone gets it to 538 — at street level, half the +city is behind you. Embree removes 482 more, which is the part frustum culling cannot do. + +![What the culling discarded](docs/culled.png) + +The same frame with everything drawn and the discarded objects in red. Red on screen is a +mistake, and what is left is slivers between buildings: 1.56% of the covered screen area. + +![The city from above](docs/topdown.png) + +From above, with the camera in amber and its two frustum edges. The kept objects are the pale +wedge just in front of the camera; everything beyond the first row of facades is red. That +narrow wedge is what 94% culling looks like. + +## Things worth knowing before copying this + +**Evergine's depth is reversed.** `DepthStencilStates.ReadWrite` compares `GreaterEqual` and +`ClearValue.Default` clears depth to 0, so the projection has to be built with +`Matrix4x4.CreatePerspectiveFieldOfView(..., reverseDepthBuffer: true)` from +`Evergine.Mathematics` — `System.Numerics` has no such parameter. Get it wrong and the scene is +empty or inside out, which looks exactly like a culling bug and is not one. The sample uses +Evergine.Mathematics for the matrices that go to the GPU and System.Numerics for the culling, +which only needs the six frustum planes and does not care about the depth convention. + +**Rotations must match on both sides, and the sense is not the textbook one.** Evergine's +`CreateRotationY` with the row-vector convention the shader uses gives `x' = x·cos + z·sin` and +`z' = -x·sin + z·cos`. The Embree geometry is baked into world space by hand, so it has to use +that exact form. Baking the opposite sense rotates the geometry Embree sees away from the +geometry the GPU draws, and the culling then discards objects that are plainly on screen — with +no other symptom. + +**You cannot update a buffer inside a render pass.** `ValidationLayer` rejects it, and while DX11 +lets it through with a trace, Vulkan and DX12 do not. That is why per-object data rides in a +per-instance vertex buffer selected with `startInstanceLocation` rather than a constant buffer +rewritten between draws. + +**Do not let the buildings overlap.** The first version placed them at random and let them +interpenetrate; that put the wrongly-discarded screen area at 3.83%, because a discarded object +growing through a kept one paints over it. Rejecting overlapping footprints took it to 0.31% on +the same layout. Interpenetration also makes the debug view lie: it shows red where the culling +was right. + +**Sample points go inside the object, not on its bounding box.** A ray aimed at an AABB corner +grazes the surface at best, and for a cylinder or a cone the corner is outside the shape +entirely, so the ray sails past and reports whatever stands behind. The points here are pulled +12% in from the corners. + +## `embree.png`, and why it exists + +![The same view traced against the Embree scene](docs/embree.png) + +The same view, traced against the Embree scene and coloured by verdict. It is a diagnostic, not +a feature: the culling can only be as correct as the agreement between the triangles the GPU +draws and the triangles Embree holds, and **nothing else in the sample would notice if the two +drifted apart**. The render would look right and objects would simply vanish for no reason. Put +this next to `city.png` and a disagreement is obvious in a second — it is what found the rotation +bug above. + +It also produces the accuracy number, measured on Embree's own geometry rather than on anything +the renderer believes. + +## Running it + +```bash +dotnet run --project CityCulling -c Release +``` + +The window orbits the city; the status bar shows draw calls, cull percentage, culling cost and +frame time. The toolbar can pause the camera, tint the discarded objects red, and write the +captures. `--capture --exit` writes them at a fixed angle and quits. + +Windows only: this one is WinForms plus DX11. The binding itself runs on every RID it ships for, +and `OcclusionCulling` is the cross-platform sample. diff --git a/CityCulling/Renderer.cs b/CityCulling/Renderer.cs new file mode 100644 index 0000000..504f587 --- /dev/null +++ b/CityCulling/Renderer.cs @@ -0,0 +1,350 @@ +using Evergine.Common.Graphics; +using Evergine.Mathematics; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Buffer = Evergine.Common.Graphics.Buffer; + +namespace CityCulling +{ + /// Per-instance data: a world matrix and a colour. + [StructLayout(LayoutKind.Sequential)] + internal struct InstanceData + { + public Matrix4x4 World; + public Vector4 Colour; + } + + /// + /// Draws the city, one draw call per visible object. + /// + /// + /// One call each rather than instancing the lot, because that is what makes the culling + /// visible in the numbers: the frame goes from a thousand draw calls to whatever survives. + /// Per-object data still arrives through a per-instance vertex buffer, selected with + /// startInstanceLocation. Updating a constant buffer between draws would be the + /// obvious alternative and it is illegal: the validation layer rejects buffer updates inside + /// a render pass, and while DX11 lets it through, Vulkan and DX12 do not. + /// + internal sealed unsafe class Renderer : IDisposable + { + private const string ShaderSource = @" +cbuffer Frame : register(b0) +{ + float4x4 ViewProjection; + float4 LightDirection; +}; + +struct VS_IN +{ + float3 position : POSITION; + float3 normal : NORMAL; + float4 world0 : TEXCOORD0; + float4 world1 : TEXCOORD1; + float4 world2 : TEXCOORD2; + float4 world3 : TEXCOORD3; + float4 colour : TEXCOORD4; +}; + +struct PS_IN +{ + float4 position : SV_POSITION; + float3 normal : NORMAL; + float4 colour : COLOR; +}; + +PS_IN VS(VS_IN input) +{ + float4x4 world = float4x4(input.world0, input.world1, input.world2, input.world3); + + PS_IN output; + float4 worldPosition = mul(float4(input.position, 1.0), world); + output.position = mul(worldPosition, ViewProjection); + output.normal = normalize(mul(float4(input.normal, 0.0), world).xyz); + output.colour = input.colour; + return output; +} + +float4 PS(PS_IN input) : SV_Target +{ + // Flat directional term plus ambient. Only so the city reads as solid volumes; the + // culling measurement is entirely on the CPU side and none of this touches it. + float ndotl = saturate(dot(normalize(input.normal), -LightDirection.xyz)); + float shade = 0.35 + (0.65 * ndotl); + return float4(input.colour.rgb * shade, 1.0); +} +"; + + private readonly GraphicsContext graphicsContext; + private readonly Dictionary ranges = new(); + + private Buffer vertexBuffer; + private Buffer indexBuffer; + private Buffer instanceBuffer; + private Buffer frameBuffer; + private Buffer[] vertexBuffers; + private GraphicsPipelineState pipelineState; + private ResourceSet resourceSet; + private InstanceData[] instances; + + public Renderer(GraphicsContext graphicsContext, City city, FrameBuffer target) + { + this.graphicsContext = graphicsContext; + this.instances = new InstanceData[city.Count + 16]; + + this.BuildGeometry(city); + this.BuildPipeline(target); + } + + /// Index of the ground's slot in the shared vertex and index buffers. + private (uint StartIndex, uint IndexCount, uint BaseVertex) groundRange; + + public void Dispose() + { + this.vertexBuffer?.Dispose(); + this.indexBuffer?.Dispose(); + this.instanceBuffer?.Dispose(); + this.frameBuffer?.Dispose(); + } + + /// + /// Fills the instance buffer and issues the draws. selects the + /// objects; when is set, the discarded ones are drawn too, + /// tinted red, which is what makes the culling's mistakes visible. + /// + public int Draw(CommandBuffer commandBuffer, City city, Matrix4x4 viewProjection, Vector3 lightDirection, bool[] visible, bool drawCulled, List<(Matrix4x4 World, Vector4 Colour)> markers = null) + { + int slot = 0; + + // The ground always goes in: it is in the Embree scene so rays can stop on it, but it + // is never a culling candidate. + this.instances[slot++] = new InstanceData + { + World = Matrix4x4.CreateScale(city.Extent * 1.6f, 1.0f, city.Extent * 1.6f), + Colour = new Vector4(0.20f, 0.21f, 0.24f, 1.0f), + }; + + var drawList = new List<(Primitive Primitive, int Slot)>(city.Count); + + for (int i = 0; i < city.Count; i++) + { + bool kept = visible[i]; + if (!kept && !drawCulled) + { + continue; + } + + ref CityObject o = ref city.Objects[i]; + + Matrix4x4 world = + Matrix4x4.CreateScale(o.HalfExtent.X, o.HalfExtent.Y, o.HalfExtent.Z) * + Matrix4x4.CreateRotationY(o.Rotation) * + Matrix4x4.CreateTranslation(o.Centre.X, o.Centre.Y, o.Centre.Z); + + Vector4 colour = kept + ? new Vector4( + ((o.Colour >> 16) & 0xFF) / 255.0f, + ((o.Colour >> 8) & 0xFF) / 255.0f, + (o.Colour & 0xFF) / 255.0f, + 1.0f) + : new Vector4(0.85f, 0.16f, 0.16f, 1.0f); + + this.instances[slot] = new InstanceData { World = world, Colour = colour }; + drawList.Add((o.Primitive, slot)); + slot++; + } + + // Markers for the diagnostic views: the camera and its frustum edges, drawn as boxes. + int markerStart = slot; + if (markers != null) + { + foreach ((Matrix4x4 world, Vector4 colour) in markers) + { + this.instances[slot++] = new InstanceData { World = world, Colour = colour }; + } + } + + // Written before the render pass opens, which is the rule the validation layer + // enforces and the reason the per-object data rides in a vertex buffer. + MappedResource mapped = this.graphicsContext.MapMemory(this.instanceBuffer, MapMode.Write); + fixed (InstanceData* source = this.instances) + { + System.Buffer.MemoryCopy(source, (void*)mapped.Data, (long)slot * sizeof(InstanceData), (long)slot * sizeof(InstanceData)); + } + + this.graphicsContext.UnmapMemory(this.instanceBuffer); + + var frame = new FrameConstants { ViewProjection = viewProjection, LightDirection = new Vector4(lightDirection, 0.0f) }; + commandBuffer.UpdateBufferData(this.frameBuffer, ref frame); + + var renderPass = new RenderPassDescription(this.Target, ClearValue.Default); + commandBuffer.BeginRenderPass(ref renderPass); + commandBuffer.SetGraphicsPipelineState(this.pipelineState); + commandBuffer.SetResourceSet(this.resourceSet); + commandBuffer.SetVertexBuffers(this.vertexBuffers); + commandBuffer.SetIndexBuffer(this.indexBuffer, IndexFormat.UInt32); + + commandBuffer.DrawIndexedInstanced(this.groundRange.IndexCount, 1, this.groundRange.StartIndex, this.groundRange.BaseVertex, 0); + + foreach ((Primitive primitive, int instanceSlot) in drawList) + { + var range = this.ranges[primitive]; + commandBuffer.DrawIndexedInstanced(range.IndexCount, 1, range.StartIndex, range.BaseVertex, (uint)instanceSlot); + } + + if (markers != null) + { + var box = this.ranges[Primitive.Box]; + for (int i = 0; i < markers.Count; i++) + { + commandBuffer.DrawIndexedInstanced(box.IndexCount, 1, box.StartIndex, box.BaseVertex, (uint)(markerStart + i)); + } + } + + commandBuffer.EndRenderPass(); + + return drawList.Count + 1; + } + + /// The framebuffer this renderer's pipeline was built for. + public FrameBuffer Target { get; private set; } + + [StructLayout(LayoutKind.Sequential)] + private struct FrameConstants + { + public Matrix4x4 ViewProjection; + public Vector4 LightDirection; + } + + [StructLayout(LayoutKind.Sequential)] + private struct VertexPositionNormal + { + public Vector3 Position; + public Vector3 Normal; + } + + private void BuildGeometry(City city) + { + var vertices = new List(); + var indices = new List(); + + // A unit quad for the ground, then one copy of each primitive. Everything shares one + // vertex and one index buffer; a draw picks its mesh with startIndex/baseVertex. + this.groundRange = Append( + vertices, + indices, + new[] + { + new VertexPositionNormal { Position = new Vector3(-1, 0, -1), Normal = Vector3.Up }, + new VertexPositionNormal { Position = new Vector3(1, 0, -1), Normal = Vector3.Up }, + new VertexPositionNormal { Position = new Vector3(1, 0, 1), Normal = Vector3.Up }, + new VertexPositionNormal { Position = new Vector3(-1, 0, 1), Normal = Vector3.Up }, + }, + new uint[] { 0, 1, 2, 0, 2, 3 }); + + foreach (Primitive primitive in Enum.GetValues()) + { + Mesh mesh = Meshes.Get(primitive); + var meshVertices = new VertexPositionNormal[mesh.Positions.Length]; + for (int i = 0; i < mesh.Positions.Length; i++) + { + meshVertices[i] = new VertexPositionNormal + { + Position = new Vector3(mesh.Positions[i].X, mesh.Positions[i].Y, mesh.Positions[i].Z), + Normal = new Vector3(mesh.Normals[i].X, mesh.Normals[i].Y, mesh.Normals[i].Z), + }; + } + + this.ranges[primitive] = Append(vertices, indices, meshVertices, mesh.Indices); + } + + var vertexArray = vertices.ToArray(); + var indexArray = indices.ToArray(); + + var vertexDescription = new BufferDescription( + (uint)(sizeof(VertexPositionNormal) * vertexArray.Length), BufferFlags.VertexBuffer, ResourceUsage.Default); + this.vertexBuffer = this.graphicsContext.Factory.CreateBuffer(vertexArray, ref vertexDescription); + + var indexDescription = new BufferDescription( + (uint)(sizeof(uint) * indexArray.Length), BufferFlags.IndexBuffer, ResourceUsage.Default); + this.indexBuffer = this.graphicsContext.Factory.CreateBuffer(indexArray, ref indexDescription); + + var instanceDescription = new BufferDescription( + (uint)(sizeof(InstanceData) * this.instances.Length), BufferFlags.VertexBuffer, ResourceUsage.Dynamic, ResourceCpuAccess.Write); + this.instanceBuffer = this.graphicsContext.Factory.CreateBuffer(ref instanceDescription); + + this.vertexBuffers = new[] { this.vertexBuffer, this.instanceBuffer }; + } + + private static (uint StartIndex, uint IndexCount, uint BaseVertex) Append( + List vertices, List indices, VertexPositionNormal[] meshVertices, uint[] meshIndices) + { + uint baseVertex = (uint)vertices.Count; + uint startIndex = (uint)indices.Count; + + vertices.AddRange(meshVertices); + indices.AddRange(meshIndices); + + return (startIndex, (uint)meshIndices.Length, baseVertex); + } + + private void BuildPipeline(FrameBuffer target) + { + this.Target = target; + + var vertexShaderDescription = new ShaderDescription( + ShaderStages.Vertex, "VS", this.graphicsContext.ShaderCompile(ShaderSource, "VS", ShaderStages.Vertex).ByteCode); + var pixelShaderDescription = new ShaderDescription( + ShaderStages.Pixel, "PS", this.graphicsContext.ShaderCompile(ShaderSource, "PS", ShaderStages.Pixel).ByteCode); + + var vertexShader = this.graphicsContext.Factory.CreateShader(ref vertexShaderDescription); + var pixelShader = this.graphicsContext.Factory.CreateShader(ref pixelShaderDescription); + + var frameDescription = new BufferDescription((uint)sizeof(FrameConstants), BufferFlags.ConstantBuffer, ResourceUsage.Default); + this.frameBuffer = this.graphicsContext.Factory.CreateBuffer(ref frameDescription); + + var layoutDescription = new ResourceLayoutDescription( + new LayoutElementDescription(0, ResourceType.ConstantBuffer, ShaderStages.Vertex | ShaderStages.Pixel)); + var resourceLayout = this.graphicsContext.Factory.CreateResourceLayout(ref layoutDescription); + + var resourceSetDescription = new ResourceSetDescription(resourceLayout, this.frameBuffer); + this.resourceSet = this.graphicsContext.Factory.CreateResourceSet(ref resourceSetDescription); + + var layouts = new InputLayouts() + .Add(new LayoutDescription() + .Add(new ElementDescription(ElementFormat.Float3, ElementSemanticType.Position)) + .Add(new ElementDescription(ElementFormat.Float3, ElementSemanticType.Normal))) + .Add(new LayoutDescription(VertexStepFunction.PerInstanceData, 1) + .Add(new ElementDescription(ElementFormat.Float4, ElementSemanticType.TexCoord, 0)) + .Add(new ElementDescription(ElementFormat.Float4, ElementSemanticType.TexCoord, 1)) + .Add(new ElementDescription(ElementFormat.Float4, ElementSemanticType.TexCoord, 2)) + .Add(new ElementDescription(ElementFormat.Float4, ElementSemanticType.TexCoord, 3)) + .Add(new ElementDescription(ElementFormat.Float4, ElementSemanticType.TexCoord, 4))); + + var pipelineDescription = new GraphicsPipelineDescription() + { + PrimitiveTopology = PrimitiveTopology.TriangleList, + InputLayouts = layouts, + ResourceLayouts = new[] { resourceLayout }, + Shaders = new GraphicsShaderStateDescription + { + VertexShader = vertexShader, + PixelShader = pixelShader, + }, + RenderStates = new RenderStateDescription + { + RasterizerState = RasterizerStates.CullBack, + BlendState = BlendStates.Opaque, + + // Evergine's depth is reversed: ReadWrite compares GreaterEqual and + // ClearValue.Default clears depth to 0. The projection must be built with + // reverseDepthBuffer: true to match, or nothing draws. + DepthStencilState = DepthStencilStates.ReadWrite, + }, + Outputs = target.OutputDescription, + }; + + this.pipelineState = this.graphicsContext.Factory.CreateGraphicsPipeline(ref pipelineDescription); + } + } +} diff --git a/CityCulling/docs/city.png b/CityCulling/docs/city.png new file mode 100644 index 0000000000000000000000000000000000000000..95d1504b32e7ad02a345ac38658e04d4d16a40dc GIT binary patch literal 51768 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%0DJ15j)Bnt>1ql&R1hX*82Rao~$(8kQG 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

YhG}&A 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 UmuGrKody3{TP!s%G^K|97qaPbfdBvi literal 0 HcmV?d00001 diff --git a/CityCulling/docs/embree.png b/CityCulling/docs/embree.png new file mode 100644 index 0000000000000000000000000000000000000000..c41023059c25f7584be784040d2e54cba2955576 GIT binary patch literal 44065 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 literal 0 HcmV?d00001 diff --git a/Embree.sln b/Embree.sln index 675577f..06d136e 100644 --- a/Embree.sln +++ b/Embree.sln @@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloEmbree", "HelloEmbree\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OcclusionCulling", "OcclusionCulling\OcclusionCulling.csproj", "{9D90D092-3E99-429C-8657-C4809D72375B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CityCulling", "CityCulling\CityCulling.csproj", "{29FBC446-BABE-4589-9557-07C01E3BED49}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,6 +71,18 @@ Global {9D90D092-3E99-429C-8657-C4809D72375B}.Release|x64.Build.0 = Release|Any CPU {9D90D092-3E99-429C-8657-C4809D72375B}.Release|x86.ActiveCfg = Release|Any CPU {9D90D092-3E99-429C-8657-C4809D72375B}.Release|x86.Build.0 = Release|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Debug|x64.ActiveCfg = Debug|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Debug|x64.Build.0 = Debug|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Debug|x86.ActiveCfg = Debug|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Debug|x86.Build.0 = Debug|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Release|Any CPU.Build.0 = Release|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Release|x64.ActiveCfg = Release|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Release|x64.Build.0 = Release|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Release|x86.ActiveCfg = Release|Any CPU + {29FBC446-BABE-4589-9557-07C01E3BED49}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index e7ed5a5..8ca5ecc 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,15 @@ EmbreeGen/ Generator console app (CppAst); vendored headers Evergine.Bindings.Embree/ The NuGet package: Generated/ bindings + runtimes/ natives HelloEmbree/ Sample: CPU ray tracer drawn with the Evergine low-level API OcclusionCulling/ Sample: what a CPU occlusion culling pass costs +CityCulling/ Sample: a city culled with Embree, drawn with the low-level API ``` +[CityCulling](CityCulling/README.md) is the two halves put together: a thousand buildings drawn +through the Evergine low-level API, with Embree deciding each frame which of them reach the GPU. At +street level it issues 56 draw calls instead of 1000. + +![The city](CityCulling/docs/city.png) + [OcclusionCulling](OcclusionCulling/README.md) measures a visibility pass over a thousand boxes scattered at random two ways — per-object rays and a visibility buffer — each with single rays and 8-wide packets, and reports both the cost and how much of the screen each one gets wrong. It is a console app From 1b9d6762698872d576755e1948db002fa1227651 Mon Sep 17 00:00:00 2001 From: jcant0n Date: Tue, 11 Aug 2026 22:19:51 +0200 Subject: [PATCH 5/5] Measure what the culling costs, and admit it does not pay off here --bench sweeps a full orbit with VSync off: the culling runs at 0.42 ms median, 2.5% of a 16.6 ms frame, and removes 964 draw calls. --bench --no-cull draws everything instead, and the frame comes out faster: 0.59 ms against 0.70 ms. Net of the culling itself, 1,001 draw calls of this geometry cost 0.47 ms and 36 cost 0.27 ms, so the pass spends 0.30 ms of CPU to save 0.19 ms of drawing. That is the scene, not the technique. These are boxes and cones of a couple of dozen triangles with a two-line shader; there is nothing to save by not drawing one. But the sample would be misleading without the counterfactual next to it -- 94% culled reads like a win, and here it is not one. --- CityCulling/Program.cs | 84 ++++++++++++++++++++++++++++++++++++++++-- CityCulling/README.md | 40 ++++++++++++++++++++ 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/CityCulling/Program.cs b/CityCulling/Program.cs index c91b163..81c8784 100644 --- a/CityCulling/Program.cs +++ b/CityCulling/Program.cs @@ -45,11 +45,19 @@ internal static class Program private static bool exitAfterCapture; private static string outputDirectory; private static int lastCandidateCount; + private static bool benchmark; + private static bool noCull; + private static int benchFrame; + private static readonly System.Collections.Generic.List BenchCull = new(); + private static readonly System.Collections.Generic.List BenchFrame = new(); + private static readonly System.Collections.Generic.List BenchVisible = new(); private static double lastMissedScreen; [STAThread] private static int Main(string[] args) { + benchmark = args.Contains("--bench"); + noCull = args.Contains("--no-cull"); bool capture = args.Contains("--capture"); exitAfterCapture = args.Contains("--exit"); captureRequested = capture; @@ -81,7 +89,8 @@ private static int Main(string[] args) }; swapChain = graphicsContext.CreateSwapChain(swapChainDescription); - swapChain.VerticalSync = true; + // VSync would clamp every frame to the refresh rate and hide what the culling costs. + swapChain.VerticalSync = !benchmark; var windowSystem = new FormsWindowsSystem { AutoRegisterWindow = false }; windowSystem.RegisterLoopThreadControl(form); @@ -111,7 +120,13 @@ private static void Draw() { long frameStart = Stopwatch.GetTimestamp(); - if (!form.PauseButton.Checked && !captureRequested) + if (benchmark) + { + // A full orbit in fixed steps, so the sweep covers every direction the camera can + // face rather than whichever ones a wall-clock animation happened to land on. + cameraAngle = CaptureAngle + ((float)benchFrame / BenchFrames * MathF.Tau); + } + else if (!form.PauseButton.Checked && !captureRequested) { cameraAngle = CaptureAngle + ((float)clock.Elapsed.TotalSeconds * 0.16f); } @@ -126,7 +141,17 @@ private static void Draw() long cullStart = Stopwatch.GetTimestamp(); int candidateCount = Culling.Frustum(city, camera, candidates); lastCandidateCount = candidateCount; - Culling.Occlusion(city, camera, candidates, candidateCount, visible); + + if (noCull) + { + // The counterfactual: draw everything and pay for it on the GPU instead. + Array.Fill(visible, true); + } + else + { + Culling.Occlusion(city, camera, candidates, candidateCount, visible); + } + double cullMs = Milliseconds(Stopwatch.GetTimestamp() - cullStart); swapChain.InitFrame(); @@ -160,7 +185,27 @@ private static void Draw() swapChain.Present(); - form.SetFrameInfo(drawn, city.Count + 1, cullMs, Milliseconds(Stopwatch.GetTimestamp() - frameStart)); + double frameMs = Milliseconds(Stopwatch.GetTimestamp() - frameStart); + form.SetFrameInfo(drawn, city.Count + 1, cullMs, frameMs); + + if (benchmark) + { + benchFrame++; + + // The first frames pay JIT and driver warm-up. + if (benchFrame > BenchWarmup) + { + BenchCull.Add(cullMs); + BenchFrame.Add(frameMs); + BenchVisible.Add(drawn); + } + + if (benchFrame >= BenchWarmup + BenchFrames) + { + ReportBenchmark(); + Environment.Exit(0); + } + } } ///

@@ -199,6 +244,37 @@ private static EvergineMath.Matrix4x4 ViewProjection(Camera camera) private static double Milliseconds(long ticks) => ticks * 1000.0 / Stopwatch.Frequency; + private const int BenchWarmup = 30; + private const int BenchFrames = 360; // one full orbit, one degree at a time + + /// + /// What the culling costs across a full orbit, and what share of a 60 Hz frame that is. + /// + private static void ReportBenchmark() + { + var cull = BenchCull.ToArray(); + var frame = BenchFrame.ToArray(); + var drawn = BenchVisible.ToArray(); + Array.Sort(cull); + Array.Sort(frame); + Array.Sort(drawn); + + double medianCull = cull[cull.Length / 2]; + + Console.WriteLine(); + Console.WriteLine($"{city.Count:N0} objects, {BenchFrames} frames over a full orbit, VSync off{(noCull ? ", occlusion culling OFF" : string.Empty)}"); + Console.WriteLine(); + Console.WriteLine(" min median mean max"); + Console.WriteLine($"culling {cull[0],8:F3} {medianCull,10:F3} {cull.Average(),10:F3} {cull[^1],10:F3} ms"); + Console.WriteLine($"whole frame {frame[0],8:F3} {frame[frame.Length / 2],10:F3} {frame.Average(),10:F3} {frame[^1],10:F3} ms"); + Console.WriteLine($"draw calls {drawn[0],8:N0} {drawn[drawn.Length / 2],10:N0} {drawn.Average(),10:F0} {drawn[^1],10:N0}"); + Console.WriteLine(); + if (!noCull) + { + Console.WriteLine($"Culling is {100.0 * medianCull / 16.6:F1}% of a 16.6 ms frame at 60 Hz ({medianCull:F2} ms of budget spent to avoid {city.Count - drawn[drawn.Length / 2]:N0} draw calls)."); + } + } + /// /// Three views of the same frame: what was drawn, what was thrown away, and the whole /// city from above so the occlusion shadows behind each building are visible. diff --git a/CityCulling/README.md b/CityCulling/README.md index e0b9adc..ede1d45 100644 --- a/CityCulling/README.md +++ b/CityCulling/README.md @@ -46,6 +46,46 @@ From above, with the camera in amber and its two frustum edges. The kept objects wedge just in front of the camera; everything beyond the first row of facades is red. That narrow wedge is what 94% culling looks like. +## What it costs, across a full orbit + +`--bench` turns VSync off and sweeps a full circle in 360 steps, so the numbers cover every +direction the camera can face rather than whichever ones an animation happened to land on. + +``` + min median mean max +culling 0.306 0.422 0.437 0.816 ms +whole frame 0.533 0.696 0.705 2.050 ms +draw calls 2 36 35 75 +``` + +**The culling costs 0.42 ms, which is 2.5% of a 16.6 ms frame at 60 Hz**, and it removes 964 +draw calls. + +## And it does not pay for itself here + +`--bench --no-cull` skips the occlusion pass and draws everything: + +``` + min median mean max +culling 0.117 0.123 0.129 0.247 ms (frustum only) +whole frame 0.418 0.589 0.635 1.369 ms +draw calls 1,001 1,001 1001 1,001 +``` + +The frame is **faster without the occlusion pass**: 0.59 ms against 0.70 ms. Taking the culling +out of both, 1,001 draw calls of this geometry cost 0.47 ms and 36 cost 0.27 ms — so the pass +spends 0.30 ms of CPU to save 0.19 ms of drawing, and loses 0.11 ms on the deal. + +That is not a defect in the culling, it is the scene. These are boxes and cones of a couple of +dozen triangles with a two-line shader; there is almost nothing to save by not drawing one. The +pass breaks even when an average object costs about 0.3 µs more than it does here, and wins +comfortably beyond that — which is to say, with real meshes, real materials and real overdraw. +The 0.42 ms is what the technique costs; whether it is worth paying depends entirely on what a +draw call costs you. + +Worth knowing before wiring this into an engine, and worth measuring there rather than trusting +this number. + ## Things worth knowing before copying this **Evergine's depth is reversed.** `DepthStencilStates.ReadWrite` compares `GreaterEqual` and