Gesigneerde Afstandsvelden: Een Visuele Introductie

EN NL ES PT-BR


Gesigneerde afstandsvelden (SDF’s) beantwoorden de belangrijkste vraag in procedurele graphics: waar is het dichtstbijzijnde oppervlak en aan welke kant sta ik? Weten wat de afstand tot het oppervlak op elk punt is, maakt ray marching, collision checks en vormcompositie mogelijk met eenvoudige rekenkunde in plaats van dure geometrieverwerking. In plaats van expliciet driehoeken, lijnen of polygonen op te slaan, definieer je een functie en evalueer je die op elk punt waar je informatie nodig hebt. Dat maakt SDF’s een natuurlijke keuze voor procedurele graphics, waar vormen vaak wiskundig worden opgebouwd, gecombineerd en vervormd.

Wat één Getal Je Kan Vertellen

Voor elk punt in de ruimte geeft een SDF op positie p\mathbf{p} een gesigneerde scalaire waarde d(p)d(\mathbf{p}) terug:

  • positief buiten de vorm
  • nul op het oppervlak
  • negatief binnen de vorm

De absolute waarde d(p)|d(\mathbf{p})| is de kortste afstand tot de grens en het teken vertelt aan welke kant je zit. Als d(p)=0.12d(\mathbf{p}) = -0.12, dan ligt het punt 0.12 eenheid binnen de vorm. Als d(p)=0.12d(\mathbf{p}) = 0.12, ligt het 0.12 eenheid buiten de vorm. Bij nul zit je op het oppervlak. Eén getal geeft je zowel een zijlabel als een afstand.

Dat betekent dat één scalair veld meer opslaat dan een binaire masker. Negatieve waarden tekenen contouren binnenin de vorm, nul markeert de grens zelf, en positieve waarden tekenen contouren erbuiten.

Inside Surface Outside

Beweeg over de heatmap om op elk punt de gesigneerde afstand te inspecteren. De uitlezing toont de waarde (negatief binnen, positief buiten) en labelt elke locatie als Binnen, Oppervlak of Buiten. De nulcontour, de vormgrens zelf, is altijd zichtbaar als een scherpe zwarte lijn. Gebruik het keuzemenu om te wisselen tussen vormen: Cirkel, Box, Afgeronde Box, Lijnsegment, Capsule en Regelmatige Veelhoek werken allemaal op dezelfde manier, ook al verandert de geometrie. Elke vorm toont zijn SDF-formule boven de parameterschuifregelaars, zodat je de wiskunde aan het veld kunt koppelen terwijl je straal, breedte of afronding aanpast.

Omdat de SDF op elk punt de afstand codeert, kun je het oppervlak met een vast bedrag verschuiven door simpelweg een margewaarde af te trekken. Dat creëert een collisionbuffer, een inspringing voor afschuiningen, of een uitgebreide schil zonder de oorspronkelijke vorm te veranderen. Hetzelfde veld dat het oppervlak definieert, geeft ook aan hoe ver alles er vandaan is, wat verklaart waarom SDF’s voorkomen in rendering-, physics- en isovlakextractie -pipelines zonder tussentijdse formaatconversie.

Formules voor Primitieve Vormen

Elke SDF-scène begint met eenvoudige bouwstenen. Elke primitieve heeft een compacte formule, en zodra je begrijpt hoe een paar ervan werken, wordt het patroon achter alle andere duidelijk.

De cirkel is het natuurlijke startpunt:

d(p)=pcrd(\mathbf{p}) = \|\mathbf{p} - \mathbf{c}\| - r

De term pc\|\mathbf{p} - \mathbf{c}\| meet de Euclidische afstand van het samplepunt p\mathbf{p} tot het middelpunt c\mathbf{c} van de cirkel. Door de straal rr af te trekken verschuift de nuldoorgang naar buiten, naar de cirkelgrens. Wanneer het punt exact op de grens ligt, is de afstand tot het middelpunt gelijk aan rr en geeft de formule nul terug. Buiten de cirkel is de afstand tot het middelpunt groter dan rr, dus het resultaat is positief. Binnenin is het kleiner dan rr, dus het resultaat is negatief en de grootte vertelt hoe ver naar binnen het punt zich bevindt.

In code is de cirkelformule een one-liner:

float circleSDF(vec2 p, vec2 center, float r) {
    return length(p - center) - r;
}

De box bouwt voort op hetzelfde idee maar gebruikt componentsgewijze afstandslogica. Voor een box gecentreerd op c\mathbf{c} met halve grootte b\mathbf{b}:

q=pcbd(p)=max(q,0)+min(max(qx,qy),0)\begin{aligned} \mathbf{q} &= |\mathbf{p} - \mathbf{c}| - \mathbf{b} \\ d(\mathbf{p}) &= \|\max(\mathbf{q}, 0)\| + \min(\max(q_x, q_y), 0) \end{aligned}

De eerste stap verplaatst het punt naar het lokale coördinatenstelsel van de box en trekt de halve extents af. Als elke component van q\mathbf{q} negatief is, bevindt het punt zich binnen de box. De tweede stap berekent de uiteindelijke afstand: max(q,0)\|\max(\mathbf{q}, 0)\| geeft de Euclidische afstand van buitenaf (nul wanneer binnen), en min(max(qx,qy),0)\min(\max(q_x, q_y), 0) geeft de penetratiediepte van binnenuit (nul wanneer buiten). Door ze op te tellen ontstaat één gesigneerde waarde die overal het SDF-contract volgt: positief buiten, negatief binnen, nul op het oppervlak.

In code:

float boxSDF(vec2 p, vec2 center, vec2 halfSize) {
    vec2 q = abs(p - center) - halfSize;
    return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0);
}

De twee termen op de laatste regel corresponderen direct met de buiten- en binnengevallen uit de uitleg hierboven. Wanneer het punt buiten is, is max(q.x, q.y) positief en is de min-term nul. Wanneer het punt binnen is, is max(q, 0.0) nul en draagt de min-term de negatieve penetratiediepte.

Dezelfde cirkelformule generaliseert direct naar drie dimensies: vervang de 2D-lengte door een 3D-lengte en de straal blijft hetzelfde. Het resultaat is het signed distance field voor een bol , een van de weinige vormen met overal in de ruimte een exacte afstand en het natuurlijke startpunt voor het opbouwen van complexere SDF-scènes.

Voor een uitgebreide referentie met driehoeken, capsules, torussen en vele andere vormen, zie Iñigo Quilez’ catalogus van afstandsfuncties.

Vormen Combineren met Constructive Solid Geometry

Eén SDF-primitief is zelden genoeg. De meeste scènes worden opgebouwd door meerdere velden te combineren. Deze strategie om complexe vormen te maken door eenvoudigere vormen met booleaanse-achtige operaties te combineren heet constructive solid geometry (CSG). Met SDF’s is CSG slechts een kwestie van een paar min- en max-bewerkingen op afstandswaarden, in plaats van de ingewikkelde mesh-doorkniptechnieken die driehoeksgebaseerde booleaanse operaties vereisen.

De standaard CSG-operatoren voor SDF’s zijn:

  • unie: min(a, b)
  • doorsnede: max(a, b)
  • aftrekking (A min B): max(a, -b)

Voor unie is de regel intuïtief: het dichtstbijzijnde oppervlak bepaalt lokaal de veldwaarde, dus je neemt de minimumafstand. Bij aftrekking (max(dA, -dB)) draaien punten binnen B van teken en snijden ze volume uit A weg. Dit is hoe gaten, uitsparingen en negatieve ruimte worden gebouwd in constructieve SDF-modellering. Het is ook hoe realtime vernietigbaar terrein werkt: een krater uithakken is één enkele aftrekking, en elke vervorming voegt slechts één term meer toe aan de CSG-boom.

0.50
0 primitives
Inside Outside

De visualisatie start in Aftrekking-modus: de ring snijdt een rond gat uit de box. De kleurenkaart toont het gesigneerde afstandsveld over de hele ruimte: blauw buiten, rood binnen, met een felle contour op het nuloppervlak. Schakel naar Unie om de twee vormen te zien samensmelten langs hun dichtstbijzijnde randen, en naar Doorsnede om alleen het overlappende gebied te zien. De hover-uitlezing toont de exacte gesigneerde afstand op elk punt, wat benadrukt dat elke operatie simpelweg een rekenkundige uitdrukking op de twee velden is. Voeg meer primitieven toe met de paletknoppen en sleep ze overlappend om complexere velden te bouwen.

Smooth Blending

Standaard min en max geven scherpe CSG-overgangen. Voor veel visuele stijlen is dat precies wat je wilt. Voor organische overgangen zijn smooth varianten gebruikelijk. Een populaire optie is smooth minimum (smin) met parameter kk:

h=clamp(0.5+0.5bak,0,1),smin(a,b,k)=mix(b,a,h)kh(1h)h = \mathrm{clamp}\left(0.5 + 0.5\frac{b-a}{k}, 0, 1\right), \quad \mathrm{smin}(a,b,k) = \mathrm{mix}(b,a,h) - k h(1-h)

