public void Test1() { To = TerrainPatch.FromId(new Point(103, 138)); From = TerrainPatch.FromId(new Point(103, 139)); To.FillPointsAndMatrices(Terrain); From.FillPoints(Terrain); To.UpdateHorizonBugHunt(From); Console.WriteLine(@"Test1 finished."); }
public void LoadRam() { Patch.FillPoints(tiles.TileTreeNode.Terrain); var width = Patch.Width; var height = Patch.Height; var vertices = new Vertex[VertexCount]; if (vertices.Length > 65536) { throw new Exception("Mesh too large"); } float xf = 1f / (width - 1); float yf = 1f / (height - 1); for (var line = 0; line < height; line++) { var points_row = Patch.Points[line]; for (var sample = 0; sample < width; sample++) { var idx = line * height + sample; vertices[idx].TexCoord.X = sample * xf; vertices[idx].TexCoord.Y = line * yf; var pt = points_row[sample]; vertices[idx].Normal.X = 0f; vertices[idx].Normal.Y = 0f; vertices[idx].Normal.Z = 1f; vertices[idx].Position.X = (float)(pt.X * Kilometers); vertices[idx].Position.Y = (float)(pt.Y * Kilometers); vertices[idx].Position.Z = (float)(pt.Z * Kilometers); //Console.WriteLine($"[{vertices[idx].Position.X},{vertices[idx].Position.Y},{vertices[idx].Position.Z}]"); } } // Define a mesh var elements = new ushort[(width - 1) * (height - 1) * 6]; { var ptr = 0; var xMax = width - 1; var yMax = height - 1; for (var x = 0; x < xMax; x++) { for (var y = 0; y < yMax; y++) { var v = x * height + y; //Console.WriteLine(@"v={0}", v); elements[ptr++] = (ushort)(v + height); // a elements[ptr++] = (ushort)(v + 1); // b elements[ptr++] = (ushort)v; // c //Console.WriteLine(@"tri [{0}, {1}, {2}]", x + YSize, v + 1, v); elements[ptr++] = (ushort)(v + height); // a elements[ptr++] = (ushort)(v + height + 1); // b elements[ptr++] = (ushort)(v + 1); // c //Console.WriteLine(@"tri [{0}, {1}, {2}]", v + YSize, v + YSize + 1, v + 1); } } } if (true) { // Average the normals var buf = DEM.GetNormalAverager(VertexCount); for (var i = 0; i < VertexCount; i++) { buf[i].Reset(); } var triCount = elements.Length / 3; var ptr = 0; for (var tri = 0; tri < triCount; tri++) { var p1 = elements[ptr++]; var p2 = elements[ptr++]; var p3 = elements[ptr++]; var v1 = vertices[p1].Position; var v2 = vertices[p2].Position; var v3 = vertices[p3].Position; //Console.WriteLine(@"textureCoords=[{0},{1}], [{2},{3}], [{4},{5}]", // v[p1].TexCoord.X, v[p1].TexCoord.Y, // v[p2].TexCoord.X, v[p2].TexCoord.Y, // v[p3].TexCoord.X, v[p3].TexCoord.Y); Shape.FindNormal(ref v1, ref v2, ref v3, out Vector3 n); if (float.IsNaN(n.X)) { throw new Exception(@"Got NaN when creating a mesh normal"); } buf[p1].Add(n); buf[p2].Add(n); buf[p3].Add(n); /* * if (tri == 0) * { * Console.WriteLine(@"First tri"); * Console.WriteLine(@" p1={0} p2={1} p3={2}", p1, p2, p3); * Console.WriteLine(@" v1={0} v2={1} v3={2}", v1, v2, v3); * Console.WriteLine(@" n1={0} n2={1} n3={2}", v[p1].Normal, v[p2].Normal, v[p3].Normal); * Console.WriteLine(@" calculated normal={0}", n); * Console.WriteLine(); * } */ /* * buf[p1].Add(v[p1].Normal); * buf[p2].Add(v[p1].Normal); * buf[p3].Add(v[p2].Normal); */ } for (var i = 0; i < VertexCount; i++) { var norm = buf[i].Normal / buf[i].Count; norm.Normalize(); /* * if (i == 0 || i == 1 || i == 257) * { * Console.WriteLine(@"point[{0}].Normal (before)={1}", i, v[i].Normal); * Console.WriteLine(@"new normal={0}", norm); * } */ vertices[i].Normal = norm; } } //Buffer = LoadVBO(vertices, elements, InterleavedArrayFormat.T2fN3fV3f); using (var ms = new MemoryStream()) { using (var bw = new BinaryWriter(ms)) { for (var i = 0; i < vertices.Length; i++) { bw.Write((float)vertices[i].TexCoord.X); bw.Write((float)vertices[i].TexCoord.Y); bw.Write((float)vertices[i].Normal.X); bw.Write((float)vertices[i].Normal.Y); bw.Write((float)vertices[i].Normal.Z); bw.Write((float)vertices[i].Position.X); bw.Write((float)vertices[i].Position.Y); bw.Write((float)vertices[i].Position.Z); } } Vertices = ms.GetBuffer(); } CornerVertices[0] = vertices[0 * Width + 0]; CornerVertices[1] = vertices[0 * Width + (Width - 1)]; CornerVertices[2] = vertices[(Height - 1) * Width + 0]; CornerVertices[3] = vertices[(Height - 1) * Width + (Width - 1)]; BoundingSphereRadius = 100f; // Radius; BoundingSphereDefined = true; }
static float EncodingToSlope(int encoding) => 4f * encoding / 1000000f; // Haven't looked at the numerics closely to see whether these are exact inverses. Don't care enough yet. /// <summary> /// Generate the near horizon for the patch, overwriting what was there. /// The horizons will be in slope format, not angles /// </summary> /// <param name="target"></param> public void AddNearHorizon(TerrainPatch target) { Debug.Assert(Terrain != null); Debug.Assert(target != null); if (target.Horizons == null) { target.InitializeHorizons(); } using (var context = new Context()) { AcceleratorId aid = Accelerator.Accelerators.Where(id => id.AcceleratorType == AcceleratorType.Cuda).FirstOrDefault(); //AcceleratorId aid = Accelerator.Accelerators.Where(id => id.AcceleratorType == AcceleratorType.CPU).FirstOrDefault(); if (aid.AcceleratorType != AcceleratorType.Cuda) { Console.WriteLine(@"There is no CUDA accelerator present. Doing nothing."); return; } using (var accelerator = Accelerator.Create(context, aid)) { target.Matrices = null; // Be sure!! target.FillPoints(Terrain); target.FillMatricesRelativeToPoint(Terrain, target.Points[0][0]); // Matrices var cpu_matrices_size = target.Height * target.Width * 12; var basePoint = target.Points[0][0]; var cpu_matrices = MakeCPUMatrices(target); // Horizon (load from target) var cpu_horizon_size = target.Height * target.Width * Horizon.HorizonSamples; var cpu_horizon = new float[cpu_horizon_size]; // Initialize to float.MinValue. Maintain horizon as slope for (var i = 0; i < cpu_horizon_size; i++) { cpu_horizon[i] = float.MinValue; } // Caster array const int dem_size = TerrainPatch.DEM_size; const int patch_size = TerrainPatch.DefaultSize; var maxDistance = (float)TerrainPatch.MaximumLocalDistance; var border = 2 + (int)Math.Ceiling(maxDistance); // the 2 is margin for the bilinear interpolation var line_min = Math.Max(0, target.Line - border); var line_max = Math.Min(dem_size - 1, target.Line + patch_size + border); // 1 more than the highest index var line_size = line_max - line_min; var line_offset = target.Line - line_min; var sample_min = Math.Max(0, target.Sample - border); var sample_max = Math.Min(dem_size - 1, target.Sample + patch_size + border); // 1 more than the highest index var sample_size = sample_max - sample_min; var sample_offset = target.Sample - sample_min; var cpu_caster_points_size = line_size * sample_size * 3; var cpu_caster_points = new float[cpu_caster_points_size]; FillNearCasterArray(cpu_caster_points, target.Points[0][0], line_min, line_max, sample_min, sample_max); //DumpNearFieldTestCsv(cpu_caster_points, cpu_matrices); var test_floats_size = Horizon.HorizonSamples * TerrainPatch.NearHorizonOversample; var test_floats = new float[test_floats_size]; using (var gpu_matrices = accelerator.Allocate <float>(cpu_matrices_size)) using (var gpu_horizon = accelerator.Allocate <float>(cpu_horizon_size)) using (var gpu_caster_points = accelerator.Allocate <float>(cpu_caster_points_size)) using (var gpu_test_floats = accelerator.Allocate <float>(test_floats_size)) { gpu_matrices.CopyFrom(cpu_matrices, 0, 0, cpu_matrices_size); gpu_horizon.CopyFrom(cpu_horizon, 0, 0, cpu_horizon_size); gpu_caster_points.CopyFrom(cpu_caster_points, 0, 0, cpu_caster_points_size); gpu_test_floats.CopyFrom(test_floats, 0, 0, test_floats_size); var groupSize = accelerator.MaxNumThreadsPerGroup; Index launchDimension = Horizon.HorizonSamples * TerrainPatch.NearHorizonOversample; const float d_min = 1f; var d_max = (float)TerrainPatch.MaximumLocalDistance; const float d_step = TerrainPatch.LocalStep; var kernel1 = accelerator.LoadAutoGroupedStreamKernel <Index, int, int, int, int, int, int, float, float, float, ArrayView <float>, ArrayView <float>, ArrayView <float>, ArrayView <float> >(NearHorizonKernel1); Console.WriteLine(@"Launching near horizon kernels ... "); if (true) { for (var target_line = 0; target_line < TerrainPatch.DefaultSize; target_line++) { for (var target_sample = 0; target_sample < TerrainPatch.DefaultSize; target_sample++) { kernel1(launchDimension, target_line, target_sample, line_offset, sample_offset, line_size, sample_size, d_min, d_max, d_step, gpu_caster_points, gpu_matrices, gpu_horizon, gpu_test_floats); } } } else { kernel1(launchDimension, 0, 0, line_offset, sample_offset, line_size, sample_size, d_min, d_max, d_step, gpu_caster_points, gpu_matrices, gpu_horizon, gpu_test_floats); } gpu_horizon.CopyTo(cpu_horizon, 0, 0, cpu_horizon_size); gpu_test_floats.CopyTo(test_floats, 0, 0, test_floats_size); // Update the horizons for (var line = 0; line < TerrainPatch.DefaultSize; line++) { for (var sample = 0; sample < TerrainPatch.DefaultSize; sample++) { var offset = (line * TerrainPatch.DefaultSize + sample) * Horizon.HorizonSamples; var buffer = target.Horizons[line][sample].Buffer; for (var i = 0; i < Horizon.HorizonSamples; i++) { buffer[i] = cpu_horizon[i + offset]; } } } } } } }
/// <summary> /// Update the horizons of a patch based on a list of shadow casters. /// The horizons will be in slope, not angle, format /// </summary> /// <param name="target"></param> /// <param name="casters"></param> public void UpdateHorizons(TerrainPatch target, List <TerrainPatch> casters) { Debug.Assert(Terrain != null); if (casters.Count < 1) { return; } using (var context = new Context()) { AcceleratorId aid = Accelerator.Accelerators.Where(id => id.AcceleratorType == AcceleratorType.Cuda).FirstOrDefault(); if (aid.AcceleratorType != AcceleratorType.Cuda) { Console.WriteLine(@"There is no CUDA accelerator present. Doing nothing."); return; } using (var accelerator = Accelerator.Create(context, aid)) { target.FillPoints(Terrain); target.FillMatricesRelativeToPoint(Terrain, target.Points[0][0]); // Matrices var cpu_matrices_size = target.Height * target.Width * 12; var basePoint = target.Points[0][0]; var cpu_matrices = MakeCPUMatrices(target); // Horizon (load from target) var cpu_horizon_size = target.Height * target.Width * Horizon.HorizonSamples; var cpu_horizon = new int[cpu_horizon_size]; for (var line = 0; line < TerrainPatch.DefaultSize; line++) { for (var sample = 0; sample < TerrainPatch.DefaultSize; sample++) { var offset = (line * TerrainPatch.DefaultSize + sample) * Horizon.HorizonSamples; var buffer = target.Horizons[line][sample].Buffer; for (var i = 0; i < Horizon.HorizonSamples; i++) { cpu_horizon[i + offset] = SlopeToEncoding(buffer[i]); } } } // Caster points var cpu_caster_points_size = casters[0].Width * casters[0].Height * 3; var cpu_caster_points = new float[cpu_caster_points_size]; // test array var cpu_test_array = new float[20]; using (var gpu_matrices = accelerator.Allocate <float>(cpu_matrices_size)) using (var gpu_horizon = accelerator.Allocate <int>(cpu_horizon_size)) using (var gpu_caster_points = accelerator.Allocate <float>(cpu_caster_points_size)) using (var gpu_test_array = accelerator.Allocate <float>(cpu_test_array.Length)) { gpu_matrices.CopyFrom(cpu_matrices, 0, 0, cpu_matrices_size); gpu_horizon.CopyFrom(cpu_horizon, 0, 0, cpu_horizon_size); var groupSize = accelerator.MaxNumThreadsPerGroup; var launchDimension = new GroupedIndex2( new Index2(128, 128), // (data.Length + groupSize - 1) / groupSize, // Compute the number of groups (round up) new Index2(1, 128)); var kernel1 = accelerator.LoadSharedMemoryStreamKernel1 <GroupedIndex2, ArrayView <float>, ArrayView <float>, ArrayView <int>, ArrayView <float>, ArrayView <int> >(ShadowKernel1); //var stopwatch = new Stopwatch(); //stopwatch.Start(); foreach (var caster in casters) { caster.FillPoints(Terrain); CopyPointsToCpuArray(caster, basePoint, cpu_caster_points); gpu_caster_points.CopyFrom(cpu_caster_points, 0, 0, cpu_caster_points_size); kernel1(launchDimension, gpu_caster_points, gpu_matrices, gpu_horizon, gpu_test_array); accelerator.Synchronize(); } // Copy out data gpu_horizon.CopyTo(cpu_horizon, 0, 0, cpu_horizon_size); gpu_test_array.CopyTo(cpu_test_array, 0, 0, cpu_test_array.Length); //stopwatch.Stop(); //Console.WriteLine($"kernel time={stopwatch.Elapsed} cpu_horizon.Max()={cpu_horizon.Max()} cpu_horizon[0]={cpu_horizon[0]}"); // Update the horizons for (var line = 0; line < TerrainPatch.DefaultSize; line++) { for (var sample = 0; sample < TerrainPatch.DefaultSize; sample++) { var offset = (line * TerrainPatch.DefaultSize + sample) * Horizon.HorizonSamples; var buffer = target.Horizons[line][sample].Buffer; for (var i = 0; i < Horizon.HorizonSamples; i++) { buffer[i] = EncodingToSlope(cpu_horizon[i + offset]); } } } //Console.WriteLine($" max slope={cpu_horizon.Select(EncodingToSlope).Max()}"); } } } }