using System.Runtime.InteropServices; using System.Text.Json.Serialization; namespace Sandbox; /// /// Represents a sphere. /// [StructLayout( LayoutKind.Sequential )] public struct Sphere { /// /// A sphere centered at the origin, with radius 1. /// public static Sphere Unit { get; } = new( 0f, 1f ); public Sphere( Vector3 center, float radius ) { Center = center; Radius = radius; } public override readonly string ToString() { return $"Center({Center}), Radius({Radius})"; } /// /// Center of the sphere. /// [JsonInclude] public Vector3 Center; /// /// Radius of the sphere. /// [JsonInclude] public float Radius; /// /// Performs an intersection test between this sphere and given ray. /// public readonly bool Trace( Ray ray, float maxDistance, out float distance ) { distance = 0; var dirToCenter = ray.Position - Center; var v = (ray.Forward.Dot( Center - ray.Position )); var disc = Radius * Radius - ((dirToCenter.Dot( dirToCenter )) - v * v); if ( disc >= 0.0f ) { var time = (v - MathF.Sqrt( disc )) / maxDistance; distance = maxDistance * time; return (time >= 0.0f && time <= 1.0f); } return false; } /// /// Performs an intersection test between this sphere and given ray. /// public readonly bool Trace( Ray ray, float maxDistance ) { var dirToCenter = ray.Position - Center; var v = (ray.Forward.Dot( Center - ray.Position )); var disc = Radius * Radius - ((dirToCenter.Dot( dirToCenter )) - v * v); if ( disc >= 0.0f ) { var time = (v - MathF.Sqrt( disc )) / maxDistance; return (time >= 0.0f && time <= 1.0f); } return false; } /// /// Returns true if sphere contains point. False if the point falls outside the sphere. /// public bool Contains( in Vector3 value ) { return (value - Center).Length <= Radius; } /// /// Volume of this sphere /// [JsonIgnore] public readonly float Volume { get { return (4.0f / 3.0f) * MathF.PI * Radius * Radius * Radius; } } /// /// Get the volume of this sphere /// [Obsolete( "Use Sphere.Volume instead." )] public readonly float GetVolume() { return Volume; } /// /// Calculates the shortest distance from the specified local position to the nearest edge of the object. /// public readonly float GetEdgeDistance( Vector3 localPos ) { float distanceToCenter = (localPos - Center).Length; return MathF.Abs( distanceToCenter - Radius ); } /// /// Returns a random point within this sphere. /// [JsonIgnore] public readonly Vector3 RandomPointInside { get { return Center + System.Random.Shared.VectorInSphere( Radius ); } } /// /// Returns a random point on the edge of this sphere. /// [JsonIgnore] public readonly Vector3 RandomPointOnEdge { get { return Center + System.Random.Shared.VectorInSphere( 1 ).Normal * Radius; } } }