Raytacing: Einfache Schnitttests Ceative Commons Namensnennung 3.0 Deutschland http://ceativecommons.og/licenses/by/3.0/de/ P. Hofmann, 22. August 2010 http://www.uninfomativ.de Einleitung Tests, ob ein Stahl ein Objekt schneidet, sind die gundlegenden Opeationen beim Raytacing. Sie entscheiden, was letztendlich auf dem Bildschim zu sehen ist. Dei diese Tests sollen hie nun vogestellt weden: Stahl vs. Kugel Stahl vs. Ebene Stahl vs. Deieck Die Listings zeigen dabei geküzten Pogammcode aus dem NetTace, einem in Java geschiebenen, netzwekfähigen Raytace: http://www.uninfomativ.de/pojects/?q=nettace Im gesamten Dokument sei ein Stahl imme paametisiet als: q = p + α u p ist de Uspungspunkt des Stahls und u seine Richtung, dabei sei u imme nomiet. In diese Richtung bewegt man sich α Schitte weit. Gewöhnlich sind also p und u fest, α wid meistens positiv sein, da man sich nach vone bewegt, um die möglichen Punkte q auf dem Stahl zu eeichen.
Schnitttest mit eine Kugel 2 1 Schnitttest mit eine Kugel Eine Kugel sei gegeben übe ihen Mittelpunkt c und den Radius. Voausgesetzt, de Stahl schneidet die Kugel, dann liegt folgende Situation vo: q c Gesucht ist nun zuest de Punkt q: Diese liegt auf dem Stahl und hat den geingsten Abstand zum Kugelmittelpunkt. Hat man q gefunden, dann kann man sich übe den Satz des Pythagoas die beiden Schnittpunkte eechnen. Von diesen wid späte gegebenenfalls ein geeignete ausgewählt. De Punkt q muss nun die Bedingung efüllen, dass e auf dem Stahl de nächste Punkt zum Kugelmittelpunkt ist. Das heißt, die Vebindungsstecke von c nach q muss senkecht zum Stahl sein, wie auch schon in de Skizze eingezeichnet. Außedem kann q übe den Stahl dagestellt weden als q = p + α u, wobei α gesucht ist. Fomal ist dann: ( q c) u = 0 p + α u c u = 0 q Nutzt man nun, dass u u = 1, da u nomiet ist, dann lässt sich diese Gleichung in die folgende Fom bingen und de Paamete α bestimmen: α = ( p c) u Mittels dieses α gelangt man zum Punkt q. Nun lässt sich beeits testen, ob de Stahl die Kugel übehaupt schneiden kann. Dazu wid einfach die Stecke von c nach q gemessen. Ist diese göße als de Kugeladius, gibt es keinen Schnitt. De folgende Satz 1 fasst diesen esten Schnitttest zusammen. Satz 1 (Bedingung fü Schnitt mit Kugel) Ein Stahl q = p + α u schneidet eine Kugel mit Mittelpunkt c und Radius genau dann, wenn q c, wobei α = ( p c) u. Sei nun ein gültiges q gegeben, sodass de Stahl die Kugel schneidet. Bishe ist abe noch unkla, wo diese Schnitt stattfindet dafü ist noch keine Bedingung gegeben, de Schnittpunkt kann also auch in negative Richtung vo dem Stahluspung liegen, was ungewünscht ist. Diese Situation muss beim Raytacing als
Schnitttest mit eine Kugel 3 kein Schnitt gewetet weden, obwohl de Stahl als Geade aufgefasst die Kugel tatsächlich schneidet. Fene ist bei zwei Schnittpunkten noch unbekannt, welche gewählt weden soll. Um übe den Pythagoas zu den beiden Schnittpunkten zu kommen, sei noch die skalae Göße x eingefüht: x q x c x ist noch unbekannt. Es ist de Abstand von q zu einem de beiden Schnittpunkte und lässt sich übe eines de beiden Deiecke bestimmen, also: 2 = x 2 + q c 2 x = 2 q c 2 Geht man nun davon aus, dass de Stahl außehalb de Kugel statet und diese in positive Stahlichtung schneidet, dann ist kla, dass h = p + (α x) u de gewünschte Schnittpunkt ist. Man geht also zuest zu q und dann wiede um x zuück zum Schnittpunkt. Es kann abe vokommen, dass ein Stahl innehalb de Kugel statet. Das ist voallem dann de Fall, wenn man Tansmission-Rays duch lichtduchlässige Mateialien vefolgt. Hie ist dann de Austittspunkt aus de Kugel gesucht, das heißt, man geht est zu q, abe dann in positive Stahlichtung um x weite. De Schnittpunkt ist dann gegeben als h = p + (α + x) u. Diese beiden Fälle gilt es als mögliche Schnittszenaien zu untescheiden. De ditte mögliche Fall, wenn nämlich de Stahl hinte de Kugel statet, also beeits wiede außehalb, füht dazu, dass es nu in negative Stahlichtung Schnittpunkte gibt. Diese inteessieen dann nicht weite und die Situation wid als kein Schnitt gewetet. Satz 2 stellt nun fomale Bedingungen an α und x, die zu Wahl des ichtigen Schnittpunktes genutzt weden. Satz 2 (Auswahl des Kugelschnittpunktes) Gegeben sei α zum Punkt q, de dem Kugelmittelpunkt am nächsten ist, außedem de Vaiationspaamete x. q efülle die Bedingung von Satz 1 auf Seite 2. Dann ist de gesuchte Schnittpunkt h: a) Gilt α x, dann ist h = p + (α x) u. b) Ist das nicht de Fall, abe α + x > 0, dann ist h = p + (α + x) u. c) Tifft keine diese Bedingungen zu, dann existiet kein Schnittpunkt in positive Stahlichtung. Um sich diese Bedingungen ichtig kla zu machen, beginnt man am besten mit dem esten Fall: De Stahl statet links außehalb de Kugel. Jetzt ist α göße als x, de Weg zu q also länge als de Weg zuück
Schnitttest mit eine Kugel 4 zum Schnittpunkt. α ist zu diesem Zeitpunkt auch positiv, es tifft also zu, dass α x. Nähet sich de Anfangspunkt p des Stahls imme weite de Kugel an, dann wid α imme kleine, bis es diekt an de Kugelobefläche genau so goß wie x ist: α x p q c Nachdem p das Kugelinnee beteten hat, ist α kleine als x gewoden. Addiet man beide, ist die Summe abe immenoch göße als Null das muss so sein, beide sind positiv. Es gilt nun, dass α + x > 0 ist. Ab jetzt wid also de echte Schnittpunkt ausgewählt: α x p q c Das ändet sich auch nicht, wenn α voübegehend negativ wid. Dann muss man est ein Stück zuück laufen, bis man q eeicht hat, um dann übe die Stecke x zum Schnittpunkt zu gelangen: α x q p c Est, wenn p die Kugel wiede velassen hat, ist α betagsmäßig goße als x und negativ. Daduch ist deen Summe nicht meh göße als Null, es gibt also keinen Schnittpunkt in positive Stahlichtung: x α q p c
Schnitttest mit eine Kugel 5 Das folgende Listing 1 ist ein leicht angepasste Auszug aus dem NetTace-Code und zeigt, wie de Schnitttest mit eine Kugel pogammatisch umgesetzt weden könnte. Listing 1: Eine Kugel testet sich auf Schnittpunkte mit einem Stahl. 1 public class Sphee3D 2 { 3 pivate Vec3 oigin ; 4 pivate double adius ; 5 6 public Vec3 intesectiontest ( Ray ) 7 { 8 // Wo ist de Punkt auf dem Stahl, de am nächsten an mi 9 // liegt? 10 double alpha = -. diection. dot (. oigin. minus ( this. oigin )); 11 Vec3 q =. evaluate ( alpha ); 12 13 // Abstand zum Kugelmittelpunkt? 14 q. subtact ( this. oigin ); 15 double disttocente2 = q. lengthsquaed (); 16 17 if ( disttocente2 > this. adius2 ) 18 etun null; 19 20 // Übe Pythagoas zu den beiden Schnittpunkten. 21 double x = Math. sqt ( this. adius2 - disttocente2 ); 22 23 // Welche von beiden liegt nähe am Ray - Uspung und in 24 // positive Stahlichtung? 25 double dist = 0.0; 26 if ( alpha >= x) 27 { 28 dist = alpha - x; 29 } 30 else if ( alpha + x > 0) 31 { 32 dist = alpha + x; 33 } 34 else 35 { 36 etun null; 37 } 38 39 // Das ist unse finale Schnittpunkt : 40 q =. evaluate ( dist ); 41 etun q; 42 } 43 }
Schnitttest mit eine Ebene 6 2 Schnitttest mit eine Ebene Eine Ebene sei gegeben als die Menge alle Punkte x, fü die gilt: ( x a) n = 0 Dabei ist a ein beliebige Punkt de Ebene, den man als Aufpunkt auffassen kann. n ist de Nomalenvekto de Ebene. Anschaulich kann man sich dieses Konstukt so vostellen: Man statet am Aufpunkt a. Wählt man nun einen beliebigen Punkt x in de Ebene, dann ist x a de Vebindungsvekto von a zu diesem Punkt. Diese Vebindungsvekto steht imme senkecht auf n, das Skalapodukt muss also 0 sein. Da n und a fü eine Ebene fest sind, lässt sich obige Gleichung noch veeinfachen: ( x a) n = 0 x n = d, dabei sei d = n a Man muss also nu das Skalapodukt eines möglichen Punktes de Ebene mit dem Nomalenvekto deselben betachten und kann alleine damit feststellen, ob de Punkt in de Ebene liegt. Nachdem man seine Ebene est einmal definiet hat, spielt de Aufpunkt a keine paktische Rolle meh, es eichen n und d, um die Ebene zu chaakteisieen. Stellt man nun x übe alle möglichen Punkte des vefolgten Stahls da, lässt sich wiede ein α als Stahlpaamete bestimmen, welches angibt, ob und wo de Stahl die Ebene schneidet: d = ( p + α u) n x α = d p n u n Offensichtlich muss fü einen gültigen Schnittpunkt in positive Stahlichtung α > 0 sein. Ist u n = 0, dann handelt es sich um einen de beiden Sondefälle Stahl liegt in de Ebene ode Stahl ist paallel zu Ebene. Beide weden in de Paxis als kein Schnitt gewetet Liegt de Stahl in de Ebene, gäbe es eigentlich unendlich viele Schnittpunkte. Es ist dennoch angebacht, dies als kein Schnitt zu weten: Damit ein Stahl in eine Ebene liegt, muss man diekt paallel zu Ebene blicken. Wüde man hie Schnittpunkte ausweten, sähe man die Ebene und sie bekäme eine Dicke. Ebenen sind abe unendlich dünn, also wäe dies keine Ebene meh sonden ein Quade. Dahe egibt es Sinn, die Ebene in diesem Sondefall zu ignoieen. De folgende Satz 3 fomalisiet die Schnittbedingung. Satz 3 (Bedingung fü Schnitt zwischen Stahl und Ebene) Ein Stahl q = p + α u schneidet eine Ebene, gegeben duch n und d, genau dann in positive Stahlichtung im Punkt q, wenn gilt: α = d p n u n > 0 fü u n 0 Auf ein Codebeispiel wid an diese Stelle vezichtet, da dieses Thema im nächsten Abschnitt noch einmal aufgegiffen wid. Dot gibt es dann ein explizites Beispiel.
Schnitttest mit einem Deieck 7 3 Schnitttest mit einem Deieck Ein Deieck wid gewöhnlich übe dei Punkte A, B und C beschieben. Diese Punkte spannen eine Ebene auf. Damit ein Stahl das Deieck schneiden kann, muss e auch zwangsläufig die Ebene schneiden, in welche das Deieck liegt. Um das heauszufinden, kann man die Ekenntnisse des Schnitttests mit eine Ebene nutzen, also Satz 3 von Seite 6. Dazu müssen natülich vohe die Ebenenpaamete bestimmt weden siehe hiefü Satz 4. Die Bezeichne, die dot eingefüht weden, weden auch im Folgenden benutzt. Satz 4 (Ebenenpaamete aus dei Punkten) Gegeben seien dei Punkte A, B und C. Emittle die Paamete de von diesen dei Punkten aufgespannten Ebene wie folgt: Wähle A als Aufpunkt de Ebene. Die beiden Kantenvektoen seien b = B A und c = C A. Übe deen Keuzpodukt ist de Nomalenvekto de Ebene bestimmt: n = b c, danach nomiee n auf die Länge 1. Folglich ist d = n A. Die Ebene ist also bekannt und daübe auch ein eventuelle Schnittpunkt. Wie schon ewähnt, gilt Satz 5: Satz 5 (Stahl muss Ebene eines Deiecks schneiden) Schneidet ein Stahl die Ebene, die von den dei Punkten eines Deiecks aufgespannt wid, nicht ode nicht in positive Stahlichtung, so schneidet e auch das Deieck nicht. Damit ist also eine este Abbuchbedingung fü den Schnitttest gegeben. Im Folgenden sei diese Bedingung efüllt und de Schnittpunkt q mit de Ebene gegeben. Es stellt sich nun die Fage, ob q innehalb des Deiecks liegt. Da Deiecke fü gewöhnlich textuiet dagestellt weden sollen und oft auch eine Nomale übe das Deieck hinweg intepoliet weden muss, bietet es sich an, den Punkt q in bayzentischen Koodinaten bezüglich des Deieckspunktes A anzugeben. Damit fällt ein spätees Textuieen leicht. Die bayzentischen Koodinaten gleichen in gewissem Sinne de Paametedastellung eine Ebene. Man statet am Punkt A und bewegt sich dann ein Stück in Richtung de Kante b, wie sie in Satz 4 eingefüht wude. Danach bewegt man sich ein Stück in Richtung de Kante c. Auf diese Weise kann man genau wie bei de Paametedastellung eine Ebene jeden Punkt des Deiecks eeichen. Fomal sieht das so aus: q = A + β ( B A) }{{ +γ ( C } A) }{{ } b c β und γ geben also an, wie weit man sich in Richtung de jeweiligen Kanten bewegt. Wählt man sie jedoch ungünstig, dann kann man das Deieck auch velassen. Ist eine de beiden Paamete Null, dann bewegt man sich nu entlang eine Kante des Deiecks. Man daf also schon einmal nicht in negative Richtung laufen, so wüde man das Deieck sofot velassen. Auch in positive Richtung daf man nicht zu weit gehen, denn nach eine vollen Kantenlänge hat man das Deieck auch wiede velassen. Bewegt man sich zusätzlich auch entlang de zweiten Kante, dann sieht man, dass β und γ zusammen eine weitee Bedingung stellen, denn ihe Summe daf nicht göße als Eins sein. Dies kann man leicht sehen, wenn man sich gedanklich
Schnitttest mit einem Deieck 8 in den Punkt A begibt und den Maximalfall β + γ = 1 annimmt. Dann lässt sich de Punkt q nämlich scheiben als: q = β b + γ c = β b + (1 β) c, da β + γ = 1 Dies ist also eine lineae Intepolation zwischen b und c, welche genau entlang de ditten Kante des Deiecks veläuft. Die dei ungültigen Fälle sind also: C C C γ β A γ γ A β A β B B B Fomal egeben sich an die beiden Paamete β und γ folgende Bedingungen: Satz 6 (Bedingung fü Punkt innehalb des Deiecks) Ein in bayzentischen Koodinaten dagestellte Punkt q = A + β ( B A) + γ ( C A) liegt genau dann im Deieck de Punkte A, B und C, wenn gilt: β 0 γ 0 α = 1 β γ 0 Wenn man die bayzentischen Koodinaten eines Punktes bezüglich eines Deieckspunktes kennt, kann man die Fage nach einem Schnitt mit dem Stahl also beantwoten: Suche einen Schnittpunkt mit de Ebene des Deiecks und stelle diesen Schnittpunkt in bayzentischen Koodinaten da. Genügen diese Satz 6, dann schneidet de Stahl das Deieck. Bleibt die Fage zu beantwoten, wie man die bayzentischen Koodinaten findet. Da Raytacing ein Thema ist, übe das sich schon viele Menschen intensiv Gedanken gemacht haben, gibt es hiefü die veschiedensten Methoden. Im Folgenden soll eine davon vogestellt weden, die einfach zu vestehen ist, ohne Betachtung von Sondefällen auskommt und sich dennoch gut optimieen lässt. Betachte die Ausgangsgleichung: q = A + β ( B A) }{{ +γ ( C } A) }{{ } b c Duch die Vektoen handelt es sich hie eigentlich um dei Gleichungen und die zwei Unbekannten β und γ. Nimmt man folgende Umfomung vo, indem man A von beiden Seiten subtahiet, dann bescheiben
Schnitttest mit einem Deieck 9 beide Seiten de Gleichung einen Vekto vom Punkt A zum Punkt q diese wid zu Veeinfachung a genannt: q A }{{ = β b + γ c } a Dieses a pojiziet man nun duch Bilden des Skalapoduktes einmal auf die Kante b und einmal auf die Kante c, woduch nu noch zwei Gleichungen und zwei Unbekannte übig bleiben: a b = β b b + γ c b a c = β b c + γ c c (I) (II) Löse (I) nach β auf: β = a b γ c b b b (III) Da keine degeneieten Deiecke geendet weden, ist imme b 0. Setze nun (III) in (II) ein, dann egibt sich nach Veeinfachung: γ = a c b b a b b c c c b b c b b c (IV) Und damit nach Einsetzen von (IV) in (III) und dessen Veeinfachung: β = a b c c a c c b c c b b c b b c (V) Angemekt sei, dass auch diese Nenne nicht Null weden können: c und b haben beide eine Länge ungleich Null, außedem sind sie nicht identisch. Mit den Gleichungen (IV) und (V) sind also die bayzentischen Koodinaten bekannt und Satz 6 auf Seite 8 kann fü den Schnitttest angewandt weden. Satz 7 (Beechnung de bayzentischen Koodinaten) Gegeben ein Deieck mit den Punkten A, B und C und Kantenvektoen b und c bezüglich des Punktes A. Fü einen Punkt q in de Ebene des Deiecks beechnen sich die bayzentischen Koodinaten bezüglich A wie folgt: Wobei wie gehabt a = q A. β = a b c c a c c b c c b b c b b c γ = a c b b a b b c c c b b c b b c
Schnitttest mit einem Deieck 10 3.1 Optimieung duch Vobeechnung Es fällt zunächst einmal auf, dass die Nenne von (IV) und (V) identisch sind. Außedem sind b und c alleine vom Deieck abhängig und nicht vom zu testenden Punkt. In a vebigt sich hingegen noch q. Wi ückstubstituieen an diese Stelle abe nicht, sonden betachten noch einmal Gleichung (V), fühen den Bezeichne D als Veküzung fü den Nenne ein und fomen etwas um: β = a b c c a c c b c c b b c b b c D = ( ) a b c c a c c b 1 D ( = a b c c D = a c c b D R ) ( a c c b c D R ) c b D } {{ } u β R 3 c c ist ein Skala, ebenso D. Das heißt, b wid zuest skaliet, bevo das Skalapodukt mit a gebildet wid. Analog wid c skaliet. Im letzten Schitt wid a ausgeklammet. Die gesamte Klamme namens u β kann nun einmalig vobeechnet weden. Fü statische Deiecke muss dies nu einmal zu Beginn des Rendevogangs geschehen, bei Animationen kann diese Vogang an den Anfang eines jeden Einzelbildes velaget weden. Auf die gleiche Weise lässt sich γ veeinfachen, sodass sich egibt: γ = a c b b D R b b c D R } {{ } u γ R 3 Im Moment sind also fü die Beechnung von β und γ folgende Schitte nötig: Beechnen von a = q A, das sind dei elementae Subtaktionen. Beechnen von β = a u β, also ein Skalapodukt. Beechnen von γ = a u γ, ein weitees Skalapodukt. Insgesamt lässt sich noch eine elementae Opeation einspaen, indem man betachtet: ( β = a u β = q A ) u β = q u β + ( A u β ) k β
Schnitttest mit einem Deieck 11 k β ist wiede nu von den Paameten des Deiecks abhängig, nicht vom potentiellen Schnittpunkt. Analoges gilt fü γ: ( γ = a u γ = q A ) u γ = q u γ + ( A u γ ) k γ Man kann also auch k β und k γ im Voaus beechnen und speichen. Dann sind po Schnitttest nu noch folgende Opeationen notwendig: Beechnen von β = q u β + k β, also ein Skalapodukt und eine Addition. Beechnen von γ = q u γ + k γ, noch ein Skalapodukt und eine Addition. Detailliet zu sehen ist dies in Listing 2, das wiede einen geküzten Auszug aus dem NetTace-Code zeigt. Auspogammiet ist dot die Vobeechnung und de Test Stahl vs. Deieck, de bekanntlich auch den Test Stahl vs. Ebene enthält.
Schnitttest mit einem Deieck 12 Listing 2: Ein Deieck testet sich auf Schnittpunkte mit einem Stahl. 37 public class Tiangle3D 38 { 39 pivate Vec3 n, ubeta, ugamma ; 40 pivate double d, kbeta, kgamma ; 41 42 /* * Vobeechnen statische Wete. */ 43 public Tiangle3D ( Vec3 [] vetices ) 44 { 45 // Kantenvektoen. 46 Vec3 b = vetices [1]. minus ( vetices [0]) ; 47 Vec3 c = vetices [2]. minus ( vetices [0]) ; 48 49 // Ebenenpaamete. 50 n = b. coss (c); 51 n. nomalize (); 52 d = n. dot ( vetices [0]) ; 53 54 // Beechne die goßen Klammen, sodass beim Schnitttest wenige 55 // Abeit getan weden muss. 56 double bb = b. dot (b); 57 double bc = b. dot (c); 58 double cc = c. dot (c); 59 60 double D = 1.0 / ( cc * bb - bc * bc); 61 double bbd = bb * D; 62 double bcd = bc * D; 63 double ccd = cc * D; 64 65 ubeta = b. times ( ccd ). minus (c. times ( bcd )); 66 ugamma = c. times ( bbd ). minus (b. times ( bcd )); 67 68 kbeta = - vetices [0]. dot ( ubeta ); 69 kgamma = - vetices [0]. dot ( ugamma ); 70 } 71 72 /* * Füht einen Schnitttest mit einem Stahl duch. */ 73 public Vec3 intesectiontest ( Ray ) 74 { 75 // Schnitttest Ray -> Ebene 76 double n =. diection. dot (n); 77 if ( Math. abs (n) < 1e -15) 78 etun null; 79 80 // Wie weit hat es de Ray von seinem Uspung zum Schnittpunkt? 81 double alpha1 = ( d -. oigin. dot ( n)) / n; 82 if ( alpha1 <= 0.0) 83 etun null; 84 85 // Schnittpunkt q mit Ebene gefunden, liegt e im Deieck? 86 Vec3 q =. evaluate ( alpha1 ); 87 double beta = ubeta. dot ( q) + kbeta ; 88 if ( beta < 0.0) 89 etun null; 90 91 double gamma = ugamma. dot ( q) + kgamma ; 92 if ( gamma < 0.0) 93 etun null; 94 95 double alpha = 1 - beta - gamma ; 96 if ( alpha < 0.0) 97 etun null; 98 99 // Es gibt also einen Schnittpunkt und diese ist q. alpha, beta 100 // und gamma könnten fü Textuieung ode ähnliches weite - 101 // vewendet weden. 102 etun q; 103 } 104 }