Übersicht

Zufällige Knäuel

Demodatei: Demo2.pov

Zunächst eine kurze Bemerkung zu den Positionen, mit deren Hilfe die Knäuel erzeugt werden. Diese Positionen werden über einen Makro erzeugt, der ein regelmäßiges x,y,z-Gitter generiert und die Punkte dieses Gitters in einem gewissen (frei zu wählenden) Bereich zufällig variieren lässt (rote Kugeln, Abbildung unten links). Weil das Knäuel auf einen bestimmten Bereich beschränkt sein soll, werden nur Positionen übernommen (Abbildung unten rechts), die sich innerhalb eines definierten Körpers befinden (hier innerhalb einer gelben Kugel, Abbildung unten, Mitte). Diese Positionen werden in Form eines Arrays gespeichert (der in diesem Fall "Positions" genannt wurde).

random positions random positions and sphere random positions within a sphere

Die Form des Knäuels, der aus diesen Positionen aufgebaut wird, hängt von der Reihenfolge ab, in der die Positionen aus dem Array abgerufen werden. Werden die Positionen in derselben Reihenfolge abgerufen, wie sie im Array gespeichert wurden, wird ein sehr geordneter Knäuel gebildet (Abbildung unten links). Beim zufälligen Abrufen der Positionen aus dem Array gibt es die Möglichkeit, die abgerufenen Positionen aus dem Array zu löschen (Abbildung unten Mitte), oder sie im Array zu belassen (Abbildung unten rechts). Werden die Punkte nach dem Abrufen im Array belassen, ergibt sich die Möglichkeit, dass einzelne Positionen mehrmals vom Sphere_Sweep durchlaufen werden, während andere Positionen nicht verwendet werden.

ordered coil random coil1 random coil2

Zunächst werde ich auf den Makro eingehen, mit dessen Hilfe die Ausgangspositionen erzeugt werden.

#macro xyzDistributionInsideArray (Object, Start, Amountx, Amounty, Amountz, Distancex, Distancey, Distancez, Variance)
//Dieser Makro erzeugt Positionen einer gegebenen Varianz in einem xyz-Gitter innerhalb eines bestimmten Objekts
//und speichert die Koordinaten der Positionen im Array "Positions".
//Der Makro hat die folgenden Parameter: Das Objekt, innerhalb dessen sich die Positionen befinden, den Startpunkt des Gitters,
//die Anzahl der Positionen und ihren Abstand für die verschiedenen Koordinaten sowie die Varianz.
//Bei der Auswahl der einzelnen Parameter sollte darauf geachtet werden, dass sich Objekt und Gitter optimal überlappen.


#declare Positions = array [Amountx * Amounty * Amountz];//Der Array wird initialisiert.
#declare Sum = 0;//Diese Variable speichert die Größe des Arrays.
#local xKoord = Start.x; //Die Variablen, die die x-, y-, und z-Koordinaten speichern, werden auf die Startposition gesetzt.
#local yKoord = Start.y;
#local zKoord = Start.z;

//Drei ineinander verschränkte Schleifen erzeugen das xyz-Gitter.

#local ticker3 = 0;
#while (ticker3 < Amountx)
#local xKoord = xKoord + Distancex;
#local yKoord = Start.y;
#local ticker2 = 0;
#while (ticker2 < Amounty)
#local yKoord = yKoord + Distancey;
#local zKoord = Start.z;
#local ticker = 0;
#while (ticker < Amountz)
#local zKoord = zKoord + Distancez;

//Zufallszahlen werden generiert ausgehen von "pseudo-random streams", die vor dem Aufruf des Makros definiert werden müssen.

#local var1 = rand(chance1);
#local var2 = rand(chance2);
#local var3 = rand(chance3);

//Hier werden die verschiedenen Positionen definiert...

#local P1 = <xKoord + Variance * (var1 - 0.5), yKoord + Variance * (var2 - 0.5), zKoord + Variance * (var3 - 0.5)>;
#if (inside (Object, P1) = 1)

//...und im Array gespeichert, wenn sie sich innerhalb des Objekts befinden.

#declare Positions[Sum] = P1;
#declare Sum = Sum + 1;
#else
#end

//Ende der Schleifen und des Makros.

#local ticker = ticker + 1;
#end
#local ticker2 = ticker2 + 1;
#end
#local ticker3 = ticker3 + 1;
#end
#end

Bevor der Makro aufgerufen wird, müssen die "pseudo-random streams" und das Objekt definiert werden.

#declare chance1 = seed (13);
#declare chance2 = seed (15);
#declare chance3 = seed (18);


#declare Container = sphere { <0, 0, 0>, 3 };

xyzDistributionInsideArray (Container, <-3, -3, -3>, 10, 10, 10, 1, 1, 1, 0.6)

In diesem Beispiel werden die Positionen innerhalb des Objekts "Container" definiert. Sie haben einen durchschnittlichen Abstand von 1 voneinander; die Variabilität beträgt 0.6.

Im Prinzip kann man den Makro aus dem vorangegangenem Kapitel benutzen, um die Positionen aus dem soeben erzeugten Array "Positions" abzurufen.

DrawSphereSweep (Positions, 0.2, Sum)

Bei Verwendung dieses Makros werden die Positionen allerdings in genau der gleichen Reihenfolge abgerufen, wie sie im Makro abgespeichert wurden. Beim Verbinden der Positionen in dieser Reihenfolge ergibt sich ein sehr ordentliches Knäuel (siehe Abbildung oben links).

Wenn wir die Zeile

#declare P1 = Positions[ticker];

dieses Makros mit der folgenden Zeile austauschen,

#declare P1 = Positions[floor(rand(chance1)*0.9999999*Sum)];

werden die Positionen in scheinbar zufälliger Reihenfolge aus dem Array abgerufen; es ergibt sich ein schönes, zufälliges Knäuel. (Diese Lösung wurde aus "arrays.inc" übernommen.) Bei dieser einfachen Lösung werden allerdings die abgerufenen Positionen nicht aus dem Array eliminiert. Deswegen kann dieselbe Position mehrere Male abgerufen werden, während andere Positionen unter Umständen überhaupt nicht abgerufen werden.
Der folgende Makro behebt dieses Problem, indem er die abgerufenen Positionen automatisch aus dem Array eliminiert. Dies geschieht, indem bei jeder Auswahl ein neuer Array definiert wird, mit einem Element weniger als im Ausgangsarray, und indem dann alle Elemente, mit Ausnahme des abgerufenen Elements, in diesen neuen Array übertragen werden.

#macro RandomArrayElement (ArrayName, ArraySize)
//Dieser Makro wählt ein zufälliges Element aus einem Array,
//speichert dieses Element als P1 und löscht es aus dem Array.
//Da der Array bei dieser Operation verändert wird, sollte man ihn unter Umständen gesondert speichern.
//Der Parameter ArraySize entspricht der Anzahl der Elemente des Arrays.
//Diese Größe wird vom Makro in der Form der Variblen "Size" ausgegeben.
//Wenn der Makro innerhalb einer Schleife arbeitet, sollte die Variable Size dem Array als Parameter ArraySize übergeben werden.
//Der Makro kann nur Arrays mit mehr als einem Element verarbeiten (Vorsicht beim Arbeiten innerhalb von Schleifen).


#local ArrayPosition = floor(rand(chance1)*0.9999999*(ArraySize));
#declare P1 = ArrayName[ArrayPosition]; //Ein Element des Arrays wird zufällig ausgewählt.
#local PositionsNew = array[ArraySize-1];//Der neue Array ist ein Element kürzer als der alte.
//Weil ein Array nicht die Größe 0 annehmen darf, kann diese Operation nur für Arrays größer als 1 durchgeführt werden.


//Die folgende Schleife überträgt alle Elemente (mit Ausnahme des ausgewählten) aus dem alten in den neuen Array.

#local ticker2 = 0;
#local ticker3 = 0;
#while (ticker2 < ArraySize)
#if (ticker2 = ArrayPosition)
#local ticker3 = ticker3 -1;
#else
#local P2 = ArrayName[ticker2];
#local PositionsNew [ticker3] = P2;
#end
#local ticker2 = ticker2 + 1;
#local ticker3 = ticker3 + 1;
#end

//Ende der Schleife. Der Inputarray des Makros wird jetzt durch den soeben erzeugten Array ersetzt.

#declare ArrayName = PositionsNew;
#declare Size = dimension_size(PositionsNew,1);
#end

Die Schleife, die den entsprechenden Sphere_Sweep aufbaut, hat die folgende Form:

#declare chance1 = seed(2);

//Weil der ursprüngliche Array während der Operation verändert wird,
//sollte der ursprüngliche Array gesondert gespeichert werden.


#declare Size = Sum;
#declare PositionsWork = Positions;

//Hier wird der Sphere_Sweep intialisiert.

sphere_sweep {
cubic_spline
Sum-1, // bei Sum würde ein Array der Größe 0 entstehen.

//Die Schleife, um die Positionen aus dem Array abzurufen.

#declare ticker = 0;
#while (ticker < Sum-1)
RandomArrayElement (PositionsWork, Size)
P1, 0.1
#declare ticker = ticker + 1;
#end

//Ende des Sphere_Sweeps

pigment {
color rgb <0, 0, 1>

}
}

Übersicht