private static Vec3 RandomUnitVector(XorShift64Star rng) { float a = 2f * XMath.PI * rng.NextFloat(); float z = (rng.NextFloat() * 2f) - 1f; float r = XMath.Sqrt(1f - z * z); return(new Vec3(r * XMath.Cos(a), r * XMath.Sin(a), z)); }
static void GetLatLon(float line, float sample, out float latitude, out float longitude) { var x = (sample - S0) * Scale; var y = (L0 - line) * Scale; var P = XMath.Sqrt(x * x + y * y); var C = 2f * GPUHorizons.Atan2(P, 2f * MoonRadius); latitude = GPUHorizons.Asin(XMath.Cos(C) * XMath.Sin(LatP) + (y == 0 ? 0 : y * XMath.Sin(C) * XMath.Cos(LatP) / P)); longitude = LonP + GPUHorizons.Atan2(x, y * LonFactor); }
// Returns the position in km static void GetVector3d(float line, float sample, float height_meters, out float x, out float y, out float z) { var radius = MoonRadius + height_meters / 1000f; GetLatLon(line, sample, out float lat, out float lon); z = radius * XMath.Sin(lat); var c = radius * XMath.Cos(lat); x = c * XMath.Cos(lon); // TODO: Not sure about these y = c * XMath.Sin(lon); }
public static Vector3 PointOnHemisphere(this XorShift64Star random, Vector3 n) { float azimuthal = random.NextFloat() * XMath.PI * 2f; float z = random.NextFloat(); float xyproj = XMath.Sqrt(1 - z * z); Vector3 v = new Vector3(xyproj * XMath.Cos(azimuthal), xyproj * XMath.Sin(azimuthal), z); if (Vector3.Dot(v, n) < 0) { return(v * -1); } else { return(v); } }
public static Vector3 GetGGXMicrofacet(XorShift64Star random, float roughness, Vector3 normal) { float rand1 = random.NextFloat(); float rand2 = random.NextFloat(); Vector3 B = GetPerpendicularVector(normal); Vector3 T = Vector3.Cross(B, normal); float a2 = roughness * roughness; float cosThetaH = XMath.Sqrt(XMath.Max(0f, (1f - rand1) / ((a2 - 1f) * rand1 + 1f))); float sinThetaH = XMath.Sqrt(XMath.Max(0f, 1f - cosThetaH * cosThetaH)); float phiH = rand2 * XMath.PI * 2f; return(T * (sinThetaH * XMath.Cos(phiH)) + B * (sinThetaH * XMath.Sin(phiH)) + normal * cosThetaH); }
public Ray GetRaySimple(float x, float y) { x = (x / (ScreenWidth - 1f) - 0.5f) * (ScreenWidth / ScreenHeight); y = (1f - y / (ScreenHeight - 1f)) - 0.5f; Vector3 direction = Vector3.Normalize(new Vector3(x * 36f, y * 36f, FocalLength)); float angle = -sphericalPosition.Y + XMath.PIHalf; float newY = direction.Y * XMath.Cos(angle) - direction.Z * XMath.Sin(angle); float newZ = direction.Z * XMath.Cos(angle) - direction.Y * XMath.Sin(angle); direction.Y = newY; direction.Z = newZ; angle = sphericalPosition.Z + XMath.PIHalf; float newX = direction.X * XMath.Cos(angle) - direction.Z * XMath.Sin(angle); newZ = direction.Z * XMath.Cos(angle) + direction.X * XMath.Sin(angle); direction.X = newX; direction.Z = newZ; return(new Ray(Position, direction)); }
static void NearFieldKernel1( Index2 index, // Contains (sample, line) First dimension changes fastest int target_line, // row within the 128 x 128 target patch int target_sample, // column int slope_idx_start, int slope_idx_stop, ArrayView <short> gpu_terrain, ArrayView <float> gpu_range, ArrayView <float> gpu_slope, ArrayView <float> gpu_rise, ArrayView <int> gpu_range_limit) { var flip = -LonFactor; // From ILGPU source code: public int ComputeLinearIndex(Index2 dimension) => Y * dimension.X + X; var rise_idx = index.ComputeLinearIndex(Dimension); var rise = gpu_rise[rise_idx]; var center_line = target_line + index.Y; var center_sample = target_sample + index.X; var center_idx = center_line * TerrainSize + center_sample; var center_height = 0.5f * gpu_terrain[center_idx]; GetVector3d(center_line, center_sample, center_height, out float center_x, out float center_y, out float center_z); center_z *= flip; for (var slope_idx = slope_idx_start; slope_idx < slope_idx_stop; slope_idx++) { var slope = gpu_slope[slope_idx]; // Work out the direction vector var ray_rad = XMath.PI * 2f * slope_idx / cpu_slope_size; // 0 deg in ME frame points toward the earth var ray_cos = XMath.Cos(ray_rad); // varies the line var ray_sin = XMath.Sin(ray_rad); // varies the sample // iterate over the ranges var range_limit = gpu_range_limit[slope_idx]; for (var range_idx = 0; range_idx < range_limit; range_idx++) { var range = gpu_range[range_idx]; var caster_line = center_line + ray_sin * range; var caster_sample = center_sample + ray_cos * range; 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_idx = y1 * TerrainSize + x1; var q11 = gpu_terrain[q11_idx]; var q12_idx = q11_idx + TerrainSize; var q12 = gpu_terrain[q12_idx]; // First interpolation across rows (line) var q1_line = q11 + (caster_line - y1) * (q12 - q11); var q21_idx = q11_idx + 1; var q21 = gpu_terrain[q21_idx]; var q22_idx = q11_idx + TerrainSize + 1; var q22 = gpu_terrain[q22_idx]; // Second interpolation across rows var q2_line = q21 + (caster_line - y1) * (q22 - q21); // Interpolate across samples and convert to meters var caster_height = q1_line + (caster_sample - x1) * (q2_line - q1_line); caster_height *= 0.5f; GetVector3d(caster_line, caster_sample, caster_height, out float caster_x, out float caster_y, out float caster_z); caster_z *= flip; var dx = caster_x - center_x; var dy = caster_y - center_y; var d = XMath.Sqrt(dx * dx + dy * dy); // horizontal distance in moon radius units var light_ray_height = caster_z - slope * d; // negative slope gets higher as light ray goes toward the center var ray_rise_height = light_ray_height - center_z; // moon radius units var ray_rise_meters = ray_rise_height * 1000f; // Alternative //var dInMeters = d * 1000f; //var deltaHeightInMeters = (caster_z - center_z) * 1000f; //var rise2 = deltaHeightInMeters - dInMeters * slope; rise = XMath.Max(rise, ray_rise_meters); } } gpu_rise[rise_idx] = rise; }
public Vector3 GetIndirectDiffuse2(XorShift64Star random, Scene scene, Vector3 position, Vector3 normal) { Vector3 lightAccumulator = new Vector3(); int samples = 4; for (int i = 0; i < samples; i++) { float azimuthal = random.NextFloat() * XMath.PI * 2f; float z = random.NextFloat(); float xyproj = XMath.Sqrt(1 - z * z); Vector3 dir = new Vector3(xyproj * XMath.Cos(azimuthal), xyproj * XMath.Sin(azimuthal), z); if (Vector3.Dot(dir, normal) < 0) { dir *= -1; } Ray ray = new Ray(position + dir * 0.002f, dir); Intersection intersection = scene.TraceScene(ray); if (!intersection.Hit && !intersection.HitLight) { lightAccumulator += Vector3.Multiply(scene.SkylightColor * scene.SkylightBrightness * Vector3.Dot(dir, normal), DiffuseColor) * Diffuse; continue; } else if (!intersection.Hit || intersection.HitLight) { continue; } Material hitMaterial = intersection.HitObject.Material; Vector3 lightC = hitMaterial.GetShaded3(random, scene, intersection.HitPosition, dir, intersection.HitNormal); lightC *= Vector3.Dot(dir, normal); lightAccumulator += Vector3.Multiply(lightC, DiffuseColor) * Diffuse; } lightAccumulator /= (float)samples; return(lightAccumulator); }
static double Evaluate(int individualIndex, int independentsRowIndex, ArrayView2D <double> independents, ArrayView <NodeGPU> nodes, ArrayView <int> nodeArrayStarts) { for (int nodeIndex = 0; nodeIndex < nodeArrayStarts.Length; nodeIndex++) { Index1 currentNodeIndex = new Index1(nodeArrayStarts[individualIndex] + nodeIndex); //NodeGPU currentNode = nodes[currentNodeIndex]; if (nodes[currentNodeIndex].IndependentIndex >= 0) { int independentIndex = nodes[currentNodeIndex].IndependentIndex; nodes[currentNodeIndex].Number = independents[independentsRowIndex, independentIndex]; } else if (nodes[currentNodeIndex].OperatorIndex >= 0) { Index1 branchIndex1 = new Index1(nodeArrayStarts[individualIndex] + nodes[currentNodeIndex].Branch1); Index1 branchIndex2 = new Index1(nodeArrayStarts[individualIndex] + nodes[currentNodeIndex].Branch2); if (nodes[currentNodeIndex].OperatorIndex < 6) { if (nodes[currentNodeIndex].OperatorIndex < 4) { if (nodes[currentNodeIndex].OperatorIndex == 2) { nodes[currentNodeIndex].Number = nodes[branchIndex1].Number + nodes[branchIndex2].Number; } else if (nodes[currentNodeIndex].OperatorIndex == 3) { nodes[currentNodeIndex].Number = nodes[branchIndex1].Number - nodes[branchIndex2].Number; } } else { if (nodes[currentNodeIndex].OperatorIndex == 4) { nodes[currentNodeIndex].Number = nodes[branchIndex1].Number * nodes[branchIndex2].Number; } else if (nodes[currentNodeIndex].OperatorIndex == 5) { nodes[currentNodeIndex].Number = nodes[branchIndex1].Number / nodes[branchIndex2].Number; } } } else if (nodes[currentNodeIndex].OperatorIndex >= 6 && nodes[currentNodeIndex].OperatorIndex <= 15) { if (nodes[currentNodeIndex].OperatorIndex == 6) { nodes[currentNodeIndex].Number = -nodes[branchIndex1].Number; } else if (nodes[currentNodeIndex].OperatorIndex == 8) { nodes[currentNodeIndex].Number = XMath.Sin(nodes[branchIndex1].Number); } else if (nodes[currentNodeIndex].OperatorIndex == 9) { nodes[currentNodeIndex].Number = XMath.Cos(nodes[branchIndex1].Number); } else if (nodes[currentNodeIndex].OperatorIndex == 14) { nodes[currentNodeIndex].Number = XMath.Pow(nodes[branchIndex1].Number, nodes[branchIndex2].Number); } else if (nodes[currentNodeIndex].OperatorIndex == 15) { nodes[currentNodeIndex].Number = XMath.Sign(nodes[branchIndex1].Number); } } else { Index1 branchIndex3 = new Index1(nodeArrayStarts[individualIndex] + nodes[currentNodeIndex].Branch3); Index1 branchIndex4 = new Index1(nodeArrayStarts[individualIndex] + nodes[currentNodeIndex].Branch4); if (nodes[currentNodeIndex].OperatorIndex == 18) { if (nodes[branchIndex1].Number == nodes[branchIndex2].Number) { nodes[currentNodeIndex].Number = nodes[branchIndex3].Number; } else { nodes[currentNodeIndex].Number = nodes[branchIndex4].Number; } } else if (nodes[currentNodeIndex].OperatorIndex == 19) { if (nodes[branchIndex1].Number < nodes[branchIndex2].Number) { nodes[currentNodeIndex].Number = nodes[branchIndex3].Number; } else { nodes[currentNodeIndex].Number = nodes[branchIndex4].Number; } } else if (nodes[currentNodeIndex].OperatorIndex == 20) { if (nodes[branchIndex1].Number <= nodes[branchIndex2].Number) { nodes[currentNodeIndex].Number = nodes[branchIndex3].Number; } else { nodes[currentNodeIndex].Number = nodes[branchIndex4].Number; } } else if (nodes[currentNodeIndex].OperatorIndex == 21) { if (nodes[branchIndex1].Number == 0) { nodes[currentNodeIndex].Number = nodes[branchIndex2].Number; } else { nodes[currentNodeIndex].Number = nodes[branchIndex3].Number; } } else if (nodes[currentNodeIndex].OperatorIndex == 22) { if (nodes[branchIndex1].Number == 1) { nodes[currentNodeIndex].Number = nodes[branchIndex2].Number; } else { nodes[currentNodeIndex].Number = nodes[branchIndex3].Number; } } } if (nodes[currentNodeIndex].Number == double.NaN) { return(double.NaN); } } if (nodes[currentNodeIndex].IsRoot == 1) { return(nodes[currentNodeIndex].Number); } } return(double.NaN); }
static double Sin(double x) => XMath.Sin((float)x);
// This kernel runs very quickly and is called 128 x 128 times. 128 x 128 runs takes 8 sec ... longer than the 5 sec timeout. // It would be better if more work were done in the kernel and the kernel were called fewer times, I think. static void NearFieldKernel1( 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, float observer_height_in_km, 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 = XMath.Cos(ray_angle); var ray_sin = XMath.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; azimuth_rad = Atan2(y, x) + XMath.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; // Adjust for solar array height (this is temporary, and I'm not sure we want this in the final version) z -= observer_height_in_km; var alen = XMath.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; }