Autor Wątek: D3DXVec3Unproject, nazwa, a środek ?  (Przeczytany 601 razy)

Offline matuzalem

  • Użytkownik

# Kwiecień 13, 2009, 16:41:47
Witam

Ostatnio doszedłem do tematu 'picking' - jednak wcześniej postanowiłem, że najpierw stworze takie ustrojstwo, które umożliwi mi poruszanie obiektem 3D zgodnie z ruchami myszki/kursora.

Znalazłem kilka przykładów w sicie:

http://www.ureader.com/msg/1464578.aspx
http://www.gamedev.net/community/forums/topic.asp?topic_id=397658

nie wiem czy działają, nie miałem jeszcze czasu sprawdzić :P ale wyglądają dobrze :) - które używają funkcji D3DXVec3Unproject.

Interesuje mnie co ta funkcja ma w swych bebechach, tzn. co dokładnie robi (matematycznie) - wytłumaczenie w MSDN: "Projects a vector from screen space into object space" mówi mi tylko tyle, że jest to projekcja wektora  z "ekranu na obiekt", a mnie interesuje, co on robi z danymi wewnątrz.

Domyślam się, że funkcja D3DXVec3Project jest "odwrotnością".

//EDIT
Niestety w/w przykłady nie działają... tzn. obiekt się porusza, ale wychodzi mocno poza zakres obszaru widoku (1024x768; początkowe położenie obiektu 0.0f, 0.0f, 0.0f; kamera pos: 0.0f, 0.0f, 10.0f; look at: 0.0f, 0.0f, 0.0f)

Pozdrawiam
« Ostatnia zmiana: Kwiecień 13, 2009, 19:02:53 wysłana przez matuzalem »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Avaj

  • Użytkownik

# Kwiecień 13, 2009, 19:02:52
Ta funkcja robi dokładnie to co jest napisane :)

Podając współrzędne punktów do rysowania np. modelu podajesz je w przestrzeni obiektu. Są one potem w vertex shaderze mnożone przez macierz świata, widoku i projekcji. Po tych mnożeniach, dostajesz punkt w przestrzeni ekranu który można już normalnie narysować. Tak działa D3DXVec3Project.

D3DXVec3UnProject robi na odwrót. Znasz pozycję kliknięcia myszki, pozycja myszki jest w 2D, a my chcemy wiedzieć w co klikamy w 3D. Bierzemy współrzędne mychy, wyrażamy je w screen-space, mnożymy przez inwersję macierzy projekcji, inwersję widoku i inwersję świata. W efekcie dostaniemy współrzędne tego wektora w przestrzeni obiektu. Mając to możemy potraktować ten wektor jako półprostą (ray) z którą sprawdzamy kolizje.

Offline matuzalem

  • Użytkownik

# Kwiecień 13, 2009, 19:05:09
Ta funkcja robi dokładnie to co jest napisane :)

Podając współrzędne punktów do rysowania np. modelu podajesz je w przestrzeni obiektu. Są one potem w vertex shaderze mnożone przez macierz świata, widoku i projekcji. Po tych mnożeniach, dostajesz punkt w przestrzeni ekranu który można już normalnie narysować. Tak działa D3DXVec3Project.

D3DXVec3UnProject robi na odwrót. Znasz pozycję kliknięcia myszki, pozycja myszki jest w 2D, a my chcemy wiedzieć w co klikamy w 3D. Bierzemy współrzędne mychy, wyrażamy je w screen-space, mnożymy przez inwersję macierzy projekcji, inwersję widoku i inwersję świata. W efekcie dostaniemy współrzędne tego wektora w przestrzeni obiektu. Mając to możemy potraktować ten wektor jako półprostą (ray) z którą sprawdzamy kolizje.

Dzięki za wytłumaczenie - domyślałem się, że chodzi o mnożenie - jednak w jaki sposób wykonać to o czym pisałem, obiekt porusza się "za" kursorem myszki?

//EDIT
Na razie nie chce wykrywać kolizji "myszki" z obiektem - pickingu, tylko by obiekt podążał za myszką.

//EDIT2
yyy nie wiem czy to jest dobrze czy nie... ale wpadłem na coś takiego :) - a to coś działa :P
Użyłem D3DXVec3Unproject dla wektora (mouse_x, mouse_y, 0.0f) dla pozostałych argumentów to co mają mieć; macierz świata jest identycznościowa; następnie wyplute wyniki w wektorze (x, y) pomnożyłem przez odległość obiektu od kamery (tu 10.0f jednostek) i hula :), wydaj mi się, że jest to logiczne, ale czy nie ma "ale" ?