Als kk groter wordt, verbreedt de blendzone. Als k0k \to 0, benadert het gedrag gewone min. Soortgelijke varianten bestaan voor smooth subtraction en smooth intersection.

0.50
0 primitives
Inside Outside

Hier staat de operatie vanaf het begin op Smooth Unie. De twee vormen overlappen elkaar met een verzachte grens waar ze samenkomen. Sleep de blend-schuifregelaar omhoog om de blendzone te verbreden, of schakel terug naar Unie om de scherpe naad te vergelijken met de soepele versie. De hover-uitlezing laat zien hoe de gecombineerde afstandswaarde verandert naarmate de kk-parameter de overgang verzacht.

Dit is de belangrijkste reden dat SDF-scènecode compact blijft. Een hele scenegraph kan worden teruggebracht tot één functie die één scalar teruggeeft. Je kunt diezelfde functie gebruiken voor rendering, collision checks, masking en effecten.

Smooth compositie is krachtig, maar verandert de lokale kromming en soms de veldkwaliteit. Als je pipeline afhankelijk is van strikte afstandsgaranties voor lange raystappen, kan agressief smoothen vragen om strakkere drempels of conservatievere staplogica.

Domeintransformaties en Herhaling

Een groot voordeel van SDF’s is dat je vaak de inputruimte transformeert in plaats van de vormfunctie zelf. Veelgebruikte domeintransformaties:

  1. Translatie: evalueer op pt\mathbf{p} - \mathbf{t}
  2. Rotatie: evalueer op R1pR^{-1}\mathbf{p}, waarbij R1R^{-1} de inverse van de rotatiematrix is (de tegenovergestelde rotatie toepassen op het invoerpunt)
  3. Schaling: evalueer op p/s\mathbf{p}/s en schaal de afstand terug met ss
  4. Herhaling: omhul coördinaten met mod of fract om een vorm in een raster te herhalen

Met die aanpak kan één primitive-definitie veel instanties opleveren. Een enkele cirkel-SDF wordt bijvoorbeeld een raster van cirkels door de invoercoördinaten door een mod-bewerking te voeren die ze over de ruimte verdeelt. Dat is een belangrijke reden waarom SDF’s populair zijn in shaders met veel procedurele inhoud.

Domeintransformaties combineren ook goed met ruis. Met value noise, Perlin noise en fractale ruis kun je coördinaten of afstandswaarden moduleren voor steenachtige, vloeibare of wolkachtige structuren, terwijl je dezelfde function-first modellering behoudt.

Gebakken Velden: Geometrie Samplen naar een Raster

Niet elke vorm komt als een nette formule. Letterglyphs, vernietigbaar terrein, gescande modellen en handgemaakte polygonenmeshes hebben allemaal SDF’s nodig, maar missen een gesloten-vorm uitdrukking. Voor zulke geometrie moet het veld worden berekend en opgeslagen in plaats van analytisch afgeleid.

Dit proces heet baking: gesigneerde afstanden vooraf berekenen op elk punt van een regelmatig raster, de samples opslaan en interpoleren tussen samples om toekomstige queries te beantwoorden. Het ruilt rekentijd-per-query in voor eenmalig-berekenen-vaak-uitlezen, en exacte afstand voor benaderde afstand.

Inside Outside Surface

Druk op play om de per-cel evaluatie te volgen: elk rasterpunt vindt de dichtstbijzijnde polygoonrand en noteert een gesigneerde afstand. De kleuroverlay toont bilineaire interpolatie die het veld reconstrueert uit die discrete samples. Bij lage resolutie wijkt de nulcontour zichtbaar af van de echte randen en ronden hoeken af. Resolutie verhogen verkleint de fout, maar verdubbelen kost 4× meer samples in 2D en 8× in 3D.

Eenmaal gebakken zijn dezelfde downstream technieken nog steeds van toepassing. CSG-operaties, oppervlaktenormalen en ray marching gebruiken allemaal dezelfde scalaire waarden, ongeacht of een formule of een raster ze produceerde, al hebben geïnterpoleerde velden ruimere stapveiligheidsmarges nodig omdat ze de exacte afstandsgarantie niet behouden. Voor een diepere blik op resolutiekeuzes, interpolatieartefacten, adaptief samplen en productietoepassingen zoals Valve’s SDF-tekstweergave en Unreal Engine 5 mesh-afstandsvelden, zie het artikel gebakken gesigneerde afstandsvelden .

Oppervlaktenormalen uit de SDF-Gradiënt

Zodra een ray marcher of andere query een oppervlaktepunt vindt, is de volgende vraag meestal in welke richting dat oppervlak wijst. Oppervlaktenormalen zijn essentieel voor belichting, reflecties en botsingsrespons: ze vertellen je hoe licht van het oppervlak weerkaatst en in welke richting objecten moeten glijden wanneer ze elkaar raken.

