3D Gu


Lua unterstützt sogar die Arbeit mit 3D Objekten, insofern im LuaPlayer eine "3D Gu" enthalten ist. Ich empfehle allerdings, dass Anfänger die Finger davon lassen, denn die Arbeit mit der 3D Gu ist recht schwer. Zuerst einmal sollte man wissen, dass es in 3D nicht nur die x und y Achsen gibt, sondern x,y, und z Achse. Also Höhe, Breite und Tiefe. Zudem kann man in der 3D Guauch nicht von "blit" reden, da ja kein Bild in der 2 Dimensionalen Ebene dargestellt wird, sondern ein 3-dimensionalesObjekt. Die Funktion hierfür heisst Gum.translate(x,y,z). Desweiteren läuft eine 3D-Darstellung auch etwas anders ab als eine 2-dimensionale.

Grundlegend kann man in jedes Lua-Script die 3D Gu, insofern der LuaPlayer es abspielen kann, einbetten. Die 3D Gu muss gestartet und auch wieder geschlossen werden:

	Gu.start3d()
		--der Code für das Objekt
	Gu.end3d()
	

Nun, wir müssen systematisch vorgehen. Zuallererst benötigen wir eine Farbe und die Farbtiefe für unser Objekt, dass wir noch gar nicht erstellt haben. Also weisen wir der 3D Gu eine Farbe und eine Farbtiefe zu:

	Gu.clearColor(farbe)
	--...legt die Füllfarbe fest
	Gu.clearDepth(0)
	--...legt die Farbtiefe fest, von 0 bis 255(0=kein Farbtiefe,255=größte Farbtiefe)
	Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT)
	--...weist dem Objekt die eingegebene Farbe und Farbtiefe zu
	

Also sieht der Code bisher so aus:

	farbe = Color.new(255,0,255)
	Gu.start3d()
	Gu.clearColor(farbe)
	Gu.clearDepth(0)
	Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT)
	Gu.end3d()
	

Nun, weiter geht es. Nachdem jetzt die Farbe und Farbtiefe festgelegt ist, müssen wir dem LUAPlayer mitteilen, wie wir auf das Objekt schauen werden. Das ganze nennt man auch "Kamera", also die Sicht auf das "Model" (Objekt). Das wird so festgelegt:

	Gum.matrixMode(Gu.PROJECTION)
	Gum.loadIdentity()
	Gum.perspective(50, 16/9, 0.5, 1000)
	

Dieser Codeblock legt die Kameraposition fest. Der Wert 50 legt fest, wieviel man von der 3D Gu sehen kann. 16/9 ist die Bilddarstellung. 0.5 legt fest, wie nah man das Objekt sehen kann. 1000 legt fest, bis in welche Entfernung man das Objekt sehen kann.

Folglich sieht der gesamte 3D Gu Code so aus:

	farbe =Color.new(255,0,255)
	Gu.start3d()
	Gu.clearColor(farbe)
	Gu.clearDepth(0)
	Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT)
	Gum.matrixMode(Gu.PROJECTION)
	Gum.loadIdentity()
	Gum.perspective(50, 16/9, 0.5, 1000)
	Gu.end3d()
	

...das war es aber noch lange nicht, denn nun folgt, nachdem die Farbdarstellung und die Perspektive festgelegt wurde, der Anzeigemodus:

	farbe = Color.new(255,0,255)
	Gu.start3d()
	Gu.clearColor(farbe)
	Gu.clearDepth(0)
	Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT)
	Gum.matrixMode(Gu.PROJECTION)
	Gum.loadIdentity()
	Gum.perspective(50, 16/9, 0.5, 1000)
	Gum.matrixMode(Gu.VIEW)
	Gum.loadIdentity()
	Gu.end3d()
	

...was jetzt noch fehlt ist/sind das/die eigentliche(n) Objekt(e). Und die sind im großen und ganzen nur am Anfang schwer.Wenn man das Konzept dahinter einmal verstanden hat, dürfte es nicht mehr schwer sein. Vorweg, es gibt 7 Arten von Formen & Figuren:

Gu.POINTS- zeichnet Punkte.
Gu.LINES- zeichnet Linien.
Gu.LINES_STRIP- Zeichnet aneinandergereihte Linien.
Gu.TRIANGLES- Zeichnet Dreiecke.
Gu.TRIANGLES_STRIP- zeichnet aneinandergehängte Dreiecke.
Gu.TRIANGLES_FAN- zeichnet ebenfalls aneinandergehängte Dreicke, allerdings an 2 andere Eckpunkte.
Gu.SPRITES- zeichnet Quader.

Zusätzlich können solche Objekte nur im Gu.matrixMode(Gu.MODEL) angezeigt werden. Das bedeutet, es gibt wieder ein Codeupdate, und wir nähern uns langsam dem Ziel!

	farbe = Color.new(255,0,255)
	Gu.start3d()
	Gu.clearColor(farbe)
	Gu.clearDepth(0)
	Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT)
	Gum.matrixMode(Gu.PROJECTION)
	Gum.loadIdentity()
	Gum.perspective(50, 16/9, 0.5, 1000)
	Gum.matrixMode(Gu.VIEW)
	Gum.loadIdentity()
	Gum.matrixMode(Gu.MODEL)
	Gum.loadIdentity()
	Gum.translate(0, 0, -3)
	Gu.disable(Gu.TEXTURE_2D)
	Gu.end3d() 
	

Ganz wichtig, Gum.translate legt die Position des Objektes im 3D-Koordinatensystem fest! In diesem Fall sind Texturen zusätzlich deaktiviert, das Objekt bekommt nur Farbe. Soweit so gut, wollen wir doch endlich mal ein Objekt erstellen. Dafür sollte man wissen, wie Tables funktionieren.

	triangle = {
		{red,3,-2,0}, --eckpunkt 1
		{red,-3,-2,-2}, --eckpunkt 2
		{red,3,3,-1}, --eckpunkt 3}
	} 
	

Diese Table liefert nachher die Werte für das zu zeichnende Dreieck. Grundsätzlich muss die Table so aussehen:

	table = {
		{farbe,x,y,z}
	}
	

Beim Dreieck brauchen wir eben 3 von diesen "innertable Tables", da ein Dreieck eben 3 Eckpunkte hat. Bei einem Punkt Bei einem Punkt braucht man nur eines davon. Nun gut, da wir jetzt unser Dreieck haben, kommt der finale Schritt, nämlich das Stückchen Code in der Gu, dass unsere Table "triangle" verwendet, um ein Dreieck zu zeichnen:

	Gum.drawArray(Gu.TRIANGLES, Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D, triangle)
	

...diese sehr kompliziert aussehende Zeile gibt unser Dreieck aus! Und so extrem kompliziert ist sie auch gar nicht. Der erste Teil in der Klammer "Gu.TRIANGLES" teilt dem LUAPlayer mit, dass ein Dreieck gezeichnet werden soll. Für einen Punkt müsste hier "Gu.POINTS" stehen. Der zweite Teil sagt, dem LUAPlayer, dass wir uns im 32 Bit Modus befinden. Den zweiten Teil muss man nicht wirklich verstehen, den kann man einfach so stehen lassen. Im dritten Teil informieren wir den LUAPlayer, wo er die Eckpunkte des Dreiecks finden kann. Unsere Table oben heisst "triangle", darin befinden sich die Koordinaten der Eckpunkte. Und die verwenden wir auch hier. Hier also mal der komplette Code:

	red = Color.new(255,0,0)
	triangle = {
		{red,3,-2,0}, --eckpunkt 1
		{red,-3,-2,-2}, --eckpunkt 2
		{red,3,3,-1}, --eckpunkt 3
	}
	farbe =Color.new(255,0,255)
	Gu.start3d()
	Gu.clearColor(farbe)
	Gu.clearDepth(0)
	Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT)
	Gum.matrixMode(Gu.PROJECTION)
	Gum.loadIdentity()
	Gum.perspective(50, 16/9, 0.5, 1000)
	Gum.matrixMode(Gu.VIEW)
	Gum.loadIdentity()
	Gum.matrixMode(Gu.MODEL)
	Gum.loadIdentity()
	Gum.translate(0, 0, -3)
	Gu.disable(Gu.TEXTURE_2D)
	Gum.drawArray(Gu.TRIANGLES, Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D, triangle)
	Gu.end3d()
	

...das waren die Grundlagen der 3D Gu. Es gibt da jetzt noch ein paar weitere Funktionen, und Texturen darf man natürlich auch nicht vergessen:

	Gum.rotateXYZ(x* (Gu.PI/180),y* (Gu.PI/180),z* (Gu.PI/180))
	--rotiert ein Objekt nach den eingegebenen Werten. Der Befehl sollte nach Gum.translate() 
	--und vor Gum.drawArray() platziert werden. Werte kann man für x,y und z einsetzen.
	
	Gum.lookAt(vonwox,vonwoy,vonwoz,nachx,nachy,nachz,0,1,0)
	--ändert die Kameraposition von der Standardposition zu den eingegebenen Positionen.
	--Das 0,1,0 am Ende muss man nicht verändern.
	

Und nun noch das Verwenden von Texturen:

	Gu.enable(Gu.BLEND)
	Gu.blendFunc(Gu.ADD, Gu.SRC_ALPHA, Gu.ONE_MINUS_SRC_ALPHA, 0, 0)
	Gu.enable(Gu.TEXTURE_2D);
	

Diese 3 Befehle aktivieren die Verwendung von Texturen.

	Gu.texImage(bild)
	--verwendet das angegebene Bild als Textur.
	

Nun noch ein paar Zeilen Code, die man vorerst nicht verstehen muss und die man so lassen kann. Lediglich die Farbe "white" sollte auch richtig definiert sein:

	Gu.texFunc(Gu.TFX_MODULATE, Gu.TCC_RGBA)
	Gu.texEnvColor(white)
	Gu.texFilter(Gu.LINEAR, Gu.LINEAR)
	Gu.texScale(1, 1)
	Gu.texOffset(0, 0)
	Gu.ambientColor(white)
	

Das mit den Texturen geht ja nun auch recht schnell. Es muss dann nur noch eine kleine Änderung bei Gum.drawArray() vorgenommen werden.

	Gum.drawArray(Gu.TRIANGLES, Gu.TEXTURE_32BITF+Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D,table)
	

...hier sieht der 2. Parameter (Wert) in der Klammer etwas anders aus. Er wurde für die Verwendung von Texturen angepasst. Zur Übersicht und Veranschaulichung hier noch der gesamte Code mit Textur:

	white = Color.new(255,255,255)
	red = Color.new(255,0,0)
	bild = Image.load("bild.png")
	
	triangle = {
		{0,0,red,0,0,0},
		{1,0,red,1,0,0},
		{1,1,red,1,-1,0},
		
		{0,0,red,0,0,0},
		{0,1,red,0,-1,0},
		{1,1,red,1,-1,0}
	}
	
	farbe =Color.new(255,0,255)
	Gu.start3d()
	Gu.clearColor(farbe)
	Gu.clearDepth(0)
	Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT)
	Gum.matrixMode(Gu.PROJECTION)
	Gum.loadIdentity()
	Gum.perspective(50, 16/9, 0.5, 1000)
	Gum.matrixMode(Gu.VIEW)
	Gum.loadIdentity()
	Gu.enable(Gu.BLEND)
	Gu.blendFunc(Gu.ADD, Gu.SRC_ALPHA, Gu.ONE_MINUS_SRC_ALPHA, 0, 0)
	Gu.enable(Gu.TEXTURE_2D)
	Gu.texImage(bild)
	Gu.texFunc(Gu.TFX_MODULATE, Gu.TCC_RGBA)
	Gu.texEnvColor(farbe)
	Gu.texFilter(Gu.LINEAR, Gu.LINEAR)
	Gu.texScale(1, 1)
	Gu.texOffset(0, 0)
	Gu.ambientColor(farbe)
	Gum.matrixMode(Gu.MODEL)
	Gum.loadIdentity()
	Gum.translate(0, 0, -3)
	Gum.drawArray(Gu.TRIANGLES, Gu.TEXTURE_32BITF+Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D,triangle)
	Gu.end3d()
	

Noch ein nachträglicher Hinweis: die Auflösung der Texturbilder muss durch 8 Teilbar sein und darf maximal 512x512 betragen. Ich habe es zwar versucht einigermaßen verständlich zu erklären, aber trotzdem kann es ein wenig unverständlich sein, da ich mich persönlich nicht richtig intensiv mit der 3D Gu beschäftige. Am besten fängt man hiermit an und lernt dann Stück für Stück dazu, "learning by modding" nenn ich das. Fragen bitte ins Forum posten, Danke!