Pozdrawiam
« Ostatnia zmiana: Kwiecień 13, 2009, 19:53:26 wysłana przez matuzalem »

Offline matuzalem

  • Użytkownik

# Kwiecień 13, 2009, 23:20:07
Ta funkcja robi dokładnie to co jest napisane :)

Podając współrzędne punktów do rysowania np. modelu podajesz je w przestrzeni obiektu. Są one potem w vertex shaderze mnożone przez macierz świata, widoku i projekcji. Po tych mnożeniach, dostajesz punkt w przestrzeni ekranu który można już normalnie narysować. Tak działa D3DXVec3Project.

D3DXVec3UnProject robi na odwrót. Znasz pozycję kliknięcia myszki, pozycja myszki jest w 2D, a my chcemy wiedzieć w co klikamy w 3D. Bierzemy współrzędne mychy, wyrażamy je w screen-space, mnożymy przez inwersję macierzy projekcji, inwersję widoku i inwersję świata. W efekcie dostaniemy współrzędne tego wektora w przestrzeni obiektu. Mając to możemy potraktować ten wektor jako półprostą (ray) z którą sprawdzamy kolizje.

Próbuje, próbuję i nic :) chciałby uzyskać taki sam wynik przy "ręcznym liczeniu" jaki zwraca D3DXVec3Unproject... o mnożeniu już wiem jednak sama funkcja pobiera jeszcze info o viewport i na pewno nie bez powodu...

Domyślam się, że pewnie gdzieś wykorzystuje coś takiego:

v.x =  ( ( ( 2.0f * Cursor.x ) / BackBuffer.Width  ) - 1 ) / mxproj(1, 1);
v.y = -( ( ( 2.0f * Cursor.y ) / BackBuffer.Height ) - 1 ) / mxproj(2, 2);
v.z =  [to_set];

ale gdzie i jak? ; spotkałem się jeszcze, że z macierzy mxproj pobierane są wartości z (0, 0) i (1, 1) od czego to zależy? (oczywiście jeśli ma to coś wspólnego z D3DXVec3Unproject bo jeśli nie to pominąć :P )

//EDIT
zgłupiałem :| teraz to już nie łapie mam takie same wyniki ale, sami zobaczcie...


 D3DVIEWPORT9 d3dv;
  D3DXMATRIX mxproj, mxview, mxworld;


  dev->GetViewport(&d3dv);
  dev->GetTransform(D3DTS_PROJECTION, &mxproj);
  dev->GetTransform(D3DTS_VIEW, &mxview);
 
  D3DXMatrixIdentity(&mxworld);

  D3DXVECTOR3 vec3(mouse_x, mouse_y, 0.0f);
  D3DXVECTOR4 vec4(0.0f, 0.0f, 0.0f, 0.0f);

//  vec3.x = (((2.0f * mouse_x) / d3dv.Width) - 1.0f) / mxproj(2, 2);
//  vec3.y = (((-2.0f * mouse_y) / d3dv.Height) + 1.0f) / mxproj(2, 2);
// lub
  vec3.x = (((2.0f * mouse_x) / d3dv.Width) - 1.0f) / mxproj(2, 2);
  vec3.y = -(((2.0f * mouse_y) / d3dv.Height) - 1.0f) / mxproj(2, 2);

  D3DXMatrixInverse(&mxproj,  NULL, &mxproj);
  D3DXMatrixInverse(&mxworld, NULL, &mxworld);
  D3DXMatrixInverse(&mxview,  NULL, &mxview);

  D3DXVec3Transform(&vec4, &vec3, &mxproj);
  vec3.x = vec4.x;
  vec3.y = vec4.y;
  vec3.z = vec4.z;

  D3DXVec3Transform(&vec4, &vec3, &mxview);
  vec3.x = vec4.x;
  vec3.y = vec4.y;
  vec3.z = vec4.z;

  D3DXVec3Transform(&vec4, &vec3, &mxworld);
  vec3.x = vec4.x;
  vec3.y = vec4.y;
  vec3.z = vec4.z;

// vec3 zawiera wynik


a zgłupiałem z powodu mxproj(2, 2); dla-czemu ?
to jest dziwne... używam macierza projekcji dla perspektywy "w lewo" (nie ortogonalnie)
zgodnie z tą macierzą



gdzie P(2,2):



n == z-axis,
h == wysokość screen-a,
a == kąt fov (focus)

i bądź tu mądry :|


Dzięki
Pozdrawiam
« Ostatnia zmiana: Kwiecień 14, 2009, 00:11:34 wysłana przez matuzalem »