XYZ->Sferisch->XYZ coordinaten

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Voor een prototype probeer ik mannetjes rond te laten lopen op een bol. Voor dit soort logica is het het makkelijkste voor mij om sferische coordinaten te gebruiken, maar voor het renderen en picking e.d. heb ik juist XYZ (cartesische) coordinaten nodig.

De bol heeft een radius van 1 en een origin van (0,0,0)

Ik heb het volgende stelsel gebruikt:
Het neutrale punt is (1,0,0)
Sy (of pitch) geeft de hoogte op de bol aan en loopt van pi/2 (top) naar 0 (evenaar) naar -pi/2 (bottom)
Sx (of yaw) geeft de rotatie rond de evenaar van de bol aan en loopt van 0 (rechts) naar pi (links) naar 2*pi (weer rechts).

Dit werkt prima, maar nu heb ik weer cartesische coordinaten nodig, daarom bedacht ik het volgende:
-Neem een vector wijzend naar het neutrale punt (1,0,0).
-Roteer deze rond de z-as (pitch)
-En daarna rond de y-as (yaw)

Ik dacht dat ik nu het goede punt in cartesische coordinaten zou hebben. En deze methode klopt ongeveer, maar het z-coordinaat heeft het verkeerde teken (raar, ik kan maar niet beredeneren waarom, maar in het vlak waar yaw in [0,pi] geld wordt deze negatief :/ ) en rond de evenaar (pitch=0) kloppen de punten perfect. Ook vanaf de voorkant (yaw=0) is er geen probleem, maar zodra pitch groter wordt terwijl yaw niet nul is lijkt er van de x en z coordinaten niets meer te kloppen.

Nu heb ik de rotaties van de vector al omgekeer maar dan komt er alleen maar onzin uit, dus ik maak een andere logisch fout, maar wat doe ik verkeerd?!

Hier zijn de twee schuldige functies

(Ik gebruik het XNA framework, waar Matrix en Vector3 en hun functies al in zitten, daar zit hoogstwaarschijnlijk niet de fout)

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public static Position ToSpherical(Vector3 position)
        {            
            float sx;
            float sy;

            //Sy in [-pi/2,pi/2) pi/2 meaning top, -pi/2 meaning bottom
            //Sx in [0,2*pi) 0 meaning (1,0,0), pi meaning (-1,0,0)

            if (position.Z >= 0)
            {
                sx = (float)Math.Acos(Vector3.Dot(position, Vector3.Right));
            }
            else
            {
                sx = MathHelper.TwoPi - (float)Math.Acos(Vector3.Dot(position, Vector3.Right));
            }

            sy = (float)Math.Asin(Vector3.Dot(position, Vector3.Up));
            return new Position(sx, sy);
        }

        public static Vector3 ToVector3(Position pos, float sphereRadius)
        {            
            float yaw = pos.Sx;
            float pitch = pos.Sy;

            Vector3 v = new Vector3(1, 0, 0);
            
            v = Vector3.Transform(v, Matrix.CreateRotationZ(pitch));
            v = Vector3.Transform(v, Matrix.CreateRotationY(yaw));
                                                
            return Vector3.Normalize(v) * sphereRadius;
        }

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
(Update/fix dus maar even als nieuwe post).

Na wat rondvragen bleek dat Spinor in #XNA (op effnet) al sferische mapping code had:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 public Vector3 SphericalToCartesian(Vector3 pos)
        {
            float radius = pos.X;
            float inclination = pos.Y;
            float azimuth = pos.Z;

            float x = (float)(radius * Math.Sin(inclination) * Math.Cos(azimuth));
            float y = (float)(radius * Math.Cos(inclination));
            float z = (float)(radius * Math.Sin(inclination) * Math.Sin(azimuth));
            return new Vector3(x, y, z);
        }

        public Vector3 CartesianToSpherical(Vector3 pos)
        {
            float radius = pos.Length();
            float inclination = (float)Math.Acos(pos.Y / radius);
            float azimuth = (float)Math.Atan2(pos.Z, pos.X);
            return new Vector3(radius, inclination, azimuth);
        }


Deze code gebruikt de volgende mapping (die prima is voor wat ik nodig heb)
Inclination van 0~pi (0 = top, pi = bottom)
Azimuth van -pi~pi (0 = rechts, pi - epsilon is links voorkant, -pi - epsilon = links achterkant).

Waarom mijn bovenstaande code niet werkt is me nog steeds onduidelijk, en daar zou ik graag over verder discussieren, maar het probleem zelf is in iedergeval opgelost.

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
Misschien helpt het als je de vectoren visualiseert. Ik vermoed dat het te maken heeft met het feit dat door een rotatie om Z ( azimuth ) de rotatieas voor de inclination verandert, en dus niet meer een simpele rotatie om x of y is. Dat lijk je wel te willen doen nl.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
Weet niet of je hier veel aan hebt, maar vergeet niet om de hoeken binne [0,2pi] te houden. Heb het hier even uit de cameraclass van m'n 3D-progsel gehaald.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
// Houd alles in 0-2pi, zodat de berekening van upvector klopt
if(fabs(angleV) > tweepi)
    angleV = 0.0f;
if(fabs(angleH) > tweepi)
    angleH = 0.0f;

(...)

// Stel de upvector in
if(fabs(angleV) > halfpi && fabs(angleV) < anderhalfpi)
    vecCameraup.y = -1.0f;
else
    vecCameraup.y = 1.0f;


Dit houdt dus netjes de coordinaten binnen de grenzen. Als ik dit niet gebruik, crapt de camera in hetzelfde progsel helemaal uit (hier alleen de W-beweging):

C++:
1
2
3
4
5
6
7
case 'W': {
    vecCamerapos.x += 0.2f*cos(angleH)*cos(angleV);
    vecCamerapos.y += 0.2f*sin(angleV);
    vecCamerapos.z += 0.2f*sin(angleH)*cos(angleV);
    break;
}
(... andere knoppen ...)


Dit stukje is dus nodig om een camera door een wereld te laten bewegen. vecCamerapos is in World Space, waardoor we niet zomaar 'vooruit' kunnen bewegen als we op W klikken. Dan moet dus eerst met de hoek de uitwijking bepaald worden waarheen gewezen wordt. Daarmee wordt dan vecCameralookat berekend:

Hiermee worden dus azimuth en inclination (en een radius van 1) van Spherical naast cartesian omgezet met trig (geen matrices, ook al die doen in principe hetzelfde.

C++:
1
2
vecCameralookat = D3DXVECTOR3(vecCamerapos.x+cos(angleH)*cos(angleV),vecCamerapos.y+sin(angleV),vecCamerapos.z+sin(angleH)*cos(angleV));
vecCameradir = vecCameralookat - vecCamerapos;


En met lijntje trekken van vecCameralookat die precies 1 verder ligt dan de camera, in de richting van de angleV/angleH-berekening naar de cameraplek zelf levert dus de richtingvector op.

Hoop dat je er wat aan hebt.

Edit: Goed, ik doe dus na wat beter kijken exact hetzelfde als XNA doet. Stap twee: wat is er dan fout aan het eigen baksel.

Ah, ik zie het al denk ik. Je vergeet om de X-as te draaien. Hierdoor weet je niet welke kant de camera op wijst. Dat is de welbekende (?) upvector. Die moet uiteraard wel op (0,1,0) staan. Als deze bijvoorbeeld per ongeluk op (0,-1,0) staat, zal inderdaad de z negatief worden, omdat de camera ondersteboven staat. Dit wordt dus geregeld door dat kleine stukje code bovenin deze post.

Grote kans dat je het toch gewoon met trig moet doen.

[ Voor 25% gewijzigd door Orwell op 17-04-2011 13:25 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wat altijd zo irritant is aan zowel informatie hierover op het internet en topics als deze is dat niemand er even aan denkt uit te leggen hoe z'n assenstelsel in elkaar zit. Je z-as als pitch komt vrij weinig voor, meestal is het x (voor zowel y-up als z-up)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
@ orwell, volgens mij klopt dat niet, ik heb op dit moment geen boven nodig vermoed ik omdat duidelijk gedefineerd is welke kant ik op draai over de z-as (negatief is met de klok mee is naar boven). Ook waren mijn hoeken netjes tussen 0 en 2pi, maar volgens mij maakt dit ook niet uit (de cosinus en sinus functie kan het weinig schelen, en hieruit is de rotatie matrix ook gemaakt.


@Farlane, zover ik het me tot nu toe gevisualizeerd had lijkt me de z-as juist wel correct, ik begin met een vector die naar rechts wijst, draaien om de z-as maakt deze vector dus naar rechts boven kijken (of rechts onder). Daarna draai ik deze hele vector om de y-as.

Maar zowel jij als .Oisyn wijzen toch op die z-as transformatie, dus daar ga ik zeker naar kijken, hoe ik er op kwam om z te gebruiken? Ik zat met mijn hoofd te denken aan een plat liggende eenheidscirkel in het x-z vlak., met dus de neutral stand aan de rechterkant, daarom had ik z bedacht als pitch. (Ik gebruik y=up).

Anyway, ik zal de oude code nog even van Hg pullen en dan kijken of de X en Y as rotaties beter gaan als de Z-as rotaties.

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Het is een kwestie van conventie. Ik vind het altijd wel prettig om een vector bij een identity transform naar voren te laten wijzen, maar naar rechts is natuurlijk net zo goed mogelijk. Maar jij gebruikt dus z=forward met een linkshandig systeem, wat natuurlijk wel gebruikelijk is in D3D en waarschijnlijk dus ook XNA.

De reden waarom je z het verkeerde teken is is waarschijnlijk omdat de rotatie met de klok mee draait in de richting van de rotatie-as gezien, terwijl jij waarschijnlijk verwacht dat de rotatie tegen de klok in draait.

[ Voor 8% gewijzigd door .oisyn op 17-04-2011 22:11 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
LH systeem is idd wat D3D gebruikt, gek genoeg gebruikt XNA een RH systeem. Ik kwam hier achter toen ik een camera class van een C++ D3D naar XNA porte :S, gaf leuke problemen.

[ Voor 6% gewijzigd door NC83 op 18-04-2011 01:09 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Eigenlijk maakt dat voor het probleem niet uit. De rotaties worden weliswaar tegen de klok in, maar de z-as staat ook de andere kant op.

.edit: oh wacht, ik bedenk me nu dat het probleem in je z zat, en niet in je y. Maar welk assenstelsel je ook gebruikt, [1, 0, 0] 90 graden over de y-as geeft [0, 0, -1]

[ Voor 40% gewijzigd door .oisyn op 18-04-2011 02:47 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
NC83 schreef op maandag 18 april 2011 @ 01:07:
LH systeem is idd wat D3D gebruikt, gek genoeg gebruikt XNA een RH systeem. Ik kwam hier achter toen ik een camera class van een C++ D3D naar XNA porte :S, gaf leuke problemen.
Je bent in principe 100% vrij om LH of RH te kiezen in D3D, maar zo ongeveer 99% van de boeken en tutorials op internet gaan van LH uit. Jeps, hetzelfde effect als "D3D==LH", maar is er keuze in principe. ;)

Mrreh, de Z zit nu dus aan de rechterkant van de positieve X. In principe is het dus logisch dat als je positief horizontaal draait (yaw) , dat je dan linksaf gaat en dat Z negatief wordt.
.edit: oh wacht, ik bedenk me nu dat het probleem in je z zat, en niet in je y. Maar welk assenstelsel je ook gebruikt, [1, 0, 0] 90 graden over de y-as geeft [0, 0, -1]
Ik kan best fout zitten, maar als Y up is (volgens roy-t), is X vooruit. Neem eens je hand. Als je met je duim naar boven wijst, is je wijsvingenr X+, je duim Y+, en de Z+ is afhangend van LH en RH linksaf of rechtsaf dwars op je hand.

Als je dus horizontaal om Y heen een draait (dus je draait je tafel/bureau om je duim heen), zul je dus met +90grad draaien op het XZ-vlak linksaf (?) gaan, dus kom je bij LH op (0,0,1) uit (draai naar links, Z+ zit dwars op hand naar links). RH komt dus op (0,0,1) uit.

Lijkt me wel tenminste, anders snap ik het ook niet meer. :)

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Orwell schreef op maandag 18 april 2011 @ 11:43:
Ik kan best fout zitten, maar als Y up is (volgens roy-t), is X vooruit.
Dat is dus niet waar. Dat y up is zegt niets over de richting van de x- en z-as. Hooguit dat, van bovenaf gezien, de z-as 90 graden met de klok mee gedraaid is tov de x-as. Dus bijvoorbeeld x=right en z=back, of x=left en z=forward, maar ook x=left-forward en z=right-forward. Pas bij het vastzetten van twee assen kun je aan de hand van RH of LH zeggen waar de derde as naar wijst.
Neem eens je hand. Als je met je duim naar boven wijst, is je wijsvingenr X+, je duim Y+, en de Z+ is afhangend van LH en RH linksaf of rechtsaf dwars op je hand.
Je vergeet dat je je hand gewoon kunt draaien, bovendien doe je het verkeerd. Duim is X+, wijsvinger is Y+, middelvinger is Z+.
Als je dus horizontaal om Y heen een draait (dus je draait je tafel/bureau om je duim heen), zul je dus met +90grad draaien op het XZ-vlak linksaf (?) gaan, dus kom je bij LH op (0,0,1) uit (draai naar links, Z+ zit dwars op hand naar links). RH komt dus op (0,0,1) uit.
Een y-rotatie-matrix is altijd

cos θ; 0; sin θ
0; 1; 0
-sin θ; 0; cos θ

(met kolomvectoren, met rijvectoren is ie de transpose) ongeacht LH or RH.
Met θ=90 graden kom je dus op

0; 0; 1
0; 1; 0
-1; 0; 0

De vector [1, 0, 0] met die matrix vermenigvuldigen geeft gewoon [0, 0, -1], ongeacht RH of LH. Handedness verandert de wiskunde dus compleet niet - het zegt hoogstens iets over hoe je het resultaat interpreteert.

[ Voor 61% gewijzigd door .oisyn op 18-04-2011 12:43 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Orwell schreef op maandag 18 april 2011 @ 11:43:
[...]


Je bent in principe 100% vrij om LH of RH te kiezen in D3D, maar zo ongeveer 99% van de boeken en tutorials op internet gaan van LH uit. Jeps, hetzelfde effect als "D3D==LH", maar is er keuze in principe. ;)

Mrreh, de Z zit nu dus aan de rechterkant van de positieve X. In principe is het dus logisch dat als je positief horizontaal draait (yaw) , dat je dan linksaf gaat en dat Z negatief wordt.


[...]


Ik kan best fout zitten, maar als Y up is (volgens roy-t), is X vooruit. Neem eens je hand. Als je met je duim naar boven wijst, is je wijsvingenr X+, je duim Y+, en de Z+ is afhangend van LH en RH linksaf of rechtsaf dwars op je hand.

Als je dus horizontaal om Y heen een draait (dus je draait je tafel/bureau om je duim heen), zul je dus met +90grad draaien op het XZ-vlak linksaf (?) gaan, dus kom je bij LH op (0,0,1) uit (draai naar links, Z+ zit dwars op hand naar links). RH komt dus op (0,0,1) uit.

Lijkt me wel tenminste, anders snap ik het ook niet meer. :)
In XNA heb je geen keuze enkel RH als je de standaard functies gebruikt :(

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max

Pagina: 1