Potřebujete transformovat pozici myši na souřadnice v OpenGL scéně a nevíte si rady? Pokud ano, jste na správném místě.
Vytvoříme jednoduchou funkci, která provede všechny potřebné operace. Předávat se jí budou dvě celá čísla definující pozici v okně a výstupem budou tři čísla x, y, z pozice ve scéně. Co všechno budeme potřebovat:
Jak tedy na ně?
Potřebujeme nagrabovat informace o aktuálním viewportu. Konkrétně se jedná o počáteční x a y souřadnice spolu se s jeho šířkou a výškou. Pro tuto operaci poslouží OpenGL funkce glGetIntegerv().
GLint viewport[4];// Paměť pro viewport
glGetIntegerv(GL_VIEWPORT, viewport);// Získání viewportu
Pole viewport bude po provedení příkazu obsahovat následující informace.
Jakmile máme informace o viewportu, můžeme se pustit do získávání informací o modelview matici, která určuje, jak jsou koordináty OpenGL primitiv transformovány do viditelných souřadnic. Překl.: V modelview matici je uloženo nastavení kamery (např. translace a rotace).
GLdouble modelview[16];// Paměť pro modelview matici
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);// Získání modelview matice
Dále potřebujeme získat projekční matici, která transformuje vertexy v souřadnicích očí do ořezávacích koordinátů. Překl.: Projekční matice se používá pro nastavení perspektivní nebo pravoúhlé projekce.
GLdouble projection[16];// Paměti pro projekční matici
glGetDoublev(GL_PROJECTION_MATRIX, projection);// Získání projekční matice
Poté, co jsme toto všechno udělali, můžeme nagrabovat souřadnice v okně. V našem případě se zajímáme o pozici myši.
POINT mouse;// Bude ukládat x a y souřadnice myši
GetCursorPos(&mouse);// Grabování souřadnic myši
ScreenToClient(hWnd, &mouse);// Souřadnice v klientské oblasti okna
GLfloat winX, winY, winZ;// Bude ukládat x, y, a z souřadnice
winX = (float)mouse.x;// X pozice myši
winY = (float)mouse.y;// Y pozice myši
Střed souřadnicového systému [0; 0] se ve Windows nachází vlevo nahoře, zatímco u OpenGL je vlevo dole.
winY = (float)viewport[3] - winY;// Odečte aktuální y pozici myši od výšky obrazovky.
Jistě jste si všimli, že nám chybí hodnota na ose z...
glReadPixels(winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);// Získání z pozice
Vše, co nám ještě zbývá udělat, je vypočítat finální hodnoty na OpenGL osách.
GLdouble posX, posY, posZ;// Bude obsahovat výsledné hodnoty
gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);// Transformace do OpenGL souřadnic
Pomocí právě získaných znalostí můžeme napsat C/C++ funkci, která z pozice myši v okně vypočítá OpenGL souřadnice.
CVector3 GetOGLPos(int x, int y)
{
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX, winY, winZ;
GLdouble posX, posY, posZ;
glGetDoublev(GL_MODELVIEW_MATRIX, modelview );
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
winX = (float)x;
winY = (float)viewport[3] - (float)y;
glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
return CVector3(posX, posY, posZ);
}
A ještě jednou, tentokrát v Delphi...
function GetOGLPos(X, Y: Integer): T3D_Point;
var
viewport: array [1..4] of Integer;
modelview: array [1..16] of Double;
projection: array [1..16] of Double;
winZ: Single;
begin
glGetDoublev(GL_MODELVIEW_MATRIX, @modelview);
glGetDoublev(GL_PROJECTION_MATRIX, @projection);
glGetIntegerv(GL_VIEWPORT, @viewport);
Při testování jsem objevil, že pokud se v Delphi rovná y hodnota nule, vrací se nedefinovaná hodnota.
if (Y = 0) then Y := 1;
glReadPixels(X, -Y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, @winZ);
gluUnProject(X, viewport[4]-Y, winZ, @modelview, @projection, @viewport, Result[1], Result[2], Result[3]);
end;
Tak to bude vše. Myslím, že to ani nebolelo...
napsal: Luke Benstead <Lukerd84 (zavináč) lycos.co.uk>
přeložil: Přemysl Jaroš <xzf (zavináč) seznam.cz>
Anglický originál článku lze najít na adrese http://nehe.gamedev.net/data/articles/article.asp?article=13.