Hi,
ich sitze schon seit einiger Zeit an einer 3D - Engine (ich muss dazu sagen, dass ich das ganze Ding mehr oder weniger selbst schreiben möchte, um den Hintergrund zu verstehen)
Hierzu habe ich folgende Klassen erstellt:
DrawFrame - Erbt von JFrame, implementiert Runnable und stellt wiederholt das Bild auf dem Bildschirm dar
Main - Implementiert Runnable und verteilt die Spieldaten (Spieler/Kamera-Position, Bild, Blickrichtung) und sorgt dafür, dass bei Schließaufforderung des DrawFrames alle Threads beendet werden
Container - Implementiert Runnable und enthält mehrere Chunks, die ebenfalls von Runnable erben, und hat die Aufgabe, die festen Bestandteile der Spielwelt zu verwalten (Dreiecksklasse -> Plain). Die Chunks verwalten die Flächen und sortieren sie vor, der Container stellt daraus 2 Listen zusammen. Die 1. Liste wird vom Grafiker benötigt und soll gemalt werden, die 2. vom Physiker und soll zur physik. Berechnung dienen
Physiker - Erbt von Runnable und soll mit den Flächen vom Container realistische Physik ermöglichen
Rechenzentrum - Rechenzentrum ist mehr oder weniger eine Schnittstelle zu Methoden, die das berechnen auf der Grafikkarte ermöglichen sollen. Das mit der Grafikkarte habe ich mithilfe von lwjgl.jocl erstellt.
Grafiker - Die momentan aufwendigste Klasse. Erbt von Runnable und soll die Flächen darstellen. Hierzu müssen die Flächen natürlich gedreht, um die Spielerposition verschoben und auf einen virtuellen Bildschirm transformiert werden
Mein Problem: Der Grafiker läuft im Moment noch (bei einer Fläche) mit 1 - 2 FPS. Das ist natürlich nciht ganz so toll
Weiter unten findest du die run-Methode.
Wie kann man die so ändern, dass er schneller läuft?
Ist die Programmstruktur so in Ordnung?
Ich hab nämlich so ne leise Ahnung, dass das mit den ganzen Runnables suboptimal sein KÖNNTE (100% Leistungs-Auslastung)
Wie ist die Struktur bei 3D-Engines/-Spielen im allgemeinen?
Ich bin dankbar für jede Antwort
Code:
Eine besondere Frage zu den Zahlen nach den r.init() -Aufrufen:
Soweit ich das verstanden habe, macht jeder Core in der Grafikkarte eine eigene Berechnung und ruft dabei aus den CLMem - Objekten denjenigen Index auf, dem er zugeteilt worden ist. Da aber nur begrenzt viele Cores zur Verfügung stehen muss ich das ja irgenwie beschränken (Momentan mit counter > x)
Wie krieg ich aber genau raus, wieviele Cores ich benutzen darf?
Ich danke jedem, der sich auch nur die Mühe gemacht hat, das alles hier duchzulesen :toll:
Gruß eMmiE
ich sitze schon seit einiger Zeit an einer 3D - Engine (ich muss dazu sagen, dass ich das ganze Ding mehr oder weniger selbst schreiben möchte, um den Hintergrund zu verstehen)
Hierzu habe ich folgende Klassen erstellt:
DrawFrame - Erbt von JFrame, implementiert Runnable und stellt wiederholt das Bild auf dem Bildschirm dar
Main - Implementiert Runnable und verteilt die Spieldaten (Spieler/Kamera-Position, Bild, Blickrichtung) und sorgt dafür, dass bei Schließaufforderung des DrawFrames alle Threads beendet werden
Container - Implementiert Runnable und enthält mehrere Chunks, die ebenfalls von Runnable erben, und hat die Aufgabe, die festen Bestandteile der Spielwelt zu verwalten (Dreiecksklasse -> Plain). Die Chunks verwalten die Flächen und sortieren sie vor, der Container stellt daraus 2 Listen zusammen. Die 1. Liste wird vom Grafiker benötigt und soll gemalt werden, die 2. vom Physiker und soll zur physik. Berechnung dienen
Physiker - Erbt von Runnable und soll mit den Flächen vom Container realistische Physik ermöglichen
Rechenzentrum - Rechenzentrum ist mehr oder weniger eine Schnittstelle zu Methoden, die das berechnen auf der Grafikkarte ermöglichen sollen. Das mit der Grafikkarte habe ich mithilfe von lwjgl.jocl erstellt.
Grafiker - Die momentan aufwendigste Klasse. Erbt von Runnable und soll die Flächen darstellen. Hierzu müssen die Flächen natürlich gedreht, um die Spielerposition verschoben und auf einen virtuellen Bildschirm transformiert werden
Mein Problem: Der Grafiker läuft im Moment noch (bei einer Fläche) mit 1 - 2 FPS. Das ist natürlich nciht ganz so toll
Wie kann man die so ändern, dass er schneller läuft?
Ist die Programmstruktur so in Ordnung?
Ich hab nämlich so ne leise Ahnung, dass das mit den ganzen Runnables suboptimal sein KÖNNTE (100% Leistungs-Auslastung)
Wie ist die Struktur bei 3D-Engines/-Spielen im allgemeinen?
Ich bin dankbar für jede Antwort
Code:
Code:
while(running) {
if (c.getReadyG()) {
//Erst die Variablen setzen, die man für den Durchlauf benötigt
final float r = this.R; //Winkel nach oben/unten in Radiant
final float b = this.B;//Winkel nach links/rechts in Radiant
final float[] spieler = s.retList(); gibt die Spielerposition in einem float[] zurück
this.buf = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
this.g = buf.createGraphics();
delta = System.nanoTime();
//Hier jetzt die ganzen Umformungen
//Alle Flächen holen
this.plains = convert(c.getGraphlist()); //c ist Instanz von Container
c.unreadyG(); //Teilt Container mit, dass die Liste geholt wurde
if (this.plains.length != 0) {
// Alle Punkte um minus S verschieben
plains = mux(mux(move(demux(demux(plains)),spieler)));
//move() kann nur mit einem float[] arbeiten, daher müssen wir den DDDPoint[] erst zu float[] umformen (1 * Plain -> DDDPoint[3] -> float[9])
// Alle Punkte um R und S rotieren
plains = mux(mux(turn(demux(demux(plains)),-r,-b)));
//@turn() s.o.
// Alle Flächen aussortieren, die hinter dem Spieler liegen (Mittelpunkt)
boolean[] bools = Xsmaller0(plains);
//Blickrichtung x-Achse
int counter = 0;
for (int i = 0;i < bools.length;i++) {
if (bools[i]) {
counter++;
}
}
Plain[] a = new Plain[counter];
counter = 0;
for (int i = 0;i < bools.length;i++) {
if (bools[i]) {
a[counter++] = plains[i];
}
}
plains = a;
// Nach Entfernung sortieren...
float[] Entfernung = new float[plains.length];
float[] mids = new float[plains.length * 3];
for (int i = 0;i < plains.length;i++) {
DDDPoint[] p = new DDDPoint[] {plains[i].getMid()};
float[] work = demux(p);
mids[i * 3 + 0] = work[0];
mids[i * 3 + 1] = work[1];
mids[i * 3 + 2] = work[2];
}
this.r.init("mult");
//Das ist nötig, damit er die Kernel (JOCL) initialisieren kann
counter = mids.length;
while (true) {
float[] work;
if (counter > 256) {
work = new float[256];
for (int i = 0;i < work.length;i++) work[i] = mids[i + counter - 256];
work = this.r.mult(work, work);
for (int i = 0;i < work.length;i++) mids[i + counter - 256] = work[i];
counter -= 256;
} else {
work = new float[counter];
for (int i = 0;i < work.length;i++) work[i] = mids[i];
work = this.r.mult(work, work);
for (int i = 0;i < counter;i++) mids[i] = work[i];
counter = 0;
break;
}
}
this.r.finish("mult");
//Gibt Ressourcen wieder frei
//--> 0,2 Sekunden =(
//jetzt Entfernung ausrechnen
this.r.init("heron");
//@"heron" -> Wurzelnäherungsverfahren nach heron
float[] sum = new float[mids.length / 3];
for (int i = 0;i < mids.length / 3;i++) {
sum[i] = mids[i * 3 + 0] + mids[i * 3 + 1] + mids[i * 3 + 2];
}
counter = sum.length;
while (true) {
float[] work;
if (counter > 512) {
work = new float[512];
for (int i = 0;i < work.length;i++) work[i] = sum[i + counter - 512];
work = this.r.sqrt(work, 5);
for (int i = 0;i < work.length;i++) sum[i + counter - 512] = work[i];
counter -= 512;
} else {
work = new float[counter];
for (int i = 0;i < work.length;i++) work[i] = sum[i];
work = this.r.sqrt(work, 5);
for (int i = 0;i < counter;i++) sum[i] = work[i];
counter = 0;
break;
}
}
this.r.finish("heron");
//--> 0,2 Sekunden =(
// jetzt sortieren
qs.parallelSortieren(sum, plains);
//--> Sehr kurz =)
counter = sum.length-1;
while(sum[counter] > this.renderwidth) {
counter--;
}
Plain[] work = new Plain[counter];
for (int i = 0;i < counter;i++) work[i] = plains[i];
// umformen
Triangle[] t = this.tr.transform(work);
// einfach nur malen, da die sowieso schon sortiert sind
for (int i = t.length;i > 0;i--) {
g.setColor(java.awt.Color.green);
g.fillRect(0, 0, this.width, this.height);
t[i].paint(g);
}
delta = System.nanoTime() - delta;
fps = (int)(1 / (float)((float)delta / 1000000000) + 0.5);
this.toRecieve = this.buf;
//Buffer-Bild wird umgeschrieben, damit immer nur das "fertige" genommen werden kann
}
}
}
Eine besondere Frage zu den Zahlen nach den r.init() -Aufrufen:
Soweit ich das verstanden habe, macht jeder Core in der Grafikkarte eine eigene Berechnung und ruft dabei aus den CLMem - Objekten denjenigen Index auf, dem er zugeteilt worden ist. Da aber nur begrenzt viele Cores zur Verfügung stehen muss ich das ja irgenwie beschränken (Momentan mit counter > x)
Wie krieg ich aber genau raus, wieviele Cores ich benutzen darf?
Ich danke jedem, der sich auch nur die Mühe gemacht hat, das alles hier duchzulesen :toll:
Gruß eMmiE