using System.Globalization; /// /// The single author of Assets/Shaders/Gravity.cginc, the GPU lowering of the zone's potential. The law is /// GravityField's (its constants are read here, not respelled) and the height is Zone.GetHeight: each well's /// potential minus its reference, summed, divided by the exaggeration. Unity does not run C# when it imports a /// shader, so the committed cginc is this output; GravityShaderTests fails unless it equals Source() exactly. /// To change the shader, change this file and regenerate: AETHERIA_REGENERATE_GRAVITY_CGINC=1 dotnet test --filter GravityShaderTests. /// public static class GravityShader { public const string Path = "Assets/Shaders/Gravity.cginc"; /// The whole file, with LF line ends. public static string Source() => (Template .Replace("@TAIL@", GravityField.TailOffset.ToString("R", CultureInfo.InvariantCulture))) .Replace("\r\n", "\n"); private const string Template = @"#ifndef AETHERIA_GRAVITY_INCLUDED #define AETHERIA_GRAVITY_INCLUDED // GENERATED by ServerShared/GravityShader.cs from GravityField; do not edit (GravityShaderTests fails on any difference). // The lowering of the zone's potential (aetheria-gravity, cut grid-lowering). The law is ServerShared's GravityField // and the height is Zone.GetHeight; this file decides nothing. GravityLowering.Lower fills the buffer and the globals // from the zone (positions from Orbit.Position, reference from Zone.WellReference) each frame. // GravityFieldParityVerify renders it and compares every texel with -Zone.GetHeight. struct GravityWell { float2 position; float strength; float coreRadius; float reference; }; StructuredBuffer _GravityWells; int _GravityWellCount; float _HeightExaggeration; // GravityField.Potential: c is the well's strength, R its core radius, r the distance. float gravityPotential(float c, float R, float r) { return c == 0 ? 0 : r < R ? c * r * r / (2 * R * R) : c * (log(r / R) + @TAIL@); } // Zone.GetHeight at world xz: each well's potential minus its own reference, summed, divided by the exaggeration. float gravityHeight(float2 p) { float result = 0; for (int i = 0; i < _GravityWellCount; i++) { GravityWell well = _GravityWells[i]; result += gravityPotential(well.strength, well.coreRadius, length(p - well.position)) - well.reference; } return result / _HeightExaggeration; } #endif "; }