# Ball is Kaputt



## suelman (20. Jan 2009)

Hi, 
Kleines Rotationsproblem:


Bewegung in 2 Richtungen:
X und Z.
Geschwindigkeit speedX/speedZ

Ball rollt im begrenzten Spielfeld. 
Sprich:
 Wenn posZ>zMax speedZ*=-1;
 ...

Für die Rotation des Balls im 3dRaum in etwa:

speed = Math.sqrt(speedX*speedX+speedZ*speedZ);

angle = Math.atan2(speedZ, speedX)

//rotation:
gl.gl_Rotatef(gesRotation+=speed, Math.cos(angle),0,-Math.sin(angle));

So, der ganze Schmu haut auch soweit hin. Der Ball rollt wunderbar übers Spielfeld.
ABER:
jedesmal wenn er an der Spielbegrenzung abprallt, sprich
speedZ*=-1;
oder 
speedX*=-1;

haut das für einen Frame mit der Rotation nicht mehr hin. Ist ganz logisch, weil sich die Drehrichtung hart ändert.
Bsp: nehmen wir an 
speedX sei 0;
speedZ = 1;
gesRotaion ist 90;

nun ändert speedZ sein Vorzeichen.

Damit die Rotation noch passt muss 

gl.gl_RotateF(90,0,0,1)

nach dem Vorzeichenwechsel zu

gl.gl_RotateF(270,0,0,-1)

werden. 


Überseh ich da irgendwas oder muss ich das Problem anders angehen ?


----------



## Marco13 (21. Jan 2009)

???:L Beschreib' mal etwas genauer, wie dieser ... ... ... Zusammenhang zwischen Geschwindigkeit und Rotation .... ... ... zustande kommt....


----------



## suelman (21. Jan 2009)

Marco13 hat gesagt.:
			
		

> ???:L Beschreib' mal etwas genauer, wie dieser ... ... ... Zusammenhang zwischen Geschwindigkeit und Rotation .... ... ... zustande kommt....



also der Rotationswinkel (Gesmatwinkel) wird durch gesRotation+=speed gegeben

vlg( gl.gl_Rotatef(gesRotation+=speed, Math.cos(angle),0,-Math.sin(angle)); )

die nächsten drei Parameter geben die Rotation in x,y,z richtung (bei mir ist x und z ausreichend).
Diese liegen immer zwischen -1 und 1.

Und wie gesagt. das rollen funktioniert. Nur bei einem Richtungswechsel n.B. z wird zu -z springt er ja quasie um 
gesRotation in die entgegengesetzte richtung. Und genau da hauts nicht hin. Sprich bei einem Vorzeichenwechsel von z müsste er auch -gesRotation machen. aber So einfach ists ja nicht, weil ich ja anteilig auch noch in x richtung drehe. 
Das rollen selber in die entgegengesetzte richtung ist auch richtig.

axo. und die Rotation geht fortlaufen. Sprich wenn 360 grad überschritten ists so als fängt gl.gl_Rotatef wieder bei 0 an ...


----------



## Spacerat (22. Jan 2009)

Hmm...

Das mus kein Rechenfehler sein. Das liegt glaube ich an GL. Transformations-Befehle wirken additiv auf die aktuelle Matrix. Möglicherweise fehlt hier, da und dort nur ein gl_loadIdentity(). Im Zweifelsfalle sollte man dann auch mit gl_pushMatrix() und gl_popMatrix() arbeiten. Hat lange gedauert, bis ich das auf der Reihe hatte.

Allerdings, wenn daran gedacht wurde, bräuchte ich mal einblick in etwas vorhandenen Code.

mfg Spacerat


----------



## Marco13 (22. Jan 2009)

So ganz hab' ichs immernoch nicht kapiert: Du hast eine Rollrichtung auf einer Ebene. Der Ball rollt über die Ebene und dreht sich dabei, wobei die Drehachse senkrecht auf der Rollrichtung (und parallel zur Rollebene) liegt. Wenn der Ball abprallen soll, muss man sich genau überlegen (oder darüber philosophieren) wie die Drehachse danach sein soll - im Zweifelsfall wieder senkrecht zur (neuen) Rollrichtung - das komplizierte ist vmtl. der richtige (stetige) Übergang zwischen diesen Richtungen - meintest du das?


----------



## suelman (22. Jan 2009)

Marco13 hat gesagt.:
			
		

> ...- im Zweifelsfall wieder senkrecht zur (neuen) Rollrichtung - das komplizierte ist vmtl. der richtige (stetige) Übergang zwischen diesen Richtungen - meintest du das?



Marco, du formulierst immer so dass man es versteht. Das ist genau was ich meine. Nur ebend nicht senkrecht, das braucht nicht umbedingt, da es für mich reicht, wenn der ball normal rollt. Die drehrichtung ist anteilig aufgeteilt in x und z richtung (y richtung ist quasi vertikal, x und z horizontal und ebend in die ebene hinein). Definiert durch >>Math.cos(angle),0,-Math.sin(angle) 
Das Problem liegt genau in den Übergängen der Drehrichtung. 

dreht man z.B. nur in z richtung könnte man das einfach lösen indem man mit
gl.gl_Rotatef(-gesRotation+=speed, Math.cos(angle),0,-Math.sin(angle));
statt
>>gl.gl_Rotatef(gesRotation+=speed, Math.cos(angle),0,-Math.sin(angle)); rotieren würde, aber da schlägt die anteilige drehung der x achse sofern nicht gilt: z=1 und x=0 bzw z=-1 und x= 0, böse mit.

@Spacerat 
Also die schilderung des Problems mit meinem pseudocode sollte eigentlich reichen um das Problem zu diskutieren. Das mit dem Load Identity / Push und Pop hab ich mitlerweile eigentlich ganz gut verstanden meine ich, aber wenns dir(und damit ev auch mir) hilft ...


```
gl.glLoadIdentity();
//...
gl.glPushMatrix();

//translate to x,y,z position
gl.glTranslatef(pos.x, pos.y, pos.z);
//Rotate ball (tan b = Ankatete / Gegenkatete)
if(rotX==0){
	angle = 0;
}else{
	angle = (float)Math.atan2(rotZ, rotX);
}
rotationSpeed = (float) Math.sqrt((rotX*rotX)+(rotZ*rotZ));
rotationX-=rotationSpeed*Globals.BALL_SPEED_MULTIPLICATOR;
gl.glRotatef(rotationX, -(float)Math.sin(angle), 0, (float)Math.cos(angle));
//set Material
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, Materials.Ball_ambient,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, Materials.Ball_diffuse,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, Materials.Ball_specular,0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_EMISSION, Materials.Ball_emissiv,0);
gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, Materials.Ball_shininess);
//enable and set textures
gl.glEnable(GL.GL_NORMALIZE);
gl.glActiveTexture(GL.GL_TEXTURE0);
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glBindTexture(GL.GL_TEXTURE_2D,texture0);
gl.glUniform1iARB(gl.glGetUniformLocationARB(prog.m_programObject, "texture0"), 0);
gl.glActiveTexture(GL.GL_TEXTURE1);
gl.glBindTexture(GL.GL_TEXTURE_2D, bumpMap);
gl.glUniform1iARB(gl.glGetUniformLocationARB(prog.m_programObject, "texture1"), 1);

gl.glCallList(list);
gl.glPopMatrix();
gl.glActiveTexture(GL.GL_TEXTURE0);
gl.glDisable(GL.GL_TEXTURE_2D);
gl.glActiveTexture(GL.GL_TEXTURE1);
gl.glDisable(GL.GL_TEXTURE_2D);
[!code]
```


----------



## Marco13 (22. Jan 2009)

Hm... das könnte ein bißchen fummelig werden - zumindest fällt mir spontan keine schöne "Fingerschnipp-Zauberlösung" ein... ein erster Ansatz wäre, die Rotation des Balles nicht nur als einen float-Wert zu speichern, sondern ... hm  ???:L (ja, ganz brutal erstmal, um den Ansatz zu verdeutlichen: ) als komplette Matrix. Die Matrix wird dann bei jedem Dreh-Schritt (also überall da, wo du im Moment 
rotationX-=rotationSpeed*Globals.BALL_SPEED_MULTIPLICATOR; 
machst) mit einer Matrix multipliziert, die nur das Delta beschreibt - also sowas wie

```
float angleDelta = rotationSpeed*Globals.BALL_SPEED_MULTIPLICATOR;
Vector currentAxis = new Vector(-(float)Math.sin(angle), 0, (float)Math.cos(angle));
Matrix rotationDelta = new Matrix(currentVector, angleDelta);
currentRotation.multiplyWith(rotationDelta);
gl.glMultMatrix(currentRotation);
```
Das ist natürlich in gewisser Hinsicht die Holzhammer-Methode, aber müßte zum Testen _relativ_ leicht zu implementieren sein, und wenn's dann hübsch aussieht, kann man überlegen, ob man's noch schöner, "sauberer" und effizienter hinkriegt...


----------



## suelman (22. Jan 2009)

Ah, das sieht allerdings recht gut aus. das könnte klappen. Werds leider erst Sonntag/spätestestens Montag versuchen können. Aber auf den ersten Blick würd ich sagen der Ansatz sieht sehr gut aus. Wobei ich mal schnell dazwischen schieben möchte, so auf den ersten Blick und als Verständnisfrage:

mit 

```
Matrix rotationDelta = new Matrix(currentVector, angleDelta);
```


meinst du doch bestimmt

```
Matrix rotationDelta = new Matrix(currentAxis, angleDelta);
```
oder wo kommt der currentVector auf mal her ?

MFG und danke !!! (vorerst  ich werd auf jeden noch posten obs dann geklappt hat)


----------



## Marco13 (22. Jan 2009)

Natürlich - das ist ja alles Pseudocode, nur um die Idee zu verdeutlichen. (Btw: Mit sowas wie https://vecmath.dev.java.net/ werden solche Matrix- und Vektor-hantierereien u.U. deutlich einfacher)


----------



## Spacerat (23. Jan 2009)

Möglicherweise hilft dann das ja...

```
gl.glRotatef(rotationX, -(float) Math.sin(angle), 0, 0);
gl.glRotatef(rotationZ, 0, 0, (float)Math.cos(angle));
```
Natürlich muß "rotationZ" dafür noch berechnet werden (ggf. "=-rotationX"). Zumindest werden die Achsen damit unabhängig voneinander rotiert. Bevor du aber mit diesen Matrix und Vector-Klassen losrennst (immer diese Overheads frisst Speicher und Performance), schau dir noch mal an welche Möglichkeiten JOGL (ist doch JOGL oder? ...sieht jedenfalls danach aus) dafür bietet. Ich rede da gerade von "LoadMatrix" und GetMatrix. Damit kann man diese Berechnungen auf Basis von Primitivtypen durchführen.

mfg Spacerat


----------



## Marco13 (23. Jan 2009)

Das wäre natürlich eine einfachere Lösung. Meistens ist es so: Für jedes Problem gibt es eine Lösung, die einfach, elegant... und falsch ist. Ich müßte mich da jetzt auch erstmal mit Bleistift und Papier hinsetzen, um mit Sicherheit sagen zu können, dass das so nicht funktioniert, aber ich "glaube", dass es nicht funktioniert: Die Drehachsen ändern sich ja, und im Moment des Abprallens befindet sich der Ball in einer bestimmten "Konfiguration", die man mit zwei Euler-Winkeln nicht unbedingt beschreiben kann, und die als "Ausgangslage" für alle weiteren Drehungen dienen muss. Aber der TO kann es natürlich auch auf die einfache Variante versuchen


----------



## Guest (25. Jan 2009)

Spacerat hat gesagt.:
			
		

> Möglicherweise hilft dann das ja...
> 
> ```
> gl.glRotatef(rotationX, -(float) Math.sin(angle), 0, 0);
> ...



Also das hab ich schon probiert gehabt.

und wegen 



			
				Spacerat hat gesagt.:
			
		

> ...Natürlich muß "rotationZ" dafür noch berechnet werden


ja das muss anders berechnet werden. es spielt da ja sogar eine rolle in welcher reihenfolge rotiert wird. Zudem ist 'mein' Problem damit ja noch nicht aus der Welt. Zudem muss bei dem 'Spacerat' Ansatz auch noch um die Y-Achse rotiert werden, weil nach der Rotation um die X-Achse sich die Z-Achse Verschoben hat.

Ich werd mir da lieber erstmal ersteren Ansatz zur Brust nehmen, der hat mehr Perspektive. Dazu muss ich ja lediglich die Positionstransformation immer relativ abhängig zu der Vorherigen Position berechnen, ansonsten hab ich kaum Änderungen an der Formel. Und das bischen Performance was verlohren geht ist nebensächlich. (Jedenfalls für mein kleines Spielchen). ...


----------



## suelman (25. Jan 2009)

Also, jetzt wo ich es implementiert und das verhalten gesehen hab, erscheint es offensichtlicht. 
Marco13, der Ansatz ist ursprünglich gut, aber:
Das kann natürlich auch nicht gehen. Quasie das selbe fenomen was ich darüber bei spacerat beschreiben hab. Sobald ich die alte Matrix nehme, (also nach der letzten teildrehung) haben sich die Drehachsen schon ein stück verändert. Die Anschließende Drehung muss dann natürlich auch relativ dazu mit angepassten drehachsen sein. Womit sich der ball mit einem einfachen 

```
gl.glRotatef(-rotationSpeed*Globals.BALL_SPEED_MULTIPLICATOR, (float)Math.cos(angle), 0, (float)Math.sin(angle));
```
natürlich wild in alle richtungen dreht.
Ich wette man kann mein problem viel einfacher lösen als die Verschiebung der Drehachsen zu bestimmen. Wir kommen nur nicht drauf. 

(Lautes Verdammtgerufe)


----------



## Marco13 (25. Jan 2009)

Ich tippe mal darauf, dass es auch mit der Reihenfolge der Multiplikationen zu tun hat. Kannst du ein FERTIG COMPILIERBARES!!! Beispielprogramm posten?


----------



## suelman (27. Jan 2009)

Marco13 hat gesagt.:
			
		

> Ich tippe mal darauf, dass es auch mit der Reihenfolge der Multiplikationen zu tun hat.


ich eher weniger, weil das eigentliche rollen auf der ebene Funktioniert



			
				Marco13 hat gesagt.:
			
		

> Kannst du ein FERTIG COMPILIERBARES!!! Beispielprogramm posten?



Ich wüsste nicht wie/hab kein onlinespeicher zur Verfügung


----------



## Ebenius (27. Jan 2009)

suelman hat gesagt.:
			
		

> Marco13 hat gesagt.:
> 
> 
> 
> ...


Du hast doch Eigene Dateien... Als ZIP packen, hochladen, rechtsklick auf den Link, Link posten.


----------



## suelman (28. Jan 2009)

Jaaaa, das problem ist aber dass da was von max 512 kB steht. Das reicht nicht annähernd und das so abzuspecken dass ich das ich das auf 512kb bekomme ist mehr arbeit als das neu zu schreiben, und bevor ich mich daran setze kann ich mich besser an die lösung des problems machen ...


----------



## suelman (28. Jan 2009)

Marco, du hattest recht, war doch "mehr oder weniger" n reihenfolgefehler drin nachdem ich mich an deinen Ansatz gemacht hab. aber nu läufts 
hier der code (falls es noch interessiert)


```
gl.glPushMatrix();
		//translate to x,y,z position
		gl.glTranslatef(pos.x, pos.y, pos.z);
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, transform_matrix, 0);
		//Rotate ball (tan b = Ankatete / Gegenkatete)
		angle = (float)Math.atan2(rotZ, rotX);
		rotation = (float) Math.sqrt((rotX*rotX)+(rotZ*rotZ))*Globals.BALL_SPEED_MULTIPLICATOR;
		// no Transformation bevor rotation so start from the identity
		gl.glLoadIdentity();
		gl.glRotatef(-rotation, -(float)Math.sin(angle), 0, (float)Math.cos(angle));
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, matrix, 0);
		//multiply last new Rotation with last rotation
		gl.glLoadMatrixf(matrix, 0);
		gl.glMultMatrixf(old_matrix, 0);
		//multiply transformation and rotation
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, old_matrix, 0);
		gl.glLoadMatrixf(transform_matrix, 0);
		gl.glMultMatrixf(old_matrix, 0);
		//set materials and paint...
```

Nochmals danke für eure bemühungen !!


----------

