3D coordinaat naar 2D projectiecoord

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
hallo wiskundigen onder u,

ik zoek de berekeningen die nodig zijn om het geprojecteerde 2D coordinaat te krijgen van een 3D coordinaat, gezien door een camera met perspectief.

ik vermoed dat ik alle benodigde variabelen heb:

*de matrix met de verplaatsing en rotatie van de camera
*de verticale FOV (kijkhoek) van de camera
*de 2D schermresolutie
*de aspect ratio
*een om te zetten 3D coordinaat

ik denk dat ik een aardig eind zou komen als de camera geen perspectief had, maar daar zit ik een beetje stuk. ik gebruik een gluPerspective call, en in de documentatie staat de matrix die hiervoor wordt gemaakt.

ik vermoed dat ik de verplaatsing/rotatiematix moet vermenigvuldigen met die matrix, of andersom, of juist de inversen van deze matrices moet gebruiken, maar mijn wiskundekennis is.. ehh.. laten we maar zeggen abominabel :Y)

heb ik alle benodigde variabelen en zo ja, heeft iemand wat pointers voor me? (no pun intended ;))

*overigens; ik herinner me dat opengl een functie had om zo'n 2D coordinaat te berekenen, maar ga er van uit dat ik die niet kan gebruiken :)

[ Voor 6% gewijzigd door Verwijderd op 24-01-2011 14:09 ]


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Waarschijnlijk is het de inverse van die camera rotatie matrix maal de gluperspective matrix, maal je 3d vector als x,y,z,1. Daar krijg je een 4-vector uit, xyzw, je 2d punt is dan x/w,y/w.

[ Voor 8% gewijzigd door Zoijar op 24-01-2011 14:11 ]


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoijar schreef op maandag 24 januari 2011 @ 14:11:
Waarschijnlijk is het de inverse van die camera rotatie matrix C maal de gluperspective matrix P, maal je 3d vector v als x,y,z,1. Daar krijg je een 4-vector uit, xyzw, je 2d punt is dan x/w,y/w.
Je bedoelt P∙C-1∙v, en niet C-1∙P∙v

[ Voor 9% gewijzigd door .oisyn op 24-01-2011 14:59 ]

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!

Verwijderd

Topicstarter
bedankt jongens, het lijkt redelijk te kloppen, alleen zijn mn coordinaten nog wat verschoven (een verschuiving die wat 'randomig' afhankelijk lijkt van de verplaatsing/rotatie van de camera)

het zou goed kunnen liggen aan een foutje ergens in mn code, ik zoek nog ff door. wat voor coordinaten zou ik terug moeten krijgen; x en y van -1 tot 1 of iets dergelijks?

Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

De coordinaten die je eruit krijgt liggen van -1 t/m 1 in x- en y-richting en van 0 t/m 1 in z-richting.

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!

Verwijderd

Topicstarter
ahh, dan doe ik duidelijk iets fout. mijn Z ligt eerder rond de 100, vast niet geheel toevallig is dat ongeveer de afstand van de camera tot het te projecteren 3D-punt :)

*hmm, de x en y coordinaten (VOOR de deling door W) doen vrolijk mee aan dat soort coordinaten van rond de 10tallen..

ok ik denk dat ik ijl, je bedoeld vast NA de deling :) dan klopt het idd.

[ Voor 37% gewijzigd door Verwijderd op 24-01-2011 15:39 ]


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wacht, ik bedoelde wel de coordinaten ná de deling door w he :)
.edit: oh ik had je edit niet gezien :P

[ Voor 34% gewijzigd door .oisyn op 24-01-2011 16:01 ]

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!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

.oisyn schreef op maandag 24 januari 2011 @ 14:57:
Je bedoelt P∙C-1∙v, en niet C-1∙P∙v
Oops |:( Inderdaad...
bedankt jongens, het lijkt redelijk te kloppen, alleen zijn mn coordinaten nog wat verschoven (een verschuiving die wat 'randomig' afhankelijk lijkt van de verplaatsing/rotatie van de camera)
Misschien was je camera matrix al geinverteerd; kan het proberen zonder die inverse.

[ Voor 41% gewijzigd door Zoijar op 24-01-2011 16:09 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
ah bedankt, maar dat lijkt niet het probleem. ik heb een filmpje gemaakt, misschien herkennen jullie er een bepaald foutje in..

http://www.youtube.com/watch?v=rHr_oJaRVlk

vooral het begin van het filmpje is misschien nuttig voor de debug. als je em dan pauseert zie je dat de positie van de 'namen' precies omgekeerd zijn (check de radar). daarna roteert en verplaatst de camera naar het normale standpunt en 'klopt' het wel.

vervolgens, als ik naar rechtsboven loop lijkt de X coord goed mee te gaan. als de camera dan op een gegeven moment stop met bewegen omdat ik te ver rechtsboven ben gaat de X vrolijk door.. beetje vreemd aangezien die camerapositie ook in de inverse matrix mee zou moeten doen.

verder, later in het filmpje, als ik de camera dichterbij en lager zet vallen de namen onderuit het beeld..

herkennen jullie hier een bepaalde fout in? overigens zouden de namen precies boven de hoofden van de mannetjes moeten komen :)

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Heb je misschien je scherm coordinaten omgekeerd? Opengl scherm begint links onder, niet links boven. Ik zie niet zo snel wat het is, maar lijkt op een omkering van iets. Of links-handige versus rechts-handige coordinaten (i.e. x-as gespiegeld?)

Ziet er leuk uit trouwens; zelf gemaakt?

[ Voor 8% gewijzigd door Zoijar op 24-01-2011 16:28 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
hmja het vreemde is dus dat het eerst omgekeerd is, maar nadat de camera op zijn 'vaste hoek' staat niet meer.. ik geloof dat ik het verder wel correct heb, maar ik zal nog even kijken :)

zelf gemaakt idd, dank je :) hoop over een paar maanden een publieke beta af te hebben!

hier de code die ik nu heb.. misschien zien jullie er een domme fout in.

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void Matrix4::MultiplyVec4(float x, float y, float z, float w, float &rx, float &ry, float &rz, float &rw) {
  rx = elements[0] * x + elements[1] * y + elements[2] * z + elements[3] * w;
  ry = elements[4] * x + elements[5] * y + elements[6] * z + elements[7] * w;
  rz = elements[8] * x + elements[9] * y + elements[10] * z + elements[11] * w;
  rw = elements[12] * x + elements[13] * y + elements[14] * z + elements[15] * w;
}

Vector3 Match::GetProjectedCoord(const Vector3 &pos3D) {

  // de camera matrix inverse

  Matrix4 rotMat;
  // construct inverse werkt sowieso goed
  rotMat.ConstructInverse(camera->GetDerivedPosition(), Vector3(1, 1, 1), camera->GetDerivedRotation());


  float fov = camera->GetFOV();
  // cotangent
  float f = tan(pi * 0.5 - fov / 2.0);
  float aspect = GetMenuTask()->GetWindowManager()->GetAspectRatio();
  float zNear = 3.0;
  float zFar = 270.0;


  // het gebeuren van de gluPerspective docs

  Matrix4 perspMat;
  perspMat.elements[0] = f / aspect;
  perspMat.elements[5] = f;
  perspMat.elements[10] = (zFar + zNear) / (zNear - zFar);
  perspMat.elements[11] = (2 * zFar * zNear) / (zNear - zFar);
  perspMat.elements[14] = -1;


  Matrix4 resMat = perspMat * rotMat;

  float x, y, z, w;
  resMat.MultiplyVec4(pos3D.coords[0], pos3D.coords[1], pos3D.coords[2], 1, x, y, z, w);
  
  Vector3 result;
  result.coords[0] = x / w;
  result.coords[1] = y / w;
  
  result += 1.0;
  result *= 0.5;
  result *= 100; // in percentage van scherm breedte/hoogte: 0 .. 100
  
  return result;
}

[ Voor 78% gewijzigd door Verwijderd op 24-01-2011 17:58 ]


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Zo te zien (als ik het goed zie...) vermenigvuldig je voor met de (rij)vector, maar je moet navermenigvuldigen met een kolomvector. i.e.: rx = elements[0]*x + elements[4]*y + elements[8]*z + elements[12]*w; etc. Effectief vermenigvuldig je dus met de transpose. (regel 2-5)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
bedankt zoijar, zoiets had ik ook vermoed, dus ik had het al geprobeerd:

C++:
1
2
3
4
5
6
7
8
  void Matrix4::MultiplyVec4(float x, float y, float z, float w, float &rx, float &ry, float &rz, float &rw) {
    Transpose();
    rx = elements[0] * x + elements[1] * y + elements[2] * z + elements[3] * w;
    ry = elements[4] * x + elements[5] * y + elements[6] * z + elements[7] * w;
    rz = elements[8] * x + elements[9] * y + elements[10] * z + elements[11] * w;
    rw = elements[12] * x + elements[13] * y + elements[14] * z + elements[15] * w;
    Transpose();
}


maar helaas krijg ik dan helemaal bizarre resultaten..

ik zal nog even alle combinaties van transpose/niet transpose proberen bij alle matrices :P

ps. of bedoel je nog wat anders met voor/na-vermenigvuldigen?

overigens gebruik ik de transpose van wat openGL normaal doet. ik dacht dat ik daarom misschien die perspectiefmatrix van de gluPerspective docs ook nog moest transposen, maar dat levert ook niet echt geslaagde resultaten op :(

[ Voor 16% gewijzigd door Verwijderd op 24-01-2011 19:36 ]


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

ps. of bedoel je nog wat anders met voor/na-vermenigvuldigen?
Je hebt twee manieren om vectoren te specificeren. Of als (4,1) matrix (een rijvector, want de vector bestaat uit 1 rij), of als (1,4) matrix (een kolomvector)

Aangezien het aantal rijen van een matrix aan de linkerkant van de vermenigvuldiging overeen moet komen met het aantal kolommen van de matrix aan de rechterkant, schrijf je dus v*M voor een rijvector en M*v voor een kolomvector. Ook de volgorde van vermenigvuldiging met andere matrices draait om. Voor rijvectoren is een transformatie over A gevolgd door een transformatie over B te schrijven als v*A*B. Bij kolomvectoren is dat precies andersom: B*A*v. Dit bedoelde hij dus met voor- en navermenigvuldigen.

Welke versie je toepast moet je zelf bepalen. D3D gebruikt rijvectoren en OpenGL gebruikt kolomvectoren. Máár, dat is niet alles. Een 2D array kun je op twee manieren in het geheugen zetten. Of row-major, wat wil zeggen dat je hele rijen aaneengesloten opslaat. Dit komt het overeen met de gebruikelijke 2d arrays in de meeste programmeertalen, dus M[rij][kolom] of als M[rij * breedte + kolom]. Maar je kunt ook column-major opslaan, dus als M[kolom][rij] of M[kolom * hoogte + rij].

Beide dingen bepalen dus hoe je de elementen van de matrix moet accessen. D3D gebruikt zogezegd rijvectoren, en slaat de matrices row-major op. OpenGL gebruikt weliswaar kolomvectoren, maar slaat zijn data juist column-major op. Oftewel, de memory layout van een D3D matrix komt exact overeen met die van een OpenGL matrix. De implementatie van vermenigvuldigings-routines zijn dan ook identiek.

Wat je ook moet bepalen is of je een left-handed of right-handed assenstelsel gebruikt. Wederom, D3D is LH, OpenGL is RH.

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!

Verwijderd

Topicstarter
dank je voor de uitleg, weer een hoop geleerd vandaag :) wist wel wat over het row/column-major gebeuren, maar zo uitgebreid wist ik er nog niet van.

m'n bugjes zijn ook opgelost: ik voerde voor de cotangent-berekening vrolijk een FOV in graden aan tan(). dat lust ie niet ;) beetje dom :)

voor de rest bleek het te kloppen, blijkbaar ook qua volgorde en kolommigheid van de vector waarmee wordt vermenigvuldigd :) dank jullie!
Pagina: 1