private static void RendererSetup(Renderer renderer, string modelFileName, double pitchDegrees, double yawDegrees, double rollDegrees, double objectDepth, int resolution) { renderer.BackgroundColor = 0xff00ff; // pink //renderer.BackgroundColor = 0xff0000; // red //renderer.BackgroundColor = 0x0000ff; // blue renderer.SetRenderingSurface(resolution, resolution, pixels); // Load 3D model from disk using (Stream stream = new FileStream(modelFileName, FileMode.Open, FileAccess.Read)) { renderer.Load3dsModelFromStream(stream); } // Create an instance of this model in the scene. renderer.Instances.Add(new Engine3D.Instance(renderer.Model) { Position = new Engine3D.Vector(0.0, 0.0, objectDepth), // position of object (in view space) Yaw = yawDegrees / 180.0 * Math.PI, Pitch = pitchDegrees / 180.0 * Math.PI, Roll = rollDegrees / 180.0 * Math.PI }); //renderer.directionalLight_dir = new Engine3D.Vector(1.0, 1.0, 1.0); //renderer.directionalLight_dir.Normalise(); //renderer.positionalLight_pos = renderer.Instances[0].Position - renderer.directionalLight_dir * 2; //renderer.specularLight_shininess = 100.0; // Prevent Assert failure from displaying UI //Debug.Listeners.Clear(); }
public void RasteriseTest() { const int resolution = defaultResolution; using (var renderer = new Renderer()) { RendererSetup(renderer, modelFileName, defaultPitchDegrees, defaultYawDegrees, defaultRollDegrees, objectDepth, resolution); renderer.rayTrace = false; var flags = new bool[5]; var numPermutations = 1 << flags.Length; for (int i = 0; i < numPermutations; i++) { MakeBooleanPermutation(i, flags); renderer.shading = flags[0]; renderer.perPixelShading = flags[1]; renderer.pointLighting = flags[2]; renderer.specularLighting = flags[3]; renderer.depthBuffer = flags[4]; // TODO: adding this flag increases test runtime from ~10s to ~20s in Debug mode // when shading is disabled, per-pixel-shading flag has no effect if (renderer.perPixelShading && !renderer.shading) { continue; } var dirPath = "rasterise/" + resolution + 'x' + resolution; var testName = dirPath + '/' + (renderer.perPixelShading ? "perPixelShading" : (renderer.shading ? "shading" : "noShading")) + (renderer.pointLighting ? "_pointLit" : "") + (renderer.specularLighting ? "_specular" : "") + (renderer.depthBuffer ? "_depth" : "") + ("x" + renderer.rayTraceSubPixelRes); Directory.CreateDirectory(candidatePath + dirPath); Directory.CreateDirectory(baselinePath + dirPath); RenderAndTest(testName, renderer, resolution, resolution); } if (numMissingBaselines > 0) { Assert.Fail("{0} missing baseline images were recreated", numMissingBaselines); } } }
/// <summary> /// Render image using current renderer settings, and compare image against a baseline image. /// </summary> /// <param name="testName">Unique name for the test. Can contain slashes.</param> private void RenderAndTest(string testName, Renderer renderer, int imageWidth, int imageHeight) { renderer.Render(); // Copy the 2D surface into a bitmap. Bitmap bitmap = null; unsafe { fixed(void *pointer = pixels) { bitmap = new Bitmap(imageWidth, imageHeight, imageWidth * 4, PixelFormat.Format32bppRgb, (IntPtr)pointer); }; }; bitmap.Save(candidatePath + testName + bitmapFileExtension, bitmapFormat); Bitmap baseBitmap = null; try { baseBitmap = new Bitmap(baselinePath + testName + bitmapFileExtension); } catch (ArgumentException) { // Baseline image file is missing. We recreate it. bitmap.Save(baselinePath + testName + bitmapFileExtension, bitmapFormat); numMissingBaselines++; return; } int numPixelsDiff = CompareBitmaps(bitmap, baseBitmap); Assert.AreNotEqual(-1, numPixelsDiff, "Different bitmap dimensions"); var percentDiff = numPixelsDiff * 100.0 / imageWidth / imageHeight; Assert.AreEqual(0.0, percentDiff, "{0}: % different pixel colours between bitmaps", testName); }
// skip all tests up until a specific test, then run it and all the rest /* * private const string startFromTest = "raytrace/100x100/noShading_staticShadows_lightField"; * private bool skipTest = true; */ // TODO: add flag for quad-filtering on color lightfield private void RaytraceScenario(bool shading = true, bool focalBlur = false, bool shadows = false, bool staticShadows = false, bool lightField = false, bool lightFieldWithTris = false, bool pathTracing = false, bool voxels = false, int subPixelRes = 1, int resolution = defaultResolution, double pitchDegrees = defaultPitchDegrees, double yawDegrees = defaultYawDegrees, double rollDegrees = defaultRollDegrees, double focalDepth = -1, GeometryCollection extraGeometry = null) { using (var renderer = new Renderer()) { RendererSetup(renderer, modelFileName, pitchDegrees, yawDegrees, rollDegrees, objectDepth, resolution); // TODO: raytracer has slight difference on cube edges between Release and Debug mode. Rounding error? renderer.rayTrace = true; renderer.rayTraceSubdivision = true; renderer.rayTraceShading = shading; renderer.rayTraceFocalBlur = focalBlur; renderer.rayTraceFocalDepth = (Math.Abs(focalDepth + 1) < 0.001 ? objectDepth + 0.5 : focalDepth); renderer.rayTraceSubPixelRes = subPixelRes; renderer.rayTracePathTracing = pathTracing; renderer.rayTraceVoxels = voxels; renderer.rayTraceShadows = shadows; // TODO: adding this flag seems to increase test runtime massively! (during focal blur?) renderer.rayTraceShadowsStatic = staticShadows; // TODO: ambient occlusion has some instability, sometimes causes banding, and fails regression testing //renderer.rayTraceAmbientOcclusion = true; // = flags[2]; // TODO: non-cached AO has many differences to cached AO //renderer.ambientOcclusionEnableCache = false; // avoid caching static shadows to disk, as this can produce a slightly different image on each test execution renderer.CacheStaticShadowsToFile = false; // lightfields must be used in x64 mode to avoid 'cannot create MM view' errors // TODO: unit testing lightfields with memory-mapped files seems to cause an error for later tests renderer.rayTraceLightField = lightField; renderer.LightFieldStoresTriangles = lightFieldWithTris; // raytrace any extra geometry beyond the triangle model? if (extraGeometry != null) { renderer.ExtraGeometryToRaytrace = extraGeometry; } // when shadows are disabled, static shadows flag has no effect if (renderer.rayTraceShadowsStatic && !renderer.rayTraceShadows) { return; } var dirPath = "raytrace/" + resolution + 'x' + resolution; var testName = dirPath + '/' + (renderer.rayTraceVoxels ? "voxels_" : "") + (renderer.rayTracePathTracing ? "pathTracing_" : "") + (renderer.rayTraceShading ? "shading" : "noShading") + (renderer.rayTraceShadows ? (renderer.rayTraceShadowsStatic ? "_staticShadows" : "_shadows") : "") + (renderer.rayTraceAmbientOcclusion ? "_AO" : "") + (lightField && lightFieldWithTris ? "_lightFieldTri" : "") + (lightField && !lightFieldWithTris ? "_lightFieldColor" : "") + (renderer.rayTraceFocalBlur ? "_focalBlur" : "") + (focalBlur ? "x" + subPixelRes : (subPixelRes > 1 ? "_" + subPixelRes + "xAA" : "")) + (extraGeometry != null ? ("_" + (extraGeometry.Count + 1) + "_geometry") : "") + raytraceTestSuffix; /* * // skip all tests up until a specific test, then run it and all the rest * if (testName == startFromTest) * skipTest = false; * if (skipTest) * return; */ Directory.CreateDirectory(candidatePath + dirPath); Directory.CreateDirectory(baselinePath + dirPath); try { RenderAndTest(testName, renderer, resolution, resolution); } catch (Exception ex) { // TODO: reports test name, but breaks stack trace links. //Assert.Fail("{0}: threw exception", testName); Console.WriteLine(ex); throw; } } }