Een SDF kan dit beantwoorden zonder een aparte normalenbuffer op te slaan. Omdat het veld op elk punt de afstand codeert, wijst de richting waarin de afstand het snelst toeneemt altijd weg van het dichtstbijzijnde oppervlak. Dicht bij de grens is die richting de naar buiten gerichte oppervlaktenormaal. Wiskundig gezien geeft de gradiënt d(p)\nabla d(\mathbf{p}) deze richting.

Gradient arrow Surface normal

De visualisatie toont gradiëntpijlen als overlay op de SDF-heatmap. Elke pijl wijst in de richting van f\nabla f op zijn samplelocatie, en het patroon is direct zichtbaar: alle pijlen stralen naar buiten vanaf het dichtstbijzijnde oppervlak, ongeacht de vorm. Beweeg ergens over het veld en er verschijnt een probe met de gesigneerde afstand, gradiëntrichting en gradiëntgrootte op dat exacte punt. De uitlezing labelt de pijl als oppervlaktenormaal wanneer de cursor zich nabij de nulcontour bevindt, wat de relatie tussen gradiënt en normaal expliciet maakt. Klik om de probe vast te zetten en schakel vervolgens tussen cirkel, box, afgeronde box, lijnsegment en een samengestelde unie van twee cirkels om te bevestigen dat normalen op dezelfde manier uit de veldstructuur ontstaan bij elke vorm.

Merk op dat de gradiëntgrootte over het hele veld op of nabij 1 blijft. Dit is de eikonale eigenschap (f=1|\nabla f| = 1) die exacte SDF’s bijzonder maakt: de gradiëntrichting is al een eenheidsvector. Wanneer de probe op de nul-isosurface staat, ligt de pijl exact loodrecht op de oppervlaktegrens. Die loodrechte richting is de oppervlaktenormaal, en omdat de gradiëntgrootte 1 bedraagt, is er geen aparte normalisatiestap nodig behalve het delen door de eindige-verschil-constante.

In de praktijk worden gradiënten numeriek geschat met behulp van eindige verschillen, wat inhoudt dat je de SDF bemonstert op punten die iets zijn verschoven in elke as en meet hoeveel de afstand verandert:

d(p)[d(p+εx)d(pεx)d(p+εy)d(pεy)]\nabla d(\mathbf{p}) \approx \begin{bmatrix} d(\mathbf{p}+\varepsilon_x)-d(\mathbf{p}-\varepsilon_x) \\ d(\mathbf{p}+\varepsilon_y)-d(\mathbf{p}-\varepsilon_y) \end{bmatrix}

De oranje stippen rond de probe tonen precies deze samplepunten: twee langs de x-as op ±ε\pm\varepsilon en twee langs de y-as, elk gelabeld met de afstandswaarde die daar is gesampled. Sleep de ε\varepsilon-schuifregelaar om de afweging te zien. Bij een zeer kleine ε\varepsilon (0.001) kruipen de stencilpunten dicht bij de probe en kan de gradiënt ruis worden. Bij een grotere ε\varepsilon (0.5) spreidt de stencil zich wijd uit en wordt de gradiënt gladder, maar kan deze afwijken van de ware oppervlaktenormaal bij scherpe hoeken of gebieden met sterke kromming. De standaardwaarde ε=0.01\varepsilon = 0.01 balanceert nauwkeurigheid en stabiliteit voor de meeste analytische SDF’s.

Na het berekenen van beide componenten normaliseer je de resulterende vector voordat je deze in belichtingsberekeningen gebruikt. Dit is fundamenteel in veldgebaseerde rendering, omdat er geen expliciete mesh-normalenbuffer is om te raadplegen. Hetzelfde SDF-veld dat het oppervlak lokaliseert, schat ook de oriëntatie voor diffuse en speculaire belichting, reflecties of omgevingseffecten.

Veldkwaliteit en Afstandsgaranties

Niet elk gesigneerd afstandsveld is een exact afstandsveld. Een SDF afgeleid van een formule (zoals de cirkel- of box-voorbeelden eerder) geeft de ware Euclidische afstand tot het dichtstbijzijnde oppervlak terug. Een veld gebakken uit een mesh, een smooth CSG-blend of een afstandsschatter van een ruisfunctie kan een waarde teruggeven die gesigneerd en ruwweg afstand-achtig is, maar geen strikte bovengrens vormt voor hoe ver een ray veilig kan stappen.

