From b0f7a95d3806dd8017ac2abf31b1504482452a06 Mon Sep 17 00:00:00 2001 From: voidstar69 Date: Wed, 22 Aug 2018 22:34:44 +0100 Subject: [PATCH 1/2] Created test to compare dynamic shadow code against static shadow code. Allowed IntersectionInfo objects to be compared. --- Engine3D/Engine3D-Tests/Engine3D-Tests.csproj | 1 + .../Raytrace/ShadowMethodTests.cs | 64 +++++++++++++++++++ Engine3D/Raytrace/IRayIntersectable.cs | 20 ++++++ Engine3D/Raytrace/Texture3DCache.cs | 6 +- Engine3D/Texture3D.cs | 7 +- 5 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 Engine3D/Engine3D-Tests/Raytrace/ShadowMethodTests.cs diff --git a/Engine3D/Engine3D-Tests/Engine3D-Tests.csproj b/Engine3D/Engine3D-Tests/Engine3D-Tests.csproj index 76abf95..e0dd028 100644 --- a/Engine3D/Engine3D-Tests/Engine3D-Tests.csproj +++ b/Engine3D/Engine3D-Tests/Engine3D-Tests.csproj @@ -101,6 +101,7 @@ + diff --git a/Engine3D/Engine3D-Tests/Raytrace/ShadowMethodTests.cs b/Engine3D/Engine3D-Tests/Raytrace/ShadowMethodTests.cs new file mode 100644 index 0000000..331c5b6 --- /dev/null +++ b/Engine3D/Engine3D-Tests/Raytrace/ShadowMethodTests.cs @@ -0,0 +1,64 @@ +using System; +using Engine3D.Raytrace; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert; +using Scene = Engine3D.Scene; +using Vector = Engine3D.Vector; + +namespace Engine3D_Tests.Raytrace +{ + [TestClass] + public class ShadowMethodTests + { + private static readonly Random Random = new Random(); + + [TestMethod] + public void DynamicVsStaticShadowMethods() + { + IRayIntersectable geometry = new Sphere(Vector.Zero, 0.5); + var scene = new Scene(); + const byte resolution = 10; + string instanceKey = null; + const int randomSeed = 12345; + + var context = new RenderContext(new Random(randomSeed)); + var dynamicShadowMethod = new ShadowMethod(geometry, scene, false, resolution, instanceKey, context); + + context = new RenderContext(new Random(randomSeed)); + var staticShadowMethod = new ShadowMethod(geometry, scene, true, resolution, instanceKey, context); + + const int numRays = 1000000; + var numRaysHit = 0; + + for (var i = 0; i < numRays; i++) + { + var start = MakeRandomVector(-2, 2, -2, 2, -2, 2); + var dir = MakeRandomVector(-1, 1, -1, 1, -1, 1); + var info = dynamicShadowMethod.IntersectRay(start, dir, context); + if (info != null) + numRaysHit++; + + var info2 = staticShadowMethod.IntersectRay(start, dir, context); + + // TODO: find a scenario where this fails, e.g. multi-threaded render; vary number of threads; cache shadows to disk; repeat rays + Assert.AreEqual(info, info2); + } + + //Assert.AreEqual(numRays, numRaysHit, "Num rays hit {0} should be the same as total rays {1}", numRaysHit, numRays); + //Assert.IsTrue(numRays * 0.498 < numRaysHit && numRaysHit < numRays * 0.502, "Num rays hit {0} should be roughly half of total rays {1}", numRaysHit, numRays); + Console.WriteLine("Num rays hit: {0} / {1}", numRaysHit, numRays); + } + + private Vector MakeRandomVector(double minX, double maxX, double minY, double maxY, double minZ, double maxZ) + { + return new Vector((maxX - minX) * NextRandomDouble() + minX, + (maxY - minY) * NextRandomDouble() + minY, + (maxZ - minZ) * NextRandomDouble() + minZ); + } + + private double NextRandomDouble() + { + return Random.NextDouble(); + } + } +} \ No newline at end of file diff --git a/Engine3D/Raytrace/IRayIntersectable.cs b/Engine3D/Raytrace/IRayIntersectable.cs index ed06b77..2610230 100644 --- a/Engine3D/Raytrace/IRayIntersectable.cs +++ b/Engine3D/Raytrace/IRayIntersectable.cs @@ -15,6 +15,26 @@ public class IntersectionInfo // TODO: store triangle index or reference to intersected object? //public IRayIntersectable objHit; public int triIndex = -1; // -1 means that the intersected geometry is not a triangle + + public override bool Equals(object obj) + { + var other = obj as IntersectionInfo; + if (other == null) + return false; + + return rayFrac == other.rayFrac && + pos == other.pos && + normal == other.normal && + color == other.color; + } + + public override int GetHashCode() + { + return ((rayFrac.GetHashCode() + * 31 + pos.GetHashCode()) + * 31 + normal.GetHashCode()) + * 31 + color.GetHashCode(); + } } public class RenderContext diff --git a/Engine3D/Raytrace/Texture3DCache.cs b/Engine3D/Raytrace/Texture3DCache.cs index 2bf13b9..e223ed9 100644 --- a/Engine3D/Raytrace/Texture3DCache.cs +++ b/Engine3D/Raytrace/Texture3DCache.cs @@ -92,9 +92,9 @@ public T Sample(Vector pos) { // TODO: sometimes a surface point coordinate is very slightly outside the unit cube (i.e. Z coordinate of 0.50000000001) // TODO: clamp 'close' coordinates to the unit cube? - Assert.IsTrue(-0.5 <= pos.x && pos.x <= 0.5, "Texture3D coordinate is outside unit cube"); - Assert.IsTrue(-0.5 <= pos.y && pos.y <= 0.5, "Texture3D coordinate is outside unit cube"); - Assert.IsTrue(-0.5 <= pos.z && pos.z <= 0.5, "Texture3D coordinate is outside unit cube"); + Contract.Assert(-0.5 <= pos.x && pos.x <= 0.5, "Texture3D coordinate is outside unit cube"); + Contract.Assert(-0.5 <= pos.y && pos.y <= 0.5, "Texture3D coordinate is outside unit cube"); + Contract.Assert(-0.5 <= pos.z && pos.z <= 0.5, "Texture3D coordinate is outside unit cube"); var cacheIndex = (int)((pos.x + 0.5) * (cacheSize - 1)) * cacheSize * cacheSize + (int)((pos.y + 0.5) * (cacheSize - 1)) * cacheSize + (int)((pos.z + 0.5) * (cacheSize - 1)); diff --git a/Engine3D/Texture3D.cs b/Engine3D/Texture3D.cs index acc98d5..81289b3 100644 --- a/Engine3D/Texture3D.cs +++ b/Engine3D/Texture3D.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Engine3D +namespace Engine3D { interface Texture3D { From cd4c621934c7b03ce3ae54a121ba594506b467d5 Mon Sep 17 00:00:00 2001 From: voidstar69 Date: Tue, 28 Jan 2020 18:51:35 +0000 Subject: [PATCH 2/2] Misc ancient changes --- .../Engine3D-Tests/Raytrace/RendererTests.cs | 7 ++++--- .../Raytrace/ShadowMethodTests.cs | 20 ++++++++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Engine3D/Engine3D-Tests/Raytrace/RendererTests.cs b/Engine3D/Engine3D-Tests/Raytrace/RendererTests.cs index 12e46a7..5d21ac5 100644 --- a/Engine3D/Engine3D-Tests/Raytrace/RendererTests.cs +++ b/Engine3D/Engine3D-Tests/Raytrace/RendererTests.cs @@ -55,7 +55,7 @@ public class RendererTests private int numMissingBaselines = 0; - private static int[] pixels = new int[maxImageWidth * maxImageHeight]; + private static int[] pixels; [TestInitialize] public void Init() @@ -69,6 +69,7 @@ private static void RendererSetup(Renderer renderer, string modelFileName, //renderer.BackgroundColor = 0xff0000; // red //renderer.BackgroundColor = 0x0000ff; // blue + pixels = new int[resolution * resolution]; renderer.SetRenderingSurface(resolution, resolution, pixels); // Load 3D model from disk @@ -167,7 +168,7 @@ public void RaytraceDynamicShadow() public void RaytraceStaticShadow() { RaytraceScenario(shadows: true, staticShadows: true); - RaytraceScenario(shadows: true, staticShadows: true, shading: false); + //RaytraceScenario(shadows: true, staticShadows: true, shading: false); if (numMissingBaselines > 0) Assert.Fail("{0} missing baseline images were recreated", numMissingBaselines); @@ -192,7 +193,7 @@ public void RaytraceShadowAndFocalBlur() // TODO: produced image is slightly different if this test is run in isolation vs run together with test RaytraceStaticShadow. Why? // TODO: number of threads affects resulting image, slighty changing quite a few pixels // Most likely the threads are racing each other to update the shadow cache, causing non-deterministic behaviour! - [TestMethod, Ignore] + [TestMethod /*, Ignore*/] public void RaytraceStaticShadowAndFocalBlur() { RaytraceScenario(focalBlur: true, shadows: true, staticShadows: true, subPixelRes: 4); diff --git a/Engine3D/Engine3D-Tests/Raytrace/ShadowMethodTests.cs b/Engine3D/Engine3D-Tests/Raytrace/ShadowMethodTests.cs index 331c5b6..adc1b72 100644 --- a/Engine3D/Engine3D-Tests/Raytrace/ShadowMethodTests.cs +++ b/Engine3D/Engine3D-Tests/Raytrace/ShadowMethodTests.cs @@ -1,8 +1,10 @@ using System; +using Engine3D; using Engine3D.Raytrace; using Microsoft.VisualStudio.TestTools.UnitTesting; using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert; using Scene = Engine3D.Scene; +using Triangle = Engine3D.Raytrace.Triangle; using Vector = Engine3D.Vector; namespace Engine3D_Tests.Raytrace @@ -15,11 +17,24 @@ public class ShadowMethodTests [TestMethod] public void DynamicVsStaticShadowMethods() { - IRayIntersectable geometry = new Sphere(Vector.Zero, 0.5); + const int numRays = 100000; + const int numTriangles = 100; + + var geometry = new GeometryCollection(); + for (var i = 0; i < numTriangles; i++) + { + geometry.Add(new Triangle( + MakeRandomVector(-1, 1, -1, 1, -1, 1), + MakeRandomVector(-1, 1, -1, 1, -1, 1), + MakeRandomVector(-1, 1, -1, 1, -1, 1), + Color.Cyan.ToARGB())); + } + + //IRayIntersectable geometry = new Sphere(Vector.Zero, 0.5); var scene = new Scene(); const byte resolution = 10; string instanceKey = null; - const int randomSeed = 12345; + const int randomSeed = 12345678; var context = new RenderContext(new Random(randomSeed)); var dynamicShadowMethod = new ShadowMethod(geometry, scene, false, resolution, instanceKey, context); @@ -27,7 +42,6 @@ public void DynamicVsStaticShadowMethods() context = new RenderContext(new Random(randomSeed)); var staticShadowMethod = new ShadowMethod(geometry, scene, true, resolution, instanceKey, context); - const int numRays = 1000000; var numRaysHit = 0; for (var i = 0; i < numRays; i++)