Demon64 Posted September 9, 2010 Report Share Posted September 9, 2010 Witam! Mam taki mały problem, otóż próbuję napisać funkcję, która za parametry przyjmowałaby pozycję kursora myszy w 2d i położenie kamery 3d, a zwracałaby mi położenie kursora w 3d, no i nie wiem zbytnio jakimi wzorami się tu posłużyć. Z założenia wygląda to mniej więcej tak: KOD type TPoint = record x,y: integer; end; type TPoint3d = record x,y,z: double; end; type TCamera = record eye,lookat,up: TPoint3d; end; function Conv_2d_to_3d(punkt: TPoint; cam: TCamera): TPoint3d; begin Result.x:={wzór na przekształcenie na osi X}; Result.y:={wzór na przekształcenie na osi Y}; Result.z:=0; end; Parametr punkt to po prostu pixel, nad którym wisi kursor (x: 0-1023, y: 0-767, przy założeniu, że operujemy na rozdzielczości 1024x768), a parametr cam, to pozycja kamery 3d. Kombinowałem już nad tym trochę, no i ciągle coś jest nie tak... Myślę, że gdyby kamera patrzyła centralnie w dół, to nie byłoby większych problemów z tym, ale kamera patrzy w taki sposób opisany wektorami: KOD kamera.eye := Point3d( 0.0, -11.0, 12.0 ); kamera.lookat := Point3d( 0.0, -3.0, 0.0 ); kamera.up := Point3d( 0.0, 1.0, 0.0 ); Czyli patrzy na scenę pod pewnym kątem... Macie może jakieś pomysły? Albo jakieś gotowe wzory na takie przeliczenia? Link to comment Share on other sites More sharing options...
Toster Posted September 9, 2010 Report Share Posted September 9, 2010 nie jestem specjalista od 3d wiec moze gadam bzdury, ale jak masz pozycje 2d kursora i kamere to mozesz wyrysowac linie (promien/prosta) i kursor jest na calej tel lini (od oka do pozycji 2d kursora). Tak wiec trzecia wspolrzedna znajdujesz przez kolizje promienia 'z' jakims obiektem, albo pozycje 'z' ustalasz w zaleznosci od odleglosci plaszczyzny po ktorej porusza sie kursor 2d od "oka". Always Dark<br /> Link to comment Share on other sites More sharing options...
Blind Posted September 9, 2010 Report Share Posted September 9, 2010 A nie wystarczy przemnozyc wspolzednych przez wszystkie macierze? www.blinder.pl - Blog Link to comment Share on other sites More sharing options...
5corpio Posted September 9, 2010 Report Share Posted September 9, 2010 int screenWidth, screenHeight; //The screen resolution, i.e. 640 480 int mouseX, mouseY; //This is your mouse position in screen-coordinates Matrix4x4 matWorld, matView, matProj; //These are the matrices you were using for setting the environment Matrix4x4 mat; Vertex4 mouseWorld; //Will store mouse position in world coordinates mouseWorld.x = 1.0f + mouseX; mouseWorld.y = 1.0f - mouseY; //This may change to 1 + mouseY if you're using OpenGL mouseWorld.z = 0.0f; mouseWorld.w = 1.0f; mouseWorld.x /= screenWidth; mouseWorld.y /= -screenHeight; //Again the sign may change mat = matWorld * matView * matProj; //Here we perform the matrix concatenation on our own mat = mat.inverse(); //Now mat contains the inverse of that matrix, because we want to UNproject, not project. Google for "Matrix 4x4 inverse" if you don't know how to get the inverse matrix //Un-project mouseWorld = mouseWorld * mat; //If this doesn't work try mat * mouseWorld /* Alternatively you can do the matrix multiplication on your own: Vertex4 tmp = mouseWorld; mouseWorld.x = tmp.x * mat._11 + tmp.y * mat._21 + tmp.z * mat._31 + tmp.w * mat._41; mouseWorld.y = tmp.x * mat._12 + tmp.y * mat._22 + tmp.z * mat._32 + tmp.w * mat._42; mouseWorld.z = tmp.x * mat._13 + tmp.y * mat._23 + tmp.z * mat._33 + tmp.w * mat._43; */ //Now mouseWorld contains the position in world coordinates. //Get the ray: Vector3 dir; //Will contain the direction of the ray being casted by the mouse from the camera; //Assumes GetCameraPosition() returns the camera's position; dir = mouseWorld - GetCameraPosition(); Kod zaczerpnięty z: http://www.gamedev.net/community/forums/to...topic_id=526017 Wszystko opisane jest w komentarzach Ot taka mini-strona moja po godzinach http://www.wnetrzekuchni.pl Link to comment Share on other sites More sharing options...
Demon64 Posted September 10, 2010 Author Report Share Posted September 10, 2010 function Conv_2d_to_3d(punkt: TPoint; cam: TCamera): TPoint3d; var mat: _D3DMatrix; mouseWorld,tmp: TVector4; begin mouseWorld.x := 1.0 + punkt.X; mouseWorld.y := 1.0 - punkt.Y; mouseWorld.z := 0.0; mouseWorld.w := 1.0; mouseWorld.x := mouseWorld.x / Form1.ClientWidth; mouseWorld.y := mouseWorld.y / -Form1.ClientHeight; D3DXMatrixMultiply(mat,matWorld,matView); D3DXMatrixMultiply(mat,mat,matProj); D3DXMatrixInverse(mat,0,mat); // tu te zero to nie wiem dokładnie co znaczy pfDeterminant: PSingle tmp := mouseWorld; mouseWorld.x := tmp.x * mat._11 + tmp.y * mat._21 + tmp.z * mat._31 + tmp.w * mat._41; mouseWorld.y := tmp.x * mat._12 + tmp.y * mat._22 + tmp.z * mat._32 + tmp.w * mat._42; mouseWorld.z := tmp.x * mat._13 + tmp.y * mat._23 + tmp.z * mat._33 + tmp.w * mat._43; // tu miało być coś typu Result := mouseWorld - cam; ale takiego odejmowania Delphi nie może wykonać przez niezgodność typów Result.x := mouseWorld.x - cam.eye.x; Result.y := mouseWorld.y - cam.eye.y; Result.z := 0; // ta wartość będzie stała end; Kod zaczerpnięty z: http://www.gamedev.net/community/forums/to...topic_id=526017 Wszystko opisane jest w komentarzach Nie wiem czy dobrze to sobie przepisałem na Delphi, ale coś jest nie tak, bo koordynaty jakie otrzymuję po tej zamianie są siedmiocyfrowe... Czyli o wiele za duże :/ Oto moja funkcja: function Conv_2d_to_3d(punkt: TPoint; cam: TCamera): TPoint3d; var mat: _D3DMatrix; mouseWorld,tmp: TVector4; begin mouseWorld.x := 1.0 + punkt.X; mouseWorld.y := 1.0 - punkt.Y; mouseWorld.z := 0.0; mouseWorld.w := 1.0; mouseWorld.x := mouseWorld.x / Form1.ClientWidth; mouseWorld.y := mouseWorld.y / -Form1.ClientHeight; D3DXMatrixMultiply(mat,matWorld,matView); D3DXMatrixMultiply(mat,mat,matProj); D3DXMatrixInverse(mat,0,mat); // tu te zero to nie wiem dokładnie co znaczy pfDeterminant: PSingle tmp := mouseWorld; mouseWorld.x := tmp.x * mat._11 + tmp.y * mat._21 + tmp.z * mat._31 + tmp.w * mat._41; mouseWorld.y := tmp.x * mat._12 + tmp.y * mat._22 + tmp.z * mat._32 + tmp.w * mat._42; mouseWorld.z := tmp.x * mat._13 + tmp.y * mat._23 + tmp.z * mat._33 + tmp.w * mat._43; // tu miało być coś typu Result := mouseWorld - cam; ale takiego odejmowania Delphi nie może wykonać przez niezgodność typów Result.x := mouseWorld.x - cam.eye.x; Result.y := mouseWorld.y - cam.eye.y; Result.z := 0; // ta wartość będzie stała end; Co tu jest źle? Determinant? Czy może odejmowanie Result = mouseWorld - cam? Dodam, że ten Determinant jak zmienię np. na wartość 1, to nie chce mnie kompilator puścić i wywala błąd Incompatible types 'Integer' and 'PSingle'... Link to comment Share on other sites More sharing options...
5corpio Posted September 10, 2010 Report Share Posted September 10, 2010 CYTATDeterminant Wyznacznik macierzy. CYTATDodam, że ten Determinant jak zmienię np. na wartość 1, to nie chce mnie kompilator puścić i wywala błąd Incompatible types 'Integer' and 'PSingle'... Bo argumentem ma być wskaznik na float. CYTATale takiego odejmowania Delphi nie może wykonać przez niezgodność typóww nowym śmiałoby przeszło gdyby przeciążyć operatory jak w cepie. Szczerze mówiąc dokładnie nie analizowałem kodu źródłowego zarzuconego ale postaram się przetestować. // tu te zero to nie wiem dokładnie co znaczy pfDeterminant: PSingle Spróbuj zamiast 0 zamienić na nil ? Chociaż i tak pewnie to zostanie zamienione :/ Ot taka mini-strona moja po godzinach http://www.wnetrzekuchni.pl Link to comment Share on other sites More sharing options...
Demon64 Posted September 13, 2010 Author Report Share Posted September 13, 2010 Darowałem sobie z tymi własnymi przeliczeniami póki co, gdyż znalazłem taką interesującą funkcję w DirectX służącą właśnie do takich przeliczeń współrzędnych 2d na 3d: function Conv_2d_to_3d(punkt: TPoint; cam: TCamera): TPoint3d; var vect_ok,v: _D3DVECTOR; view_port: _D3DVIEWPORT8; begin v := D3DXVector3(punkt.X, punkt.Y, 0.0); Form1.c.Device.GetViewport(view_port); D3DXVec3Unproject(vect_ok, v, view_port, matProj, matView, matWorld); Result.x:=vect_ok.x; Result.y:=vect_ok.y; Result.z:=-8; end; Użyłem tej funkcji, ale coś nadal jest nie tak... Wygląda tak jakby na osi X robiło dobrze, ale za to na osi Y daje zbyt duże wartości i na dodatek szybko się one zmieniają w porównaniu do osi X... function Conv_2d_to_3d(punkt: TPoint; cam: TCamera): TPoint3d; var vect_ok,v: _D3DVECTOR; view_port: _D3DVIEWPORT8; begin v := D3DXVector3(punkt.X, punkt.Y, 0.0); Form1.c.Device.GetViewport(view_port); D3DXVec3Unproject(vect_ok, v, view_port, matProj, matView, matWorld); Result.x:=vect_ok.x; Result.y:=vect_ok.y; Result.z:=-8; end; matProj, matView, matWorld - to są zmienne globalne macierzowe TD3DXMatrix vect_ok - tu przypisywany jest wynik przeliczenia współrzędnych v - przekazuje współrzędne punktu 2d // EDIT: sprawdzałem przed chwilą i podczas zmieniania współrzędnej Z w zmiennej v z 0.0 na inne wartości, zmieniają się także otrzymywane wyniki przeliczeń z 2d do 3d nie wiem za bardzo do czego to służy... :/ Wyregulowałem to na 0.96 i w ostatniej linijce Result.z:=-8; zamieniłem na Result:=vect_ok.z; No i powiem, że teraz jak wstawię w tą wyliczoną współrzędną jakiś obiekt to się zgadza jego położenie na ekranie, jest równe z położeniem myszki, czyli wychodzi na to, że przekształca to pozycję myszki z 2d na pozycję 3d, ale w wyświetlanej płaszczyźnie. A mi zależy na tym, by wyświetlało go na wysokości z = -8 ale w takim samym miejscu jak pokazuje kursor na ekranie... Oto 2 rysunki sytuacyjne, które pomogą się wam zorientować w sytuacji: Rysunek sytuacyjny oś OY Rysunek sytuacyjny oś OX Link to comment Share on other sites More sharing options...
Blind Posted September 13, 2010 Report Share Posted September 13, 2010 Moim zdaniem zrobisz to tak(ale glowy nie daje): obliczasz ten punkt 3d nazwijmy go p1, punkt 2d zapisujesz jako punkt 3d tak ze p2 = (2d.x, 2d.y, odleglosc pierwszego planu) Teraz masz prosta w przestrzeni wyznaczona przez punkty p1 i p2 i mozesz obliczyc punkt p3 ktory znajduje sie na tej prostej i jest odalony od p2 o 8 jednostek. EDIT: Eee.. zle p2 cza by jeszcze przemnozyc przez macierz projekcji zeby otrzymac wartosci z przedzialu . No i tez pytanie czy ta plaszczyzna na ktorej znajduje sie ten punkt 3d nie jest przednim planem, jesli tak to pewnie przez manipulacje pozostalymi macierzami bedziesz mogl przesunac ta plaszczyzne bardziej w glab. To sa tylko moje przemyslenia i nie gwarantuje ze sa prawidlowe www.blinder.pl - Blog Link to comment Share on other sites More sharing options...
Demon64 Posted September 13, 2010 Author Report Share Posted September 13, 2010 Przed chwilą znów manipulowałem przekształconą współrzędną kursora 2d na 3d, by uzyskać pozycję Y obiektu na płaszczyźnie i oto rezultat: function Conv_2d_to_3d(punkt: TPoint; cam: TCamera): TPoint3d; var vect_ok,v: _D3DVECTOR; view_port: _D3DVIEWPORT8; begin v := D3DXVector3(punkt.X, punkt.Y, 0.96); D3DXMatrixTranslation( matWorld, 0.0, 0.0, 0.0 ); Form1.c.Device.GetViewport(view_port); D3DXVec3Unproject(vect_ok, v, view_port, matProj, matView, matWorld); Result.x := vect_ok.x; Result.Y := vect_ok.Y * ((cam.eye.Z+8) / Odl(vect_ok.Z,cam.eye.Z)); // obliczanie współrzędnej Y Result.z := -8; end; óĘ+óvwŁb(Ż<ŹŚĄś&śbxóvvŻ(4jWŚźdrŚź'ŹFŚzźs<!Ąjhh!ĘzKn'(ŹYz;3zxZ.Ę+zg (r'jóyęr0iŁ^j0j'huŹŚr6$jgĘ*h'#bKjWx'j7jKh6Ą2KkĄlk-gG#kjG^bppŚgVć7F6eó&EFó6BVćCEC6ÓD6W&EC6Cf\"fV7EcC4EdT5D#fWu'CC4EdUu%CŚ&VvbŁC4EfV7F#2VćBVćBbC4EG&G&6ĆFEv&ĆBf&Óć2FWf6RvWEfWw'BfWu'BC4EfV35V&ŚV7BfV7EbfWu'BE&EfWrEv&ĆB&W7VBŁfV7E6ćWRłFfV7EĆ6ćWR&W7VBŁfV7E6ćWRłFfV7EĆ6ćWR&W7VBŁÓŚVćC Wszystko działa pięknie ale tylko dla kamery położonej w punkcie (0.0, 0.0, Z), gdzie Z mogę mieć dowolne, a jak przesunę kamerę w inną pozycję to tu zaczynają się problemy. Może, żeby to lepiej zobrazować przedstawię wam screeny. Kamera w pozycji (0.0, 0.0, 12.0): Screen 1 Screen 2 Screen 3 Screen 4 Screen 5 Kamera przesunięta w inne miejsce: Screen 1 Screen 2 Screen 3 Screen 4 Link to comment Share on other sites More sharing options...
Demon64 Posted September 15, 2010 Author Report Share Posted September 15, 2010 OK trochę się pobawiłem aktualnie funkcja wygląda tak: function Conv_2d_to_3d(punkt: TPoint; cam: TCamera): TPoint3d; var vect_ok,v: _D3DVECTOR; view_port: _D3DVIEWPORT8; begin v := D3DXVector3(punkt.X, punkt.Y, 0.96); D3DXMatrixTranslation( matWorld, 0.0, 0.0, 0.0 ); Form1.c.Device.GetViewport(view_port); D3DXVec3Unproject(vect_ok, v, view_port, matProj, matView, matWorld); Result.X := vect_ok.X * ((cam.eye.Z+8) / Odl(vect_ok.Z,cam.eye.Z)); Result.Y := vect_ok.Y * ((cam.eye.Z+8) / Odl(vect_ok.Z,cam.eye.Z)); Result.z := -8; end; z płaszczyzną, na której miał znajdować się szukany punkt i działa jak należy Temat do zamknięcia Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.