Darstellungproblem Drehung/Richtung

Network

Top Contributor
Hi,

Problem "Gradzahl". Ich berechne bereits (wie ich finde) sehr umständlich und zeitintensiv den Einheitsvektor, bzw. den Richtungslaufvektor der Objekte per
Java:
vx = streckex1x2 / Math.sqrt( streckex1x2 * streckex1x2 + streckey1y2 * streckey1y2 );
vy = streckey1y2 / Math.sqrt( streckex1x2 * streckex1x2 + streckey1y2 * streckey1y2 );
(Selbstverständlich berechne ich in echt das Ergebniss der Wurzel nur einmal)

Kostet jedoch fast genau stolze 300Nanosekunden pro Berechnung auf meinem i5.


Jetzt kommt OpenGL daher und will von mir jetzt aber die Gradzahl um die Richtung des Objektes auch visualisieren zu können.
Also opengl.glRotatef( grad, x, y, z );

Das heißt ich muss nochmal umrechnen per Sinus und Cosinus. Das kostet nochmal ein paar Nanosekunden mehr.

Sinn der Sache ist es, wenn ich das Programm/Spiel/Simulation auf meinem Handy laufen lasse, wird es relativ schnell warm und verliert auch an Batteriepower.
Deshalb versuche ich irgendwie die Berechnungen zu optimieren, klein aber fein eben.

Also im Grundegenommen lautet die Frage: Was mach ich falsch? Gibt es bessere Lösungsansätze/Berechnungen. Oder kann man OpenGL direkt den Drehvektor übergeben?
Ich finde für dieses Problem einfach keine Lösung, weder Internet noch Hirn.jar spuckt Ergebnisse aus.

Vielen Dank
Gruß
Net
 

Marco13

Top Contributor
Wie du glaubst, 300ns gemessen zu haben, würde mich schon mal interessieren (das ist die Zeit, die ein Lichtstrahl braucht, um 90m zurückzulegen... ).


Ansonsten... beschreib' nochmal konkret, was du meinst. Wozu berechnest du die normierten Vektoren? Und worum willst du dann mit OpenGL drehen, und was hat das mit sin/cos und Grad zu tun? Suchst du sowas wie Math.atan2 ?
 

Network

Top Contributor
Also ich möchte ein Objekt in einem 2-Dimensionalen Raum bewegen können.
Dafür brauche ich einen Richtungsvektor, dann kann der X- und Y-Position dieser Richtungsvektor addiert werden um das Objekt zu bewegen.

Wenn ich jetzt aber eine bestimmte Maximalgeschwindigkeit haben möchte, muss ich den Vektor normieren und dann mit der gewählten Geschwindigkeit multiplizieren.
Ansonsten würde er ja vom Startpunkt gleich zum Endpunkt springen.

Aber das wird ja jetzt mit Wurzel ziehen, multiplizieren und dividieren berechnet. Also die Berechnungen die man ja jetzt eig. vermeiden sollte.
Das zieht natürlich dann auch an Zeit und Rechenpower.
Und wenn ich den Wert jetzt schon berechne, dann würde ich ihn auch gerne gleich dafür verwenden, bei OpenGL die Darstellung des Objektes(Bild) in die jeweilige Richtung zu drehen, in die es sich auch bewegt.
Jetzt will OpenGL aber Gradzahlen haben. Also muss ich den schön berechneten Einheitsvektor nochmal per Sinus und Cosinus in eine Gradzahl umberechnen.

1.) Die Frage war also allgemein, ob es bessere Wege gibt ein Objekt von a nach b rechnen.
Oder gibt es evt. in OpenGL irgendwie die Möglichkeit den Richtungsvektor anstatt der Gradzahl zu übergeben.

2.) Ich dachte System.timeInNanoseconds (oder so ähnlich) gibt auch Nanosekunden zurück... hier kam 300 heraus, wenn ich Start und Endzeit subtrahiert hatte.

3.) Bei OpenGL habe ich jetzt gefunden, was OpenGL bei glRotatef genau macht. Und er wandelt die Gradzahl tatsächlich wieder in einen(/den) normierten Vektor (zurück). Ich versuche gerade das ganze umzusetzen was da noch so berechnet wird, aber ich kapier irgendwie nicht ganz was ich machen muss. Es will irgendwie nicht.

Gruß
Net
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Erstmal vorneweg: System.nanoTime() liefert zwar eine Zeit in Nanosekunden, aber die Auflösung des Zeitmessers ist nicht "eine Nanosekunde". Auf Windows ist die Auflösung AFAIR ca. 400ns, aber das heißt nicht, dass man damit eine sqrt-Berechnung "messen" könnte.

Also muss ich den schön berechneten Einheitsvektor nochmal per Sinus und Cosinus in eine Gradzahl umberechnen

Das ist/war mir nicht ganz klar, aber ich vermute jetzt, dass du aus diesem Richtungsvektor einen Drehwinkel berechnen willst, der der Richtung entspricht - z.B. um ein Raumschiff, das in diese Richtung fliegt, so zu drehen, dass seine Spitze auch wirklich in diese Richtung zeigt. Dafür könnte man, wie meine Kristallkugel schon angedeutet hat, Math.toDegrees(Math.atan2(y,x)) verwenden.

Ansonsten ist eine sqrt zwar teuer, und man sollte sie vermeiden, wenn man kann, aber ... manchmal KANN man das eben nicht - z.B. wenn man einen Vektor normieren will.

Falls ich das jetzt nichtig verstanden habe, brauchst du den normierten Vektor ja ohnehin. Je nach Anwendungsfall könnte man in Betracht ziehen, IMMER nur den Drehwinkel zu speichern. Dann braucht man sin/cos um den Richtungsvektor zu berechnen, aber wie aufwändig das im Vergleich zu einem atan2 ist, ist schwer zu sagen (und, bevor du's versuchst: Auch schwer bis unmöglich vernünfig zu messen ;) )

Die Frage, was glRotatef macht, ist vielleicht ganz interessant: Er multipliziert die aktuelle Matrix mit einer Rotationsmatrix. Und in 2D ist es wohl immer eine Rotation um die z-Achse. Die Spalten der Rotationsmatrix sind die Bilder der Einheitsvektoren. D.h. wenn man schon einen normierten Richtungsvektor hat, kann man den theoretisch direkt in die Matrix eintragen. Aber ... man muss auch in Betracht ziehen, dass OpenGL viel in Hardware macht, und zu versuchen, ihm da (durch eigene Berechnungen) zu "helfen", könnte nach hinten losgehen.

Ob sich solche Optimierungsversuche "lohnen" ist eine heikle Frage - speziell auf einem Handy kann ich das kaum einschätzen. Aber dort dürften für die Performance auch andere Fragen wichtig sein - und vielleicht wichtiger, als ein sqrt oder sin zu vermeiden: Objektallokationen, Speicherzugriffe etc. Hast du irgendeine Möglichkeit zum Profiling?
 

Network

Top Contributor
Achso ok, also ich hatte 20 000 000 mal die oben aufgeführte Rechnung ausgeführt und danach nochmal 40 000 000 mal aber mit Zeitmessung. Der Durchschnitt von 4 Messdurchgängen ergab fast immer exakt 300, deshalb hoffte ich auf eine relativ genaue Aussage.

Nur den Drehwinkel zu speichern, würde meinen Anwendungszwecken nicht gerecht werden. Wobei mir gerade auffällt, dass ich den Drehwinkel jetzt auch jedesmal für die Mathklasse in Radians brauche :shock:
Naja aber bis jetzt läuft noch alles flüssig, bzw. wieder. Ich dachte meine Engine wäre zu langsam weil alles gehängt hatte von vorne bis hinten um dann jetzt auf ein informatik Problem zu stoßen, was maximale Speichergröße und Casten angeht.
Jetzt läuft es wieder flüssig.

Da ich tatsächlich vorhabe, es später auch für Android umzuwandeln, habe ich mir eine offizielle Liste durchgelesen und angeschaut was alles merkbare Performanceänderungen herbeiführt.
Und ehrlich gesagt verzweifle ich an Aussagen wie:
- So oft wie möglich static verwenden und final bei Variablen wenn es geht (Weltanschauung von OOP *bum*)
- Keine floats oder doubles verwenden und wenn dann nur doubles (Gibts eine Alternative???)
- Keine Methoden aufrufen (OOP? :eek:)
- Variablen immer public
- Keine Objekte zur Laufzeit erstellen oder zerstören
Naja aber bis jetzt spüre ich noch nichts von den angeschriebenen "3mal langsamer" etc...

Um aber auf den Punkt zu kommen: Marco deine Glaskugel macht mir mehr und mehr Angst. Mit der hast du schon öfters meine Posts beantwortet und Sachen beantwortet oder erahnt die ich nie erwähnt hatte. :)
 

Marco13

Top Contributor
Achso ok, also ich hatte 20 000 000 mal die oben aufgeführte Rechnung ausgeführt und danach nochmal 40 000 000 mal aber mit Zeitmessung. Der Durchschnitt von 4 Messdurchgängen ergab fast immer exakt 300, deshalb hoffte ich auf eine relativ genaue Aussage.

Das ist was anderes. Mit solchen Tests kann man schon die ungefähre Zeit messen - ich dachte, du meintest tatsächlich sowas wie
Java:
long before = System.nanoTime();
double s = Math.sqrt(42.0);
long after = System.nanoTime();
System.out.println("Duration "+(after-before));
was natürlich Unfug wäre. Aber auch bei solchen Tests mit vielen Durchläufen (wie bei allen Microbenchmarks) gibt es viele, viele Dinge, die man berücksichtigen muss, und die das Ergebnis verfälschen könnten. Im Zweifelsfall sollte man solche Messungen nur als "Richtwert" ansehen (wobei die Information "Wurzelziehen ist teuer" keines solchen Benchmarks bedürfen sollte ;) )


Da ich tatsächlich vorhabe, es später auch für Android umzuwandeln, habe ich mir eine offizielle Liste durchgelesen und angeschaut was alles merkbare Performanceänderungen herbeiführt.
Und ehrlich gesagt verzweifle ich an Aussagen wie:
- So oft wie möglich static verwenden und final bei Variablen wenn es geht (Weltanschauung von OOP *bum*)
- Keine floats oder doubles verwenden und wenn dann nur doubles (Gibts eine Alternative???)
- Keine Methoden aufrufen (OOP? :eek:)
- Variablen immer public
- Keine Objekte zur Laufzeit erstellen oder zerstören

Ja, ich hatte mir damals Google I/O 2009 - Writing Real-Time Games for Android - YouTube angesehen und fand das sehr interessant. Viele der Punkte, die du aufgelistet hast, werden dort auch erwähnt, und einem Abstraktions- und Flexibilitäts-OO-Junkie läuft's da echt kalt den Rücken runter :shock:
(Das mit den doubles, die besser sein sollen als floats, kommt mir aber komisch vor ???:L )

Ich glaube, da ist es wirklich wichtig, sich die zeitkritischen Teile rauszusuchen - also diese Aussagen nur auf den Game-Loop und die darin behandelten Objekte zu beziehen, und zu versuchen, diese Anforderungen mit einem Hauch von Flexibilität in Einklang zu bringen.

Andererseits: Es ist zwar ungewohnt, aber ... ein Android-Game ist auch eine ganz andere Kategorie von Software, als die, für die die üblichen Regeln gemacht wurden. Warum überall Interfaces mit Methoden und private Fields? Ja, weil man nie weiß, was noch für Anforderungen kommen, und die Software auch in 10 Jahren noch von anderen Personen nachvollzogen und gewartet werden können soll. Aber bei einem 1-Personen-Projekt wie einem Mini-Game, das irgendwann einfach "fertig" ist und rausgehauen und NIE mehr verändert wird, und dessen Halbwertszeit im Hinblick auf die rasanten Entwicklungen bei Smartphones vermutlich schon während der Designphase abgelaufen ist ;) ist es eigentlich egal, wenn man nicht
Java:
interface AbstractInGameItem 
{
    OperationResponse<T> executeOperation(GenericOperationDescriptor<T> op);
}
sondern ein pragmatisches
Java:
class Player 
{
    public int xPosition;
    public int yPosition;
}
hinschreibt. Die Prioritäten sind eben andere.
 

Ähnliche Java Themen


Oben