Het onderscheid is belangrijk omdat downstream-technieken afhangen van de kracht van de afstandsgarantie. Sphere tracing en sphere casting zijn alleen aantoonbaar veilig wanneer het veld de afstand nooit overschat. Als een veld de afstand onderschat (0,2 teruggeeft terwijl de ware afstand 0,5 is), neemt de marcher kleinere stappen dan nodig maar convergeert nog steeds. Als het overschat (0,5 teruggeeft terwijl de ware afstand 0,2 is), kan de marcher door een dunne wand of smal detail heen stappen.

In de praktijk hebben exacte analytische SDF’s de voorkeur wanneer veiligheidsmarges belangrijk zijn, zoals bij botsingsdetectie of lange camerastralen. Smooth CSG-blends, gebakken roosters en ruis-gemoduleerde oppervlakken versoepelen de exacte-afstandsgarantie in verschillende mate. Het ray marching-artikel behandelt hoe je stapveiligheid, epsilon-drempels en staplimieten beheert bij lossere afstandsschatters.

Waar SDF’s Passen in een Renderpipeline

SDF’s zijn een representatiekeuze, geen universele vervanging voor meshes. Ze zijn sterk wanneer vormen procedureel, sterk vervormbaar of compositie-intensief zijn. Meshes blijven beter waar handgemaakte topologie, UV-workflows en directe triangle-acceleratie belangrijk zijn.

Een praktische hybride pipeline werkt meestal als volgt: rasterizeer de hoofdscènegeometrie (personages, gebouwen, terrein) als driehoeken en gebruik vervolgens SDF’s voor specifieke effecten die profiteren van afstandsquery’s. Bijvoorbeeld:

  • Zachte schaduwen en ambient occlusion kunnen worden berekend door een SDF van de statische omgeving te evalueren als een nabewerking of tijdens belichting, ook al zijn de zichtbare oppervlakken zelf gerasteriseerd.
  • Decals en procedurele details (brandplekken, kogelgaten, plassen) kunnen op gerasteriseerde oppervlakken worden geprojecteerd door een SDF te evalueren om plaatsing en blending te bepalen.
  • Volumetrische effecten zoals mist, rook en lichtbundels gebruiken afstandsvelden om te bepalen hoe ver een ray door lege ruimte kan reizen voordat hij een oppervlak raakt, ongeacht of dat oppervlak is gerasteriseerd of ray-marched.
  • Botsings- en physics-query’s tegen statische levelgeometrie gebruiken een gebakken SDF-grid, terwijl de dynamische objecten die ernaar vragen standaard rigid-body meshes zijn. Dezelfde veldrepresentatie die rendering stuurt beantwoordt ook vragen over penetratiediepte, scheidingsrichting en continue botsingsdetectie, met toepassingen die reiken tot AI-pathfinding en realtime zachte schaduwen. Voor een overzicht van hoe deze technieken in een game-engine samenwerken, zie signed distance fields in game development .

Het belangrijkste inzicht is dat SDF-evaluatie en driehoeksrasterisatie in aparte passes opereren die elkaar voeden. Je kunt een personage rasterizen met traditionele GPU-hardware en vervolgens een afstandsveld samplen in de fragment shader om zachte zelfschaduwing van de omgeving toe te voegen. Je kunt een deeltjessysteem renderen als schermgerichte quads en vervolgens een SDF gebruiken in de vertex shader om deeltjes weg te duwen van procedurele oppervlakken. De representaties bestaan naast elkaar omdat ze verschillende vragen beantwoorden: driehoeken beantwoorden “welke kleur heeft deze pixel?” en SDF’s beantwoorden “hoe ver is het dichtstbijzijnde oppervlak vanaf dit punt?”

Voor de volledige ray-traversalcontext kun je ray marching met signed distance fields erbij pakken. Voor GPU-context over pipelinefasen is vertex en fragment shaders in de grafische pipeline nuttige achtergrond.

Samenvatting

Gesigneerde afstandsvelden modelleren vorm als één scalaire functie met twee kernbeloftes: afstandsgrootte en inside/outside-teken. Vanuit die ene representatie kun je:

  1. rays marchen met afstandsgeleide veilige stappen
  2. scènes opbouwen via min- en max-operatoren
  3. normalen schatten via eindige-verschillen gradiënten
  4. domeintransformaties toepassen om complexe procedurele layouts te bouwen

Die combinatie van compacte modellering en herbruikbare evaluatielogica maakt SDF’s zo krachtig in procedurele graphics. Als het veldcontract helder is, blijken veel “complexe” technieken variaties op hetzelfde patroon: evalueer afstand, gebruik die waarde om te beslissen wat de volgende stap is, en herhaal.