static void NearHorizonKernel1( Index index, // Horizon angle as integer int target_line, // row within the 128 x 128 target patch int target_sample, // column int line_offset, int sample_offset, int points_rows, int points_columns, float d_min, float d_max, float d_step, ArrayView <float> points, ArrayView <float> matrices, ArrayView <float> horizon, ArrayView <float> test_floats) { //if (index == 0) //{ // var delme = 1; //} // Copy the matrix into registers var pos = (target_line * TerrainPatch.DefaultSize + target_sample) * 12; var row0x = matrices[pos++]; var row1x = matrices[pos++]; var row2x = matrices[pos++]; var row3x = matrices[pos++]; var row0y = matrices[pos++]; var row1y = matrices[pos++]; var row2y = matrices[pos++]; var row3y = matrices[pos++]; var row0z = matrices[pos++]; var row1z = matrices[pos++]; var row2z = matrices[pos++]; var row3z = matrices[pos]; // Work out the location of the central point in the point array float center_line = target_line + line_offset; float center_sample = target_sample + sample_offset; var caster_line_max = (float)points_rows - 1; var caster_sample_max = (float)points_columns - 1; // Work out the direction vector var ray_angle = 3.141592653589f * 2f * index / (TerrainPatch.NearHorizonOversample * Horizon.HorizonSamples); var ray_cos = GPUMath.Cos(ray_angle); var ray_sin = GPUMath.Sin(ray_angle); // Work out the direction in horizon space (the horizon offset). This duplicates the calculation of the first point. // I'm duplicating code rather than refactoring, because there would be a lot of values to pass float azimuth_rad; { var d = 1f; var caster_line = center_line + ray_sin * d; var caster_sample = center_sample + ray_cos * d; var x1 = (int)caster_sample; // Calculate the caster point by interpolating between four points from the points array var y1 = (int)caster_line; int x2 = x1 + 1; int y2 = y1 + 1; var q11_offset = 3 * (y1 * points_columns + x1); // (y1, x1); var q11 = new Vector3(points[q11_offset], points[q11_offset + 1], points[q11_offset + 2]); var q12_offset = 3 * (y2 * points_columns + x1); // (y2, x1); var q12 = new Vector3(points[q12_offset], points[q12_offset + 1], points[q12_offset + 2]); // First interpolation across rows (line) var q1_line = q11 + (caster_line - y1) * (q12 - q11); var q21_offset = 3 * (y1 * points_columns + x2); // (y1, x2); var q21 = new Vector3(points[q21_offset], points[q21_offset + 1], points[q21_offset + 2]); var q22_offset = 3 * (y2 * points_columns + x2); // (y2, x2); var q22 = new Vector3(points[q22_offset], points[q22_offset + 1], points[q22_offset + 2]); // Second interpolation across rows var q2_line = q21 + (caster_line - y1) * (q22 - q21); // Interpolate across samples var caster = q1_line + (caster_sample - x1) * (q2_line - q1_line); // Break out the coordinates var x_patch = caster.X; var y_patch = caster.Y; var z_patch = caster.Z; // Transform the point to the local frame var x = x_patch * row0x + y_patch * row1x + z_patch * row2x + row3x; var y = x_patch * row0y + y_patch * row1y + z_patch * row2y + row3y; var z = x_patch * row0z + y_patch * row1z + z_patch * row2z + row3z; // Adjust for solar array height (this is temporary, and I'm not sure we want this in the final version) z -= ObserverHeight; // meters azimuth_rad = GPUMath.Atan2(y, x) + GPUMath.PI; // [0,2PI] } var normalized_azimuth = (Horizon.HorizonSamples - 1) * azimuth_rad / (2d * Math.PI); // range [0,1) var horizon_offset = (int)(0.5d + normalized_azimuth); Debug.Assert(horizon_offset >= 0 && horizon_offset < Horizon.HorizonSamples); // index is which direction in [target_line,target_sample]'s horizon we're working on, but could be oversamples var horizon_index = (target_line * TerrainPatch.DefaultSize + target_sample) * Horizon.HorizonSamples + horizon_offset; var highest_slope = horizon[horizon_index]; //test_floats[index] = ray_sin; for (var d = d_min; d <= d_max; d += d_step) { // Generate the location of the caster point in the points array var caster_line = center_line + ray_sin * d; var caster_sample = center_sample + ray_cos * d; test_floats[index] = caster_sample; /*{ * var idx = index == 2160 ? 7 : 11; * test_floats[idx] = d; * test_floats[idx + 1] = ray_angle; * test_floats[idx + 2] = caster_line - line_offset; * test_floats[idx + 3] = caster_sample - sample_offset; * }*/ if (caster_line < 1f || caster_line > caster_line_max || caster_sample < 1f || caster_sample > caster_sample_max) { break; } // Calculate the caster point by interpolating between four points from the points array var x1 = (int)caster_sample; var y1 = (int)caster_line; int x2 = x1 + 1; int y2 = y1 + 1; var q11_offset = 3 * (y1 * points_columns + x1); // (y1, x1); var q11 = new Vector3(points[q11_offset], points[q11_offset + 1], points[q11_offset + 2]); var q12_offset = 3 * (y2 * points_columns + x1); // (y2, x1); var q12 = new Vector3(points[q12_offset], points[q12_offset + 1], points[q12_offset + 2]); // First interpolation across rows (line) var q1_line = q11 + (caster_line - y1) * (q12 - q11); var q21_offset = 3 * (y1 * points_columns + x2); // (y1, x2); var q21 = new Vector3(points[q21_offset], points[q21_offset + 1], points[q21_offset + 2]); var q22_offset = 3 * (y2 * points_columns + x2); // (y2, x2); var q22 = new Vector3(points[q22_offset], points[q22_offset + 1], points[q22_offset + 2]); // Second interpolation across rows var q2_line = q21 + (caster_line - y1) * (q22 - q21); // Interpolate across samples var caster = q1_line + (caster_sample - x1) * (q2_line - q1_line); // Break out the coordinates var x_patch = caster.X; var y_patch = caster.Y; var z_patch = caster.Z; // Transform the point to the local frame var x = x_patch * row0x + y_patch * row1x + z_patch * row2x + row3x; var y = x_patch * row0y + y_patch * row1y + z_patch * row2y + row3y; var z = x_patch * row0z + y_patch * row1z + z_patch * row2z + row3z; var alen = GPUMath.Sqrt(x * x + y * y); var slope = z / alen; if (slope > highest_slope) { highest_slope = slope; } /*if (target_line==0 && target_sample==0 && index == 0) * { * test_floats[0] = slope; * test_floats[1] = x_patch; * test_floats[2] = y_patch; * test_floats[3] = z_patch; * test_floats[4] = x; * test_floats[5] = y; * test_floats[6] = z; * }*/ } horizon[horizon_index] = highest_slope; }
static void ShadowKernel1( GroupedIndex2 index, ArrayView <float> points, ArrayView <float> matrices, ArrayView <int> horizon, ArrayView <float> test_array, [SharedMemory(1440)] ArrayView <int> horizon_shared) { var target_line = index.GridIdx.Y; var target_sample = index.GridIdx.X; var caster_line = index.GroupIdx.Y; Debug.Assert(index.GroupIdx.X == 1); // Copy horizon for a[target_line,target_sample] into shared memory { var dim = Group.Dimension.Y; var len = horizon_shared.Length; var passes = (len + (dim - 1)) / dim; var offset = (target_line * TerrainPatch.DefaultSize + target_sample) * len; for (var pass = 0; pass < passes; pass++) { var ptr = pass * dim + caster_line; if (ptr < len) // divergence { horizon_shared[ptr] = horizon[ptr + offset]; } } } Group.Barrier(); // Copy the matrix into registers var pos = (target_line * TerrainPatch.DefaultSize + target_sample) * 12; var row0x = matrices[pos++]; var row1x = matrices[pos++]; var row2x = matrices[pos++]; var row3x = matrices[pos++]; var row0y = matrices[pos++]; var row1y = matrices[pos++]; var row2y = matrices[pos++]; var row3y = matrices[pos++]; var row0z = matrices[pos++]; var row1z = matrices[pos++]; var row2z = matrices[pos++]; var row3z = matrices[pos]; for (var caster_sample = 0; caster_sample < TerrainPatch.DefaultSize; caster_sample++) { // Fetch the other point in local frame var points_offset = (caster_line * TerrainPatch.DefaultSize + caster_sample) * 3; var x_patch = points[points_offset]; var y_patch = points[points_offset + 1]; var z_patch = points[points_offset + 2]; // Transform the point to the local frame var x = x_patch * row0x + y_patch * row1x + z_patch * row2x + row3x; var y = x_patch * row0y + y_patch * row1y + z_patch * row2y + row3y; var z = x_patch * row0z + y_patch * row1z + z_patch * row2z + row3z; // Adjust for solar array height (this is temporary, and I'm not sure we want this in the final version) z -= ObserverHeight; // meters var azimuth = GPUMath.Atan2(y, x) + GPUMath.PI; // [0,2 PI] var alen = GPUMath.Sqrt(x * x + y * y); var slope = z / alen; var slopem = slope > 2f ? 2f : slope; slopem = slopem < -2f ? -2f : slopem; slopem = slopem / 4f; var slopei = (int)(slopem * 1000000); var horizon_index = (int)(0.5f + 1439 * (azimuth / (2f * GPUMath.PI))); Atomic.Max(horizon_shared.GetVariableView(horizon_index), slopei); if (caster_sample == 0 && caster_line == 0 && target_line == 0 && target_sample == 0) { test_array[0] = x_patch; test_array[1] = y_patch; test_array[2] = z_patch; test_array[3] = x; test_array[4] = y; test_array[5] = z; test_array[6] = slope; test_array[7] = slopem; test_array[8] = slopei; test_array[9] = row3x; test_array[10] = row3y; test_array[11] = row3z; } } Group.Barrier(); { var dim = Group.Dimension.Y; var len = horizon_shared.Length; var passes = (len + (dim - 1)) / dim; var offset = (target_line * TerrainPatch.DefaultSize + target_sample) * len; for (var pass = 0; pass < passes; pass++) { var ptr = pass * dim + caster_line; if (ptr < len) // divergence { horizon[ptr + offset] = horizon_shared[ptr]; } } } }