Anzeige
Tutorialbeschreibung

C.O.F.F.E.E. - Einstieg Teil 3

C.O.F.F.E.E. - Einstieg Teil 3

Dies ist der dritte Teil der kleinen Tutorial-Reihe zu der programminternen Scriptsprache C.O.F.F.E.E. von Cinema 4D (Maxon).


Hallo und willkommen zum dritten Tutorial hier auf PSD-Tutorials.de.

In diesem Teil geht es um:

-Wie versprochen: Matrizen und Vektoren
-Kreisbeschreibung mitsinundcos
-C.O.F.F.E.E. in und um Xpresso
-C.O.F.F.E.E.-Anwendungsbeispiel (...)

Fange wir erst einmal an. Erstellt eine neue Szene und fügt ein Null-Objekt ein:

Bilder


Gebt diesem Null-Objekt noch einen C.O.F.F.E.E.-Tag:

Bilder


Prompt erscheint auch schon der Expressions-Editor mit den Parametern „doc“ und „op“.

Bevor wir uns an Vektoren und Matrizen (= Mehrzahl von Matrix) wagen, sollte man auch wissen, was diese eigentlich sind, dazu füge ich hier ein „Zitat“ von Maxon ein ;) :

"Together these four vectors can be used to represent the coordinate system for a C4D object. A coordinate system consists of three axes, one for each coordinate (X, Y and Z). The system also has a base position, from which the three axes originate. This base position is stored in v0, and the three axis vectors are stored in v1, v2 and v3 respectively:

Vector Contains
v0 position
v1 X-axis
v2 Y-axis
v3 Z-axis"

Das heißt im Großen und Ganzen, dass die Positionen (als Vektoren) in dieser „Mg()“ gespeichert sind und mit
V0 ausgegeben werden können. Die jeweiligen Ausrichtungen (der Achsen XYZ) jeweils mit V1, V2 und V3.

V0 = Position von XYZ (als Vector)
V1 = Achsausrichtung X
V2 = Achsausrichtung Y
V3 = Achsausrichtung Z


Wer mehr darüber erfahren möchte, sollte bei wikipedia.org nach „Vektor“ in der Mathematik suchen ;)

Nun zum Script:

Erstellen wir doch einfach mal einen eigenen Vektor + Koordinaten und speichern diese zur späteren Verwendung; schreibt in den Expressions-Editor:

main ( doc, op)
{
var lmat = new(Matrix); // new kann für mehrere "Objekte" verwendet werden; new(Randon) oder new(BaseContainer) (Script)
var vektor = vector(0,0,0); // Erstellt Vektor mit 0,0,0
}
// Achtung: deutsch / englisch beachten (Vektor / Vector)


Wie gehabt wird jede Zeile mit ";" beendet!

Somit haben wir eine neue Matrix erstellt und einen Vektor.
Den Vektor könnten / sollten wir nun in die Matrix „eintragen“ (übergeben klingt so abwertend..)

Wie oben beschrieben, können wir mit V0 die Position (als Vektor) auslesen, die Umkehr von „Get“ ist logischerweise „Set“, also „setten“ wir den Vektor zur Matrix:


main ( doc, op)
{
var lmat = new(Matrix)
var vektor = vector(0,0,0);

lmat->SetV0( vektor );

}

Somit wurde der von uns erstellte Vektor in die neue Matrix geschrieben. Ändert mal die Vektor-Daten in z.B. (10, 100, 2) um.

Nun soll mat natürlich noch auf das Objekt angewendet werden, mit SetMg();
(Setze Matrix Global)


main ( doc, op) 
{ 
var lmat = new(Matrix); 
var vektor = vector(0,0,0); 
mat->SetV0( vektor ); 
op->SetMg( lmat ); 
}

Um die Position des Null-Objektes besser verfolgen zu können, könnt ihr noch dessen Darstellung ändern; hier auf dem Screenshot noch der komplette Code:

Bilder


Um das Ganze noch etwas abzurunden, erstellen wir noch Benutzerdaten, um die Y-Position zu verändert; löscht dazu im Vektor die Y-Positionsangabe (Mitte)!
Um an Benutzerdaten heranzukommen, benutzt man den Befehl „ #ID_USERDATA:“ Gefolgt von der Stelle (1,2,3... usw.), in der sich die Daten befinden (erster Datensatz = 1, usw.).

Schreibt also:


main ( doc, op) 
{ 
var mat = new(Matrix); 
var vektor = vector( 0 , #ID_USERDATA:1 , 0 ) ; 
lmat->SetV0( vektor ); 
op->SetMg( mat );
}

Natürlich können viele Objekte Benutzerdaten besitzen, also müssen wir noch dazu schreiben, von welchem Objekt diese gelesen werden sollen; richtig! Vomop:

op#ID_USERDATA:1


Der Datensatz muss FLOAT sein (=Gleitkommazahl) mit der EinheitREAL (also eine „wirkliche“ Gleitkommazahl ;) )

Bilder


Erstellt die besagten Benutzerdaten! Der Max-/ Min-Wert kann natürlich frei gewählt werden. Wenn ihr den Float-Wert anschließend verändert, ändert sich auch die Y-Position des Objekts. Somit könnt ihr fast alle C.O.F.F.E.E.-Daten per Benutzerdaten steuern!

Hier nochmal der gesamte Code:


main(doc,op) 
{ 
var lmat = new(Matrix); 
var vektor = vector(0,op#ID_USERDATA:1,0); // Werte durch ein Komma trennen  
lmat->SetV0( vektor ); // Setze V0 (Vektor) in die Matrix (new)  
op->SetMg(lmat); // Schreibe Matrix (lmat) in op (Null Objekt) 
}

----------------------

Nun zum Kreis:

Ich hab' mich bei meinen Anfängen von C.O.F.F.E.E. immer gefragt:
Es muss doch irgendwie möglich sein, einen Kreis zu beschreiben, ohne ein weiteres Null-Objekt
zu erstellen und dieses alsNull-Positionzu benutzen.



Bis ich dann feststellen musste, dass ich mich damit in den Mathematikunterricht der Schule zurückgeworfen habe 0.o .

Wer erinnert sich noch an Sinus, Cosinus und Tangens...?
Egal, fangen wir an :)

Um nicht eine neue Szene zu starten, löscht einfach das Script im Expressions-Editor.

Was wir benötigen:
–speed ( die Geschwindigkeit, in der rotiert werden soll)
–distance (sozusagen der Radius; hierfür können wir den FLOAT-Wert benutzen!)
–frame (die aktuelle Zeit (das aktuelle Bild(Frame))

Speichern wir diese einfach mal in einer Variableab :)
Schreibt dazu:


var frame = doc ->GetTime()->GetFrame(doc->GetFps());
var speed = 25; // Kann variiert angegeben werden
var distance = op#ID_USERDATA:1; // Vorher erstellte Benutzerdaten

Erklärung: frame
Wir müssen GetTime mit GetFrame verknüpfen und aus dem Dokument noch die FPS auslesen (GetFps), um mit den Einzelbildern arbeiten zu können! Das wird intern berechnet und in frame gespeichert (Zeit * Fps = Frame (d.h. Bei 90-Frames und 30-Fps wäre das Video 3 Sekunden lang)!

Weiter zum Objekt:

Um auf die Objekt-Position zugreifen zu können, benutzen wir ->GetMg()
GetMg =GetMatrix-Global(Mg, geht auch für Lokal ->GetMl (L))

Lesen wir also die Matrix aus:


var pos = op ->GetMg();

Allerdings können wir so nicht damit rechnen (wird alsObjektgespeichert). Wir wollen aus der Mg die v0 (=Positionen!)
Also:


var pos = op ->GetMg()->GetV0();

Somit wird in pos die Position gespeichert (als Vektor, siehe oben) und wir können damit rechnen ;)

Nun zu Sinus

Bilder


# Quelle: Wikipedia.org -> http://upload.wikimedia.org/wikipedia/commons/e/e3/Einheitskreis_Ani.gif
#Quelle: Wikipedia.org SIN-> http://de.wikipedia.org/wiki/Sinus

Für die X-Position des Objektes reicht es, wenn man einfach .X ( punkt X) hinter die Variable schreibt (wenn dort die Informationen gespeichert sind ;) )


pos.x = sin ( speed * frame ) * distance ;

Wenn ihr eure Benutzerdaten (den FLOAT-Wert) auf 100 stellt, das Script kompilieren lasst und die Animation startet, wird eine wunderhübsche Sinus-Kurve auf derX-Positiongeneriert und dasNull-Objekt wird auf und ab "hüpfen"; die Höhe ist von dem eingestellten Wert abhängig ;) .

Wer mehr über Sin/Cos und Tan erfahren möchte, der schaut unter Wikipedia.org nach (Link: siehe oben!)!

Das Ganze mitcosnoch für die Y-Achse:


pos.y = cos ( speed * frame ) * distance ;

Jetzt sollte man natürlich noch die berechneten Daten an die Position des Objekteszurückgeben!


op -> SetPosition(pos);

Wenn ihr die var speed auch mit Benutzerdaten steuern wollt, müsst ihr als ID den Wert 2 angeben (oder nachschauen, welche ID für welche Benutzerdaten vergeben wurden...)


= op#ID_USERDATA:2;

(für weitere dann 3..4..5..6...usw.)
// INFO:
Wenn ihr statt einer reellen Zahl Prozentzahlen nehmt, beachtet, dass dann100%nur1.0alsRealist
50%dementsprechend0.5!
Somit wäre der Radius bei100%gerade mal die Einheit von1.
//
//INFO
Sollte es nach dem Kompilieren zu dem Fehler: „Parameter access failed“ kommen, bearbeitet die Benutzerdaten und überprüft die vergebene ID.
//

Wenn ihr jetzt die Animation abspielt, fährt das Objekt schön sauber im Kreis in einem Radius von 100 (m, km, was auch immer ihr eingestellt habt).

Um den Kreis darzustellen, kann man z.B. das Null-Objekt als Partikel-Emitter benutzen :)
Tun wir das doch einfach mal auf die schnelle :P . Mit Xpresso (Nicht Expresso!)

Bilder


Erstellt  einen p-Born-Node (glaub, der heißt in der deutschen Version P-Quelle) und einen P-Daten Setzen-Node. Zieht noch das Null-Objektin den Xpresso-Editor und verbindet die Ports wie im Bild:

Bilder


Setzt den Count auf ca100und die Lebenszeit von P-Quelle(P-Born) auf45, damit es einen sauberen Kreis ergibt :)

Bilder


Hier nochmal das gesamte Script mit Kommentaren :


main(doc,op) 
{ 
var frame = doc ->GetTime()->GetFrame(doc->GetFps()); // Auslesen der Frames 
var speed = 25; var distance = op#ID_USERDATA:1; // Userdaten von op Datensatz 1   
var pos = op ->GetMg()->GetV0(); // Matrix Global auslesen → Position  
pos.x = sin ( speed * frame ) * distance ; // SIN Berechnen mit veränderlicher Variable (frame) 
pos.y = cos ( speed * frame ) * distance ;// COS Berechnen mit veränderlicher Variable (frame)  
op ->SetPosition(pos); // Berechnete Position an Objekt zurückgeben 
println(pos); // Position in Konsole schreiben (nicht notwendig!)  
}


Bilder


---------------------

Aufgrund dessen, dass wir jetzt schon ein Xpresso-Tag an das Objekt geklebt haben, machen wir an der Stelle gleich weiter:

C.O.F.F.E.E. in Xpresso;
Erstellt dazu einen C.O.F.F.E.E.-Node:


Bilder


New Node>> Xpresso>> Berechne>> C.O.F.F.E.E.
Und löscht alle Aus- und Eingänge; das "Tolle" an C.O.F.F.E.E. in Xpresso ist immer noch, dass wir keine Variablen speichern müssen, die von außen kommen...
Die werden durch den Port-Namen vergeben ;)

Bilder


(Rechtsklick auf den Port selbst...)


Machen wir einfach mal die Generierung von Partikeln abhängig von der Zeit:

Jetzt noch ein neuer Node, der Zeit-Node:
Xpresso ->Allgemein -> Zeit

Löscht den Port "Zeit", erstellt dafür "Bild" (mit Klick auf das rote Kästchen!).
In Xpresso ist das C.O.F.F.E.E.-Script nicht an das Dokument (doc) geknüpft, daher müssen wir die Zeit manuell "einbinden".
Verbindet den Bild-Port mit einem neu erstellten C.O.F.F.E.E.-Eingangsport (Name: frame; Typ: Integer)

Bilder


Nun noch einen Ausgangs-Port: Typ: Bool; Name TP_on
(achtet auch hier auf die Schreibweise der Ports! Leerzeichen, Punkte, Kommas usw. werden nicht toleriert)
und verbindet "TP_on" mit dem Eingangs-Port "On" von P-Quelle (P-Born)

Bilder


Klickt nun auf den C.O.F.F.E.E.-Node und werft einen Blick in den Attribute-Manager! Man kann hier bereits das Script eintragen, würde ich allerdings nie tun ;)
Weil: 1. zu klein; 2. nicht so schön bunt! (Fehler werden übersehen!)
Klickt noch schnell auf "C.O.F.F.E.E.-Editor öffnen" und prompt öffnet sich wieder der gute alte Expression-Editor ;)

Löscht erst einmal das vorgegebene Script (eh sinnlos, Ports sind gelöscht).

Wir können das uns ganz einfach machen, sodass z.B. alle 8 Frames 1 Partikel generiert wird. Mit einer einfachen Division (nein, wir sind nicht beim Militär^^ ):
Division mit Rest: Modulo

Um dieses zu berechnen, brauchen wir die Frames und eine Konstante, die man wieder in einer var abspeichert (oder per Benutzerdaten ;) )
Schreibt erstmal:


main ()
{
var constante = 5;
var mod = Modulo( );
}

Der Befehl Modulo erwartet jetzt noch 2 Werte, je nachdem, in welcher Reihenfolge etwas geschehen soll:

Modulo( frame , constante );
Wenn z.B. Frame = 18 -> constante = 8 -> die 8 passt 2x in die 18 ->Rest 2 (8*2=16 <->18= -2)

Schreibt also in das Script:


var Modulo( frame , constante ) ;

Das sollte jetzt noch in eine IF-Anweisung!
Wenn also der "Rest" = 0 ist, dann setze TP_on = 1!

Schreibt dazu:

 

if ( mod == 0 ) 
{ 
TP_on = 1; 
} 

else 
{
TP_on = 0; 
}


Das gesamte Xpresso-/ C.O.F.F.E.E.-Script sieht dann so aus:


main() 
{ 
var constante = 8; 
var mod = Modulo ( frame , constante );  
if ( mod == 0) 
{
TP_on = TRUE;
} 
else 
{
TP_on = FALSE;
} 
} 


Wenn ihr das Script kompiliert (sollte es allerdings automatisch, sobald man etwas anderes macht ;) )
und die Animation startet, erstellt Cinema 4D alle 8 Frames an der Position des Null-Objektes einen Partikel!
(Bei 30 Frames pro Sekunde gibt es natürlich eine leichte Verschiebung der generellen Position der Partikel!)

--------------------------

Anwendungsbeispiel für C.O.F.F.E.E., ein Pendel mit SIN:

Erstellt wieder eine neue Szene und fügt ein Kreis-Spline ein:

Bilder


Konvertiert dieses mit der Taste "C", wechselt in den Punkte-Bearbeiten-Modus und baut in etwa diese Form nach:

Bilder


Die genaue Form spielt natürlich keine Rolle, wegen mir könnt ihr das auch mit einem Würfel machen! ;)
Solltet ihr doch mein Pendel nachbauen, ist es wichtig, dass die Null-Achse auch auf der Null-Position ist ;)

Fügt diesem "Objekt" nun einen C.O.F.F.E.E.-Tag zu und klickt in den Expressions-Editor; wider Erwarten brauchen wir 3 Variablen:

speed, distance und frame,

schreibt also wieder:


main (doc, op)
{
var speed = 25;
var distance = 50;
var frame = doc->GetTime()->GetFrame(doc->GetFps());
}

Da das Pendel ja "pendeln" soll, brauchen wir noch die Z-Rotation und speichern die Rotationen in der var rot ab!


var rot = op->GetRotation();


Jetzt wird noch Z berechnet:


rot.z = sin( frame * speed ) / distance;

Die Berechnung für Z jetzt wieder zurück an op (mit überschriebenen Z-Werten):


op->SetPosition(rot);

Kompilieren, Animation und starten!

Ein Blick in die perspektivische Ansicht verrät mir, dass ich statt SetRotation SetPosition geschrieben habe ...


op->SetRotation(rot);

Startet die Animation! Und das Pendel pendelt vor sich hin ;)

Das gesamte Script:


main (doc, op) 
{ 
var speed = 50; 
var distance = 2; 
var frame = doc->GetTime()->GetFrame(doc->GetFps());  
var rot = op->GetRotation(); 
rot.z = sin ( frame * speed ) / distance ; 
op->SetRotation(rot); 
}

Das war es dann auch schon wieder mit Teil 3...

In Teil 4 kommt:

- Distanzen von 2 Objekten ermitteln und Objekte darauf platzieren
- Plug In - Scripts (Interne Plugins mit dem Script-Editor)
- noch Wünsche?

DVD-Werbung
Kommentare
Achtung: Du kannst den Inhalt erst nach dem Login kommentieren.
Portrait von Lala_Ghost
  • 20.09.2013 - 16:07

Super, danke ich muss die Basics auch mal lernen! :)

Portrait von barri
  • 07.01.2011 - 17:51

Schließe mich den Vorrednern an. Hab mich wieder ein bischen mit COFFEE beschäftigt. :) Sehr schönes Tutorial

Portrait von thefip
  • 02.05.2010 - 21:42

Super Tutorial Danke

Portrait von zayacoon
  • 15.02.2010 - 17:23

Hallo, diese Coffee reihe ist sehr gut.
Bin schon auf den vierten Teil gespannt.

x
×
×