#1 05.08.2006 10:10:24

Dreamworld
UltraMember
Ort: Karlsruhe
Registriert: 06.12.2005
Beiträge: 368

RotationY

Hi, ich möchte mir gerne eine Funktion schreiben, die eine gegebene Matrix eines Objektes und einen Zielpunkt aufnimmt und daraus die Blickrichtung des Objektes berechnet.

Also so weit war ich, aber das klappt irgendwie nicht, Arccos kommt nur schrott raus...bzw gar nix (NA)

Die Matrix ist in der Klasse integriert, deswegen nicht übergeben.

Code: delphi

procedure txbasicmesh.lookatpoint(ziel:td3dxvector3);
var x_,y_,z_:single;
     m,m1:td3dxmatrix;
     cross,richtung:td3dxvector3;
     winkel,skalar:single;
begin
x_:=matrix._41;
y_:=matrix._42;
z_:=matrix._43;

//Richtungsvektor berechnet sich aus den Zielkoordinaten und der momentanen Position
d3dxvec3normalize(richtung, d3dxvector3(ziel.x-matrix._41, ziel.y-matrix._42, ziel.z-matrix._41));

//Winkel zwischen alter Richtung (Dir) und Ziel-Richtung berechnen über Skalarprodukt
skalar:=d3dxvec3dot(richtung, dir);

//Weil die länge 1 ist, berechnet sich der Winkel aus cos@=skalar richtung*dir

//Orientierung checken mit Kreutzprodukt
d3dxvec3cross(cross, richtung, dir);
//if cross.y>0 then
winkel:= arccos(skalar); //else Winkel:=-1*arcCos(3.14);
//Hinweis: hab das mal ausgeklammert, sollte jedoch in eine Richtung gehen

//Transformation zum 0-Punkt
d3dxmatrixtranslation(m1,0,0,0);

//Rotation in Richtung des Ziels (Richtung)
d3dxmatrixrotationy(m,winkel);    //Muss ich da Bogenmaß übergeben?
d3dxmatrixmultiply(m,m1,m);

d3dxmatrixmultiply(matrix,m,matrix);
matrix._41:=x_;
matrix._42:=y_;
matrix._43:=z_;
dir:=richtung;

end;



Gibts da geschicktere Möglichkeiten?

Vielleicht zum Hintergrund...ich will mein X-File einen Normalen und einen Frontvektor geben. Da sich die X-Files auf ein Ziel zubewegen, müssen sie auch da hin schaun.

Des weiteren wäre die Frage, ob ich das "abrunden" kann, also dass der Winkel nicht ruckartig gewechselt wird.

Offline

 

#2 05.08.2006 11:00:33

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: RotationY

Wenn es dir nur um die neue Matrix geht vergiss den Winkel und schau dir die Methode http://www.delphidev.de/phpBB2/viewtopic.php?t=69 an. Die macht genau das, nur ohne Winkel wink

Also sofern sich die beiden Richtungen nicht zu sehr (max 45 Grad oder so) unterscheiden kannst du einfach zwischen beiden Vektoren linear interpolieren. Allerdings sieht das um so blöder aus je mehr die Richtung abweicht. Sind beide Vektoren fast entgegengesetzt kommt sogar ein Nullvektor als Richtung raus, numerisch instabil  und ggf. sogar Division durch Null.

Eine andere Möglichkeit sind Quaternions. Damit müsste sowas ziemlich genial zum implementieren sein, allerdings ist die Mathematik recht heftig, jedenfalls blicke ich da nicht durch. Hab mich aber auch nicht wirklich damit beschäftigt.

Die letzte Möglichkeit sind natürlich die Winkel. Hier müsstest du nur den alten Winkel langsam an den neuen anpassen, also zwischen den Winkeln interpolieren. Sofern das ganze nur 2D ist, geht das ganz leicht:
Definiere dir z.B. den Vektor (1, 0, 0) als Nullwinkel. Dieser Vektor entspricht "Vorne" bei deinen Objekten wenn sie nicht gedreht sind. Alle anderen Winkel berechnest du relativ zu diesem über das Dot-Produkt, hast du ja auch schon gemacht. Hast du beide Winkel interpolierst du zwischen beiden:

winkelInter := alpha * winkelNeu + (1-alpha) * winkelAlt;

Dabei bekommst du bei alpha := 0 den alten Winkel, bei alpha := 1 den neuen, und bei Werten dazwsichen einen Winkel dazwischen.

Über D3DXMatrixRotationY bekommst du direkt die neue Matrix. (entsprechend RotationX oder Z wenn Y nicht "oben" ist)
Hier musst du nur noch die Position setzen:
matrix._41:=x_;
matrix._42:=y_;
matrix._43:=z_;

Coolcat


My software never has bugs. It just develops random features.

Offline

 

#3 05.08.2006 11:16:04

Dreamworld
UltraMember
Ort: Karlsruhe
Registriert: 06.12.2005
Beiträge: 368

Re: RotationY

Eine Sache würde ich noch gerne wissen...
D3DXMatrixRotationY muss ich den Winkel ja in Radians angeben.
Vor allem wie ich den Winkel aus dem Dot-Produkt bekomme (eigentlich über Arccos) is mein Problem. Das funxt nicht bei mir. Mach ich da was falsch?

Es ist doch cos@=a dot b, wenn der Betrag der Vektoren a und b jeweils 1 ist, oder? Das heißt ich hab ja den cosinus und will den Winkel, also arccos...genau das geht nicht. Warum?

edit: Hmm Dir war wohl nicht normalisiert

Offline

 

#4 05.08.2006 13:45:28

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: RotationY

Zitat:

edit: Hmm Dir war wohl nicht normalisiert

D.h. alles funzt?

Zitat:

Es ist doch cos@=a dot b, wenn der Betrag der Vektoren a und b jeweils 1 ist, oder?

jop

Alle Funktionen die irgendwie mit Winkeln hantieren kriegen normalerweise immer Bogenmaß, also einen Wert zwsichen 0 und 2*Pi

Coolcat


My software never has bugs. It just develops random features.

Offline

 

#5 05.08.2006 14:31:26

Dreamworld
UltraMember
Ort: Karlsruhe
Registriert: 06.12.2005
Beiträge: 368

Re: RotationY

jo es funxt soweit, muss meinen statiuschen xfile loader überarbeiten, da kommen massig fehlermeldungen die keinen sinn machen...jedenfalls für mich  :mrgreen:

das mit der "Abrundung" des ganzen mach ich später...

Offline

 

#6 15.08.2006 14:11:38

Dreamworld
UltraMember
Ort: Karlsruhe
Registriert: 06.12.2005
Beiträge: 368

Re: RotationY

Also irgendwie stimmt da was nicht.
Das erste mal, wenn ich mein Modell wo hinschicke, ist alles wunderbar, danach gehts nimmer. Denke hat irgendwas mit den Vektoren/Winkeln zu tun, die ich am Schluss übergebe, aber ich find den Fehler einfach nicht.
Vielleicht kann mir wer helfen...

Die Funtion Interpolate wird jede Renderschleife aufgerufen, Lookatpoint nur, wenn ein Mesh via Maus wo anders hingeschickt wird.

Code: delphi

procedure txbasicmesh.lookatpoint(ziel:td3dxvector3);
var
    m,m1:td3dxmatrix;
    cross,richtung:td3dxvector3;
    skalar:single;
    winkel:single;
begin
if alpha=1 then alpha:=0;
  x_:=matrix._41;
  y_:=matrix._42;
  z_:=matrix._43;

//Richtungsvektor berechnet sich aus den Zielkoordinaten und der momentanen Position
richtung:=d3dxvector3(ziel.x-x_,0,ziel.z-z_);

dir.y:=0;

d3dxvec3normalize(richtung, richtung);
d3dxvec3normalize(dir, dir);

//Winkel zwischen alter Richtung (Dir) und Ziel-Richtung berechnen über Skalarprodukt
skalar:=d3dxvec3dot(richtung, dir);
//Weil die länge 1 ist, berechnet sich der Winkel aus cos@=skalar richtung*dir
//Orientierung checken mit Kreutzprodukt
d3dxvec3cross(cross, richtung, dir);

if cross.y<0 then
winkel:= +arccos(skalar) else winkel:= -1*arccos(skalar);


stopwinkel:=winkel;

stopdir:=richtung;

dreht:=true;    //anstoßen
end;


function txbasicmesh.interpolate:boolean;
var winkelinter:single;
    mat,mat1:td3dxmatrix;
    _x,_y,_z:single;
begin
if dreht=false then exit;

winkelinter := alpha * stopwinkel + (1-alpha) * startwinkel;

_x:=matrix._41;
_y:=matrix._42;
_z:=matrix._43;

d3dxmatrixtranslation(mat, 0,0,0);
d3dxmatrixrotationy(mat1,winkelinter);
d3dxmatrixmultiply(mat, mat, mat1);

matrix:=mat;

matrix._41:=_x;
matrix._42:=_y;
matrix._43:=_z;

alpha:=alpha+0.01;
if alpha>=1 then
begin
  startwinkel:=stopwinkel;
  dir:=stopdir;
  d3dxvec3normalize(dir,dir);
  dreht:=false;
  alpha:=1;
end;
end;

Offline

 

#7 15.08.2006 15:37:01

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: RotationY

Code: delphi

if alpha=1 then alpha:=0; 


Musst du alpha nicht wieder auf 0 setzen auch wenn alpha größer 1 ist?
Also:

Code: delphi

if (alpha >= 1) then alpha:=0; 



Ansonsten vielleicht der Hinweis:

Code: delphi

_x:=matrix._41;
_y:=matrix._42;
_z:=matrix._43;
d3dxmatrixrotationy(matrix,winkelinter);
matrix._41:=_x;
matrix._42:=_y;
matrix._43:=_z; 


Ist was schneller wink

Coolcat


My software never has bugs. It just develops random features.

Offline

 

#8 15.08.2006 16:45:52

Dreamworld
UltraMember
Ort: Karlsruhe
Registriert: 06.12.2005
Beiträge: 368

Re: RotationY

das wars leider nicht
*schluchts*

Die Theorie is so einfach und ich find den Fehler nicht -.-

Also nochmal..beim ersten mal stimmt's, dann sind die Winkel völlig falsch...irgendwie übergeb ich was falsches, aber was?

Offline

 

#9 15.08.2006 17:09:40

Dreamworld
UltraMember
Ort: Karlsruhe
Registriert: 06.12.2005
Beiträge: 368

Re: RotationY

i hob's!  :mrgreen:

Die Zeile war das Verderben:

Code: delphi

stopwinkel:=winkel;



das muss


StopWinkel:=StopWinkel+Winkel;

Offline

 

#10 15.08.2006 17:19:40

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: RotationY

Dein Programmierstil ist aber für außenstehende auch nicht gerade lesefreundlich. Zum beispiel die Sache mit "Richtung" und "dir". Warum nicht "oldDir" und "newDir", oder sowas? Da sind noch mehr so Sachen.
Zudem weiß ich nicht was in der Klasse TXBasicMesh noch so alles passiert. Du greifst halt irgendwo auf diese Attribute zu...

Naja, was mir auffällt ist, das es Probleme geben könnte wenn du eine neue Richtung setzt obwohl die Drehung noch nicht abgeschlossen ist. In LookAtPoint muss auch der Startwinkel gesetzt werden. Du solltest vielleicht irgendwo den tatsächlichen aktuellen Winkel mitführen.
Desweiteren gibt es Problem beim drehen von einem sehr kleinen Winkel (-Pi) zu einem großen Winkel (+Pi): Anstatt dem "kurzen" Weg wird genau andersrum gedreht.
Außerdem ist deine Drehung nicht immer gleich schnell. Also bei dir ist die Drehung immer nach exakt der Zeit t abgeschlossen. Stattdessen vielleicht lieber x Grad pro Zeit t drehen?

Coolcat


My software never has bugs. It just develops random features.

Offline

 

#11 15.08.2006 17:29:42

Dreamworld
UltraMember
Ort: Karlsruhe
Registriert: 06.12.2005
Beiträge: 368

Re: RotationY

Zitat:

Dein Programmierstil ist aber für außenstehende auch nicht gerade lesefreundlich.

Jups das stimmt, aber ich lebe von Kommentaren. Wenn ich was fertig hab, kommentier ich erstmal die Prozeduren/funktionen aus, damit ich später damit zurechtkomme.

Zitat:

Zum beispiel die Sache mit "Richtung" und "dir". Warum nicht "oldDir" und "newDir", oder sowas?

Jo aber du wirst auch unten sehn, dass ich StopDir und StartDir eingeführt habe, hab nur vergessen da oben zu ändern.

Zitat:


Da sind noch mehr so Sachen.
Zudem weiß ich nicht was in der Klasse TXBasicMesh noch so alles passiert. Du greifst halt irgendwo auf diese Attribute zu...

Das war unerheblich für meine Frage, es hat ja, wie ich schrieb funktioniert, nur die Interpolation nicht.

Zum rest geb ich dir recht, das hab ich noch nicht bedacht, danke!

Ok alles drin, geht super, danke nochmal für die Hinweise.  :thx:

Offline

 

Brett Fußzeile

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson