- PSP Spieleentwicklung - http://psp.anmabagima.de -
Initialisieren der GU
Dieser Eintrag stammt von AnMaBaGiMa Am 13.1.2010 @ 14:20 In Allgemein | 1 Kommentar
Um in einem Homebrew die vielen Funtkionen der GU nutzen zu können, muss diese zunächst Initialisiert werden. Dies geschieht über eine Reihe von Befehlen für die GU. Wie bereits in der Einführung erläutert arbeitet die GU dabei die Befehle ähnlich einem Batch von einer Liste ab.
Dies bedeutet, dass wir diese Liste zunächst in unserem Programm definieren müssen und der GU mitteilen, dass Ihre Befehle in genau diese Liste eingestellt werden. Wichtig ist, dass diese Liste im Speicher eine entsprechende Ausrichtung hat, also immer 16Bit Blöcke belegt.
static unsigned int __attribute__((aligned(16))) list[262144];
Um die GU nutzen zu können und für unsere Zwecke “einzurichten” muss sie mit folgendem Befehl initial “aktiviert” werden:
sceGuInit();
Am Ende der Homebrew müssen wir dann entsprechend die Nutzung der GU mit dem folgenden Befehl beenden:
sceGuTerm();
Bevor wir nun die ersten GU Befehle in die Liste schreiben, noch ein paar kurze Worte zur Abarbeitung der Liste. Hier gibt es unterschiedliche Möglichkeiten. Zum einen kann man die Liste direkt an die GU übergeben sobald diese fertig befüllt wurde, oder man bereitet die Liste vor und kann diese dann zu bestimmten Zeitpunkten an die GU übergeben.
Nun aber zur Einrichtung der GU….
Wir definieren 3 Zeiger für die Adresse der Puffer - Backpuffer, Bildschirm-/Anzeigepuffer und Z-Puffer. Der Addressbereich ist dabei relativ zur Startaddresse des von der GU verwalteten Speicherbereiches - oder auch VRAM genannt. Das heißt die relative Addresse 0 hat die absolute Addresse 0×44000000. Da die GU hier nur mit relativen Adressen arbeitet ist dieser Zusammenhang zunächst nicht so wichtig…
void* drawBuff = (void*)0×0;
//die Adresse des AnzeigePuffers sollte nach dem Zeichenpuffer beginnen
//dabei müssen die Adressen weitgenug auseinander liegen, so
//dass der komplette Bildschirminhalt in diesen Bereich passt.
//bei 480×272 Bildpunkten und 4 Byte Farbtiefe sind das 522240 Bytes.
//die PSP arbeitet intern aber immer mit einer Breite die eine Potenz von 2 ist. Damit werden
//im Puffer 512×272 Bildpunkte und 4 Bytes pro Punkt belegt. Das sind dann 557056 Bytes
//die Adresse muss also (in Hex) 0×88000 höher sein als die Zeichenpufferaddresse
void* displayBuff = (void*)0×88000;
//der Z-Puffer Adresse muss um die selbe Größe hinter dem BackPuffer kommen
void* depthBuff = (void*)0×110000;
//nun teilen wir der GU diese Speicheraddressen für den jeweiligen zweck mit.
//Dazu starten wir erstmal die Liste
sceGuStart(GU_DIRECT,list);
//beim festlegen des Zeichenpuffers müssen wir auch dessen Format mitgeben.
//also 4 Bytes pro Punkt (8bit rot, 8Bit grün, 8Bit blau, 8bit Alpha) und 512 Punkte breit
sceGuDrawBuffer(GU_PSM_8888,drawBuff,512);
//dem Darstellungspuffer müssen wir zusätzlich mitgeben breit und hoch der Bildschirm ist.
//plus der Pufferbreite. Interessanterweise kein Pixelformat
sceGuDispBuffer(480,272,displayBuff,512);
//nun noch den Tiefenpuffer. Auch hier muss die Pufferbreite entsprechend angegeben werden
sceGuDepthBuffer(depthBuff,512);
Wie in der Einleitung zur GU erwähnt, wird die virtuelle Welt durch einen sogenannten Viewport betrachtet. Diesen kann man sich als virtuellen Bildschirm im virtuellen Raum vorstellen durch den der Betrachter auf diese Welt schaut. Diesen Bildschirm werden wir als nächstes festlegen. Der virtuelle Raum der PSP in X und Y Richtung ist jeweils von 0 bis 4095 Einheiten groß und definiert damit ein virtuelles Koordinatensystem. Dabei ist die X-Achse horizontal und die Y-Achse vertikal ausgerichtet. Die Tiefe verläuft entlang der Z-Achse. Der initiale Betrachtungspunkt soll sich in der Mitte dieser Welt befinden, also bei (2048, 2048).
//der virtuelle Bildschirm soll zentriert sein
//und die Breite und Höhe des PSP Schirmes haben
//die GU geht hierbei immer von der Tiefe 0 aus.
sceGuViewport(2048,2048,SCR_WIDTH,SCR_HEIGHT);
Im virtuellen Koordinatensystem das nun von 0 nur Positiv bis 4095 geht ist es zum Teil sehr umständlich Objekte darzustellen, da wir es gewohnt sind ein Koordinatensystemzentrum zu haben (Nullpunkt) von dem aus sich jede Dimension sowohl in die Positive als auch die negative Richtung ausbreitet. Darum setzen wir über eine Funktion in der GU den 0 Punkt des Koordinatensystems in die Mitte der X- und Y- Ausdehnung. Dadurch werden alle weiteren Koordinatenangaben (-2047 bis +2047 relativ zu diesem Mittelpunkt angegeben und von der GU in die Absoluten Koordinaten (0 bis 4095) umgerechnet.
//der Koordinatensystemoffset (Nullpunkt) wird abhängig von der virtuellen
//Bildschirmgröße gesetzt. Wieso ? das ist nicht ganz klar…
//ich hätte hier - vermutlich wie Ihr auch - einen Offset bei 2048/2048 erwartet.
sceGuOffset(2048 - (SCR_WIDTH/2),2048 - (SCR_HEIGHT/2));
Bisher haben wir die GU hauptsächlich in der X und Y-Ausdehnung initialisiert. In der Z - also der Tiefenrichtung scheint es keine Mittelpunktinitialisierung zu geben. Dennoch muss für den Tiefenpuffer eine Art Kallibrierung stattfinden. Diese legt fest in welchem Bereich die Tiefenwerte des Z-Puffers liegen können. Damit wird quasi die Granularität des Tiefenpuffers bestimmt. Je größer die Breite des Tiefenpuffers umso dichter können Objekte (von der Tiefe her) beieinander liegen und werden dennoch korrekt als in verschieder Tiefe liegende Objekte erkannt. Ist der Bereich für den Tiefenpuffer zu klein, dann kann die GU bei Objekten die dicht beieinander liegen nicht unterscheiden wer vorne und wer hinten ist.
//setzen des maximalen Tiefenbereiches
sceGuDepthRange(65535,0);
Neben dieser - nennen wir sie mal Basisinitialisierung - können in der GU noch diverse sinnvolle bzw. notwendige Funktionen aktiviert/deaktiviert werden. So zum Beispiel das “Clipping”, welches Objekte die sich ausserhalb des Sichtbereiches der virtuellen Kamera befinden nicht für die Darstellung berechnet. Hier also die Codestellen + Kommentar:
//aktivieren des “Zuschneiders”.
//damit wird das Berechnete Bild auf die Masse des Bildschirms zugeschnitten.
sceGuEnable(GU_SCISSOR_TEST);
sceGuScissor(0,0,SCR_WIDTH,SCR_HEIGHT);
//aktivieren der Tiefenprüfung
sceGuEnable(GU_DEPTH_TEST);
sceGuDepthFunc(GU_GEQUAL);
//Nochmals festlegen, dass “vorne” im Uhrzeigersinn ist (ClockWise)
sceGuFrontFace(GU_CW);
// aktiviere dass Flächen von “hinten” nicht gezeichnet werden
sceGuEnable(GU_CULL_FACE);
//aktiviere das Clipping
sceGuEnable(GU_CLIP_PLANES);
//aktiviere das Licht
sceGuEnable(GU_LIGHTING);
//setze des Umgebunbgslicht auf einen hellen Wert.
//Die Farbe wird dabei in Hexform als ABGR - also
//Alpha-Blau-Grün-Rot Wert die jeweils von 0 bis FF gehen abgebildet
sceGuAmbient(0xFFFFFFFF);
Nun ist die GU - zumindest initial - eingerichtet. Wir können die nun gefüllte Liste anschließen und an die GU übergeben. Sobald dies geschehen ist, wird die Sichtbarkeit des von der GU bereitgestellten Sichtbaren puffers aktiviert.
//abschließen der GU Liste führt zur sofortigen Abarbeitung
//in diesem Falle, da wir die Liste mit GU_DIRECT gestartet haben
sceGuFinish();
sceGuSync(0,0);
//Aktiviere die Anzeige der GU auf dem realen Bildschirm
sceGuDisplay(GU_TRUE);
Wichtig beim setzen/aktivieren von Funtkionen/Stati in der GU ist, dass einmal gesetzte Werte so lange unverändert bleiben bis man sie wieder ändert, unabhängig davon ob diese Einstellungen in einer Liste an die GU übergeben werden oder nacheinander in mehreren. Hat man also einmal das Licht aktiviert bleibt es so lange aktiv bis es deaktiviert wird.
Der nun noch notwendige Schritt der die Initialisierung abschließen soll, legt fest wie die 3D Landschaft durch unsere virtuelle Kamera “gesehen” wird. Dies bedeutet der Kamera das Seitenverhältnis, den Öffnungswinkel - den sogenannten FOV - und die sichtbaren Grenzen für nahe und ferne Objekte anzugeben. Über die folgenden Codezeilen stellen wir unsere Kamera auf einen Öffnungswinkel (FOV) von 45° , ein Seitenverhältnis von 16:9 ein.
//um die Matrizenfunktion der GU nutzen zu können
//muss dieser Bereich auch noch inititialisiert werden
gumInit();
// Starten einer neuen GU Liste
sceGuStart(GU_DIRECT,list);
//die Umrechnung der 3D Welt über die Kamera auf den PSP Bildschirm
//wird durch die Projektionsmatrix abgebildet
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadIdentity();
//festlegen der Kameraperspective und füllen der Projektionsmatrix mit diesen Daten
sceGumPerspective(45.0f,16.0f/9.0f,1.0f,1000.0f);
sceGuFinish();
sceGuSync(0,0);
Dieser Artikel wurde ausgedruckt ab PSP Spieleentwicklung: http://psp.anmabagima.de
URL zum Artikel: http://psp.anmabagima.de/gu-grafikpower-der-psp/initialisieren-der-gu/
Klicken hier zum Drucken.