public static void ComplexScene(int numTrials) { // the scene is compressed to avoid git issues if (!File.Exists("../Data/breakfast_room.obj")) { ZipFile.ExtractToDirectory("../Data/breakfast_room.zip", "../Data"); } Stopwatch stop = Stopwatch.StartNew(); List <TriangleMesh> meshes = new(); Vector3 min = Vector3.One * float.MaxValue; Vector3 max = -Vector3.One * float.MaxValue; Assimp.AssimpContext context = new(); var scene = context.ImportFile("../Data/breakfast_room.obj", Assimp.PostProcessSteps.GenerateNormals | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.PreTransformVertices | Assimp.PostProcessSteps.Triangulate); foreach (var m in scene.Meshes) { var material = scene.Materials[m.MaterialIndex]; string materialName = material.Name; Vector3[] vertices = new Vector3[m.VertexCount]; for (int i = 0; i < m.VertexCount; ++i) { vertices[i] = new(m.Vertices[i].X, m.Vertices[i].Y, m.Vertices[i].Z); } meshes.Add(new(vertices, m.GetIndices())); min.X = MathF.Min(min.X, m.BoundingBox.Min.X); min.Y = MathF.Min(min.X, m.BoundingBox.Min.Y); min.Z = MathF.Min(min.X, m.BoundingBox.Min.Z); max.X = MathF.Max(max.X, m.BoundingBox.Max.X); max.Y = MathF.Max(max.X, m.BoundingBox.Max.Y); max.Z = MathF.Max(max.X, m.BoundingBox.Max.Z); } var diagonal = max - min; Console.WriteLine($"Scene loaded in {stop.ElapsedMilliseconds}ms"); stop.Restart(); var rt = new Raytracer(); foreach (var m in meshes) { rt.AddMesh(m); } rt.CommitScene(); Console.WriteLine($"Acceleration structures built in {stop.ElapsedMilliseconds}ms"); Random rng = new(1337); Vector3 NextVector() => new Vector3( (float)rng.NextDouble(), (float)rng.NextDouble(), (float)rng.NextDouble()); stop.Restart(); float averageDistance = 0; for (int k = 0; k < numTrials; ++k) { for (int i = 0; i < 1000000; ++i) { var hit = rt.Trace(new Ray { Origin = NextVector() * diagonal + min, Direction = NextVector(), MinDistance = 0.0f }); if (hit) { averageDistance += hit.Distance / 1000000 / numTrials; } } } stop.Stop(); Console.WriteLine($"One million closest hits found in {stop.ElapsedMilliseconds / numTrials}ms"); Console.WriteLine($"Average distance: {averageDistance}"); stop.Restart(); float averageVisibility = 0; for (int k = 0; k < numTrials; ++k) { for (int i = 0; i < 1000000; ++i) { bool occluded = rt.IsOccluded(new ShadowRay(new Ray { Origin = NextVector() * diagonal + min, Direction = NextVector(), MinDistance = 0.0f }, maxDistance: (float)rng.NextDouble() * averageDistance * 5)); if (!occluded) { averageVisibility += 1.0f / 1000000.0f / numTrials; } } } stop.Stop(); Console.WriteLine($"One million any hits found in {stop.ElapsedMilliseconds / numTrials}ms"); Console.WriteLine($"Average visibility: {averageVisibility}"); }