Übersicht

Einspinnen eines Objekts

Demodatei: Demo3.pov

Die folgende Serie von Abbildungen demonstriert, wie man ein gegebenes Objekt mit Sphere_Sweeps einspinnen kann. Zunächst erzeugen wir, ausgehend von zufällig verteilten Positionen (Abbildung 1) einen zufälligen Blob (Abbildung 2). Dieser Blob wird von zufällig auf einer Kugelhülle verteilten Punkten umgeben (Abbildung 3). Diese Punkte werden solange auf den Blob zubewegt, bis sie ihn erreichen. (Abbildung 4). Die Folge sind zufällig verteilte Positionen auf der Oberfläche des Blobs. Diese Positionen können nun zum Aufbau von Sphere_Sweeps verwendet werden, ausgehend von der grün gekennzeichneten Position. Es gibt natürlich mehrere Möglichkeiten beim Aufbau dieser Sphere_Sweeps vorzugehen. Hier zeigen wir ein Beispiel für verzweigte und ein Beispiel für unverzweigte Sphere_Sweeps.

random position for defining the blob a random blob object surrounded by random positions random positions on the object sphere_sweep covering the object sphere_sweep covering the object sphere_sweep covering the object sphere_sweep covering the object sphere_sweep covering the object

Zunächst benötigen wir eine Reihe zufälliger Positionen, um einen zufälligen Körper aufzubauen. Der folgende Makro für diese Aufgabe ähnelt dem Makro für den Aufbau des variablen xyz-Gitters. Dieses Mal verwenden wir allerdings polare anstelle der kartesischen Koordinaten.

#macro SphereDistributionArray (Radius, Sum)
//Dieser Makro verteilt Positionen zufällig in einem polaren Koordinatensystem.
//Die Positionen werden im Array "Positions" gespeichert.
//Die Größe dieses Arrays wird in der Variablen "Number" gespeichert.


#declare Positions = array [Sum];
#declare Number = Sum;

#local ticker = 0;
#while (ticker < Sum)
#local var1 = rand(chance1);
#local var2 = rand(chance2);
#local var3 = rand(chance3);
#local P1 = <Radius* var1, 0, 0>;
#local P1 = vrotate (P1, <0, 360 * var2, 0>);
#local P1 = vrotate (P1, <0, 0, 360 * var3>);
#declare Positions[ticker] = P1;
#local ticker = ticker + 1;
#end
#end

Die Positionen, die durch den Makro definiert wurden, werden nun zum Aufbau des Blobs verwendet.

SphereDistributionArray (1.3, 100)
//Makro zur Erzeugung zufällig verteilter Positionen.
//Die Positionen des obigen Makros (gespeichert im Array "Positions") werden verwendet um einen Blob aufzubauen.


#declare Body = blob {
threshold 0.2
#declare ticker = 0;
#while (ticker < Number)
#declare P1 = Positions[ticker];
sphere { <0, 0, 0>, 1, 1
translate P1
}
#declare ticker = ticker + 1;
#end
pigment {
color rgb <1,0,0>
}
}

object {Body}

Im nächsten Schritt suchen wir nach zufällig verteilten Positionen auf der Oberfläche des soeben definierten Körpers. Um diese Positionen zu finden, erzeugen wir Positionen, die zufällig auf einer Kugel um den Körper herum verteilt sind. Diese Positionen lassen wir dann solange auf den Körper zuwandern, bis sie ihn erreichen.

#macro SurfaceDistributionArray (Object, Radius, Number)
//Dieser Makro erzeugt Zufallspositionen, die ein Objekt in Form einer Kugelhülle umgeben
//und lässt sie solange auf das Objekt zuwandern, bis sie es erreichen.


#declare Positions = array [Number];
#local ticker = 0;
#while (ticker < Number)
#local var1 = rand(chance1);
#local var2 = rand(chance2);
#local P1 = <Radius, 0, 0>;
#local P1 = vrotate (P1, <0, 360 * var1, 360 * var2>);

//Hier lassen wir die Positionen solange auf den Mittelpunkt der Kugel zuwandern, bis sie das Objekt erreichen.
#while (inside (Object, P1) = 0)
#local P1 = P1 - (1/100 * (P1 - <0, 0, 0>));
#end

#declare Positions[ticker] = P1;
#local ticker = ticker + 1;
#end
#end

Der nächste Makro sucht schließlich nach einem Weg durch die soeben definierten Punktwolken. In unserem Beispiel ist dieser Weg stets von negativen nach positiven z-Werten gerichtet.

//Dieser Makro sucht nach einem Weg durch die Wolke, die im Array Positions definiert ist.
//Der Weg wird von negativen zu positiven z-Werten gesucht.
//Deswegen sollte der Start auf der negativen z-Seite des Objekts definiert werden.
//Der Makro wird stets die Position mit dem geringsten Abstand auswählen, solange der Abstand einen unteren Schwellenwert nicht unterschreitet.
//Die Positionen für den Weg werden im Unterarray Positions2 gespeichert und werden aus dem Array Positions gelöscht.
//Die Größe dieses Unterarrays wird in der Variablen Sum2 gespeichert.


#macro SubArray (ArrayName, Start, SubArraySize)
//Der Outputarray wird initialisiert.
#declare Positions2 = array[SubArraySize];
#declare Sum2 = SubArraySize;

//Positions2 erhält sein erstes Element.
#local P0 = Start;
#declare Positions2[0] = P0 + <0, 0, P0.z/10>;
#declare Positions2[1] = P0;

//Im Verlauf dieser Schleife werden die Elemente des Inputarrays durchsucht.
#local ticker1 = 1;
#while (ticker1< SubArraySize-1)

//Ein erstes Element des Inputarrays (Positions) wird definiert.
#local P1a = ArrayName[0];
#local Distancea = vlength (P1a-P0);

//Für den Fall, dass die Elemente des Input- und Outputarrays identisch sind, wird ein anderes Element des Inputarrays gewählt.
#if (Distancea = 0)
#local P1a = ArrayName[1];
#local ticker = 2;
#else
#local ticker = 1;
#end

//Jetzt wird der Inputarray nach einem Element durchsucht, das einen positiveren z-Wert hat als das Element des Outputarrays
//und das so nah wie möglich bei diesem Element liegt, soweit es einen bestimmten Mindestabstand nicht unterschreitet.

#while (ticker < Sum)
#local P1 = ArrayName[ticker];
#local Distance = vlength (P1-P0);
#if (Distance = Distancea)
#else
#if (Distance<Distancea & P1.z>P0.z & Distance > 0.1)
#local Distancea = Distance;
#local P1a = P1;
#else
#end
#end
#local ticker = ticker + 1;
#end
#local ticker1 = ticker1 + 1;

//Das gefundene Element wird in den Outputarray übertragen.
#declare Positions2[ticker1] = P1a;
#local P0 = P1a;

//In allen Fällen, mit Ausnahme des allerersten Elements, werden die gefundenen Positionen aus dem Inputarray gelöscht.
#if (ticker1>2)
DeleteElement (Positions, Sum, P1a) //Dieser Makro löscht P1a aus dem Inputarray (Positions) und verändert die Größe dieses Arrays (Sum) entsprechend.
#else
#end
#end
#end

Die Art, wie die für den jeweiligen Weg ausgewählten Positionen aus dem Inputarray gelöscht werden, entscheidet über das Verzweigungsmuster der Sphere_Sweeps. Das Löschen aller Punkt (siehe oben) führt zu komplett unverzweigten Sphere_Sweeps (Jeder Sphere_Sweep durchläuft andere Punkte). Im Folgenden demonstrieren wir eine Löschmethode, mit der wir eine graduelle Verzweigung erreichen: Die Punkte werden erst nach einer bestimmten Länge der Sphere_Sweeps aus dem Inputarray gelöscht. Wie ich Ihnen in späteren Kapiteln zeigen werde, existieren aber noch wesentlich bessere Methoden, um realistische Verzweigungsmuster zu erzeugen.

//Die folgenden Bedingungen verursachen ein Löschen der ausgewählten Punkte ab verschiedenen Stufen.
//Dies führt zu einer zunehmenden Verzweigung der Sphere_Sweeps.
//Zunächst wird die Verzweigungsvariable mehr oder weniger zufällig definiert.


#if (rand(chance1) <0.2)
#local branching = 5;
#else
#if (rand(chance1) <0.35)
#local branching = 8;
#else
#if (rand(chance1) <0.5)
#local branching = 9;
#else
#if (rand(chance1) <0.65)
#local branching = 10;
#else
#local branching = 11;
#end
#end
#end
#end

//Die Verzweigungsvariable markiert den Punkt des Sphere_Sweeps, ab dem die Positionen aus dem Inputarray gelöscht werden. Diese Stelle entspricht der Position, ab der ein neuer Sphere_Sweep einen neuen Weg finden muss, wo sich die entsprechenden Sphere_Sweeps also verzweigen.
#if (ticker1<branching)
#else
DeleteElement (Positions, Sum, P1a) //Dieser Makro löscht P1a aus dem Inputarray (Positions) und verändert die Größe dieses Arrays (Sum) entsprechend.
#end

Nachdem wir nun all diese Makros definiert haben, kommen hier die Zeilen, mit denen sie aufgerufen werden.

//Definition von 4 pseudo-random streams.
#declare chance1 = seed (8);
#declare chance2 = seed (7);
#declare chance3 = seed (17);
#declare chance4 = seed (5);

//Makro für die Erzeugung zufällig verteilter Positionen.
SphereDistributionArray (1.3, 100)

//Die Positionen von obigem Makro (gespeichert im Array "Positions") werden verwendet, um einen Blob aufzubauen.
#declare Body = blob {
threshold 0.2
#declare ticker = 0;
#while (ticker < Number)
#declare P1 = Positions[ticker];
sphere { <0, 0, 0>, 1, 1
translate P1
}
#declare ticker = ticker + 1;
#end
pigment {
color rgb <1,0,0>
}
}

//Die im folgenden definierten Positionen werden exakt auf der Oberfläche des Blobs liegen.
//Um sie ein wenig darüber liegen zu lassen,
//wird die Größe des Blobs ein wenig reduziert, bevor er dargestellt wird.

object {Body
scale <0.97, 0.97, 0.97>}

//Makro für die Positionen auf der Oberfläche des Blobs.
SurfaceDistributionArray (Body, 2.4, 910)

//Die folgende Schleife markiert alle oben definierten Positionen durch eine kleine gelbe Kugel.
#declare ticker = 0;
#while (ticker < 910)
#declare P1 = Positions[ticker];
sphere { <0, 0, 0>, 0.025
translate P1
pigment {
color rgb <1,1,0>
}
}
#declare ticker = ticker + 1;
#end

//Die folgende Schleife definiert 20 Sphere_Sweeps, die sich durch die oben definierte Punktwolke bewegen.
#declare ticker = 0;
#while (ticker <20)
SubArray (Positions, <0, 0, -2.2>, 30)//Dieser Makro berechnet den Weg durch die Punktwolke.
DrawSphereSweep (Positions2, 0.007, Sum2) //Dieser Makro zeichnet den Sphere_Sweep.
#declare ticker = ticker + 1;
#end

//Diese letzte Kugel wird dargestellt, um den Ausgangspunkt der Sphere_Sweeps zu markieren.
sphere { <0, 0, 0>, 0.05
translate <0, 0, -2.2>
pigment {
color rgb <0,1,0>
}}

Übersicht