Signed Distance Functions (SDFs)
Signed distance functions in general represent geometry by providing a function that e.g. maps a point in R³ onto the closest scalar distance to the surface of the geometry [29]. This representation technique has already been used extensively for ray tracing applications in the field of computer graphics. For a quick introduction into SDFs the website of Inigo Quilez is referred to.
In the field of ray-based optical simulations, mathematical surface definitions, e.g. in the form of analytical equations for the surface sag or NURBs, are common [24, p. 44 ff]. However, they are also costly to implement since no "one-size-fits-all" algorithm exists which could be implemented for the intersect3d function. This is why for this package, SDFs have been chosen to represent curved surfaces. This is due to the fact that for exact SDFs
the point of intersection can be calculated exactly with reasonable convergence criteria
the normal vector at the point of intersection can be calculated exactly using automatic differentiation
the ray marching algorithm works for any shape that provides a SDF
the ray marching procedure can be computed very efficiently
The viability of SDFs for radiation transfer simulations has already been demonstrated in the literature [30]. For optical ray tracing this is a new application to the best of our knowledge. Representing lens shapes using the exact shape SDFs provided by Inigo Quilez is straight forward by combining cylinder and cut-sphere SDFs using boolean addition and subtraction. Further, custom iterative algorithms have been developed by O. Kliebisch in order to tie in (rotationally symmetrical) aspherical lenses into the ray marching formalism.
In order to implement new SDFs, the AbstractSDF interface should be used.
BeamletOptics.AbstractSDF Type
AbstractSDF <: AbstractShapeProvides a shape function based on signed distance functions. See https://iquilezles.org/articles/distfunctions/ for more information.
Implementation reqs.
Subtypes of AbstractSDF should implement all reqs. of AbstractShape as well as the following:
Functions
sdf(::AbstractSDF, point): a function that returns the signed distance for a point in 3D space
The following shapes are currently implemented:
julia> BeamletOptics.list_subtypes(BeamletOptics.AbstractSDF);
└── BeamletOptics.AbstractSDF
├── BeamletOptics.AbstractCompositeSDF
│ ├── BeamletOptics.DifferenceSDF
│ └── BeamletOptics.UnionSDF
├── BeamletOptics.AbstractLensSDF
│ ├── BeamletOptics.AbstractAsphericalSurfaceSDF
│ │ ├── BeamletOptics.ConcaveAsphericalSurfaceSDF
│ │ └── BeamletOptics.ConvexAsphericalSurfaceSDF
│ ├── BeamletOptics.AbstractCylindricalSurfaceSDF
│ │ └── BeamletOptics.AbstractAcylindricalSurfaceSDF
│ │ ├── BeamletOptics.AconcaveCylinderSDF
│ │ └── BeamletOptics.AconvexCylinderSDF
│ ├── BeamletOptics.AbstractSphericalSurfaceSDF
│ │ ├── BeamletOptics.ConcaveSphericalSurfaceSDF
│ │ └── BeamletOptics.ConvexSphericalSurfaceSDF
│ ├── BeamletOptics.ConcaveCylinderSDF
│ ├── BeamletOptics.ConvexCylinderSDF
│ ├── BeamletOptics.MeniscusLensSDF
│ ├── BeamletOptics.PlanoSurfaceSDF
│ └── BeamletOptics.SphereSDF
├── BeamletOptics.BoxSDF
├── BeamletOptics.ConicSDF
├── BeamletOptics.CutSphereSDF
├── BeamletOptics.CylinderSDF
├── BeamletOptics.RightAnglePrismSDF
└── BeamletOptics.RingSDF
At least 25 types have been found.Ray marching algorithm
The algorithm works by iteratively propagating a ray from the point of origin through a scene. At each step, the SDF/s is/are evaluated at the current point along the ray. The scaral value tells the algorithm how far the current positions is from the nearest surface. This distance is guaranteed to be a safe step size: the ray can advance by that amount without “tunneling” through any geometry. The process repeats until one of two conditions is met: (1) the distance becomes smaller than a threshold (the ray has hit a surface), or (2) a maximum number of steps or maximum distance is exceeded (the ray escapes without hitting anything). A visualization of this process is provided below. A ray propagates from the left to the right end of the scene. The step size is visualized as the radius of a sphere for each iteration.

Surface normals can be estimated numerically by sampling the SDF gradient around the hit point or by generating the automatic derivative of the SDF for exact descriptions. BMO uses both procedures, depending on the SDF type.
Composite SDFs
In order to make use of the dispatch capability of Julia, boolean composite SDFs allow users to easily combine SDFs using the + and - operators. Both share a common field layout and pivot-aware kinematics, defined by the AbstractCompositeSDF interface:
BeamletOptics.AbstractCompositeSDF Type
AbstractCompositeSDF{T} <: AbstractSDF{T}Generic supertype for boolean composite SDFs, i.e. SDFs that combine two or more AbstractSDF operands into a single shape. Owns the field layout and pivot-aware kinematics shared by all boolean composites; concrete subtypes only need to define the boolean combination semantics (sdf, normal3d, thickness).
Implementation reqs.
Subtypes of AbstractCompositeSDF should implement all reqs. of AbstractSDF as well as the following:
Fields
dir::SMatrix{3, 3, T, 9}: the composite's own orientation matrixtransposed_dir::SMatrix{3, 3, T, 9}: transpose ofdirpos::Point3{T}: the composite's own position, in that field order, and the struct must bemutablesince every setter inAbstractShape.jl/AbstractSDF.jlassigns fields directly
Functions
operands: returns aTupleof every childAbstractSDF, in any ordersdf,normal3dandthicknessspecific to the boolean combination

Union
BeamletOptics.UnionSDF Type
UnionSDF{T, TT <: Tuple} <: AbstractSDF{T}This SDF represents the merging of two or more SDFs. If the constituent SDFs do not overlap (they can and should touch) the resulting SDF should be still exact if the constituent SDFs are exact.
The intended way to construct these is not explicitely but by just adding two AbstractSDFs using the regular + operator.
s1 = SphereSDF(1.0)
translate3d!(s1, Point3(0, 1.0, 0.0))
s2 = SphereSDF(1.0)
# will result in a SDF with two spheres touching each other.
s_merged = s1 + s2Difference
BeamletOptics.DifferenceSDF Type
DifferenceSDF{T, S, TT <: Tuple} <: AbstractCompositeSDF{T}Represents the boolean subtraction of one or more tools from a base AbstractSDF, i.e. base \ (tool_1 ∪ tool_2 ∪ …). Unlike UnionSDF, the constituent SDFs are required to overlap: the tools must intersect the base for anything to be removed.
The intended way to construct these is not explicitly but by subtracting AbstractSDFs using the regular - operator:
s1 = SphereSDF(1.0)
s2 = SphereSDF(0.5)
translate3d!(s2, Point3(0.5, 0.0, 0.0))
# will result in a sphere with a smaller, off-center sphere carved out of it
s_diff = s1 - s2Non-commutativity and evaluation order
Subtraction is neither commutative nor associative, so a - b and b - a differ, and a chain like a + b - c + d must keep track of when each operand was combined. Repeated subtraction is flattened along its own chain via the identity
so a - b - c produces a single DifferenceSDF with one base and a flat tools tuple, rather than deepening the type on every chained -. Mixed +/- chains still nest (e.g. a + b - c is (a + b) - c, and ... + d afterwards wraps the whole difference in a UnionSDF) — this is what keeps their meaning, since material added after a subtraction must not be carved away by it.
Exactness
Per iquilezles.org/articles/distfunctions, opSubtraction = max(-a, b) is only a bound, not an exact SDF: it under-estimates the true distance near the seam between base and tool. This is the safe direction for sphere tracing — an under-estimate never causes tunneling, it only costs a few extra ray marching iterations near concave creases. Correctness of ray marching hinges on normal3d being resolved by explicit operand selection (as implemented here) rather than by automatic differentiation, which picks the wrong sub-shape at the seam.
Exactness
Boolean addition of non-overlapping, exact SDFs stays exact. Boolean subtraction, by contrast, only yields a bound: max(-a, b) under-estimates the true distance near the seam between operands. This under-estimate is the safe direction for sphere tracing — it never causes tunneling, only a few extra ray marching iterations near concave creases. For information refer to the website of I. Quilez