Jak określić obiekt / powierzchnię wskazaną przez użytkownika za pomocą lwjgl?
9
Tytuł mówi prawie wszystko. Pracuję nad prostym projektem „przyzwyczajajmy się do lwjgl”, polegającym na manipulowaniu kostką rubika, i nie mogę wymyślić, jak powiedzieć, na którą stronę / kwadrat wskazuje użytkownik.
Uwaga: Wiele silników AFAIK robi to całkowicie na procesorze, niezależnie od renderowania i bez użycia OpenGL, ponieważ jest szybszy (ale bardziej skomplikowany).
user253751,
Odpowiedzi:
8
Będziesz chciał skorzystać z wyboru 3D. Oto kod, którego używam w mojej grze.
Najpierw rzuciłem promień z aparatu. Używam myszy, ale jeśli używasz tylko tego, na co patrzy użytkownik, możesz po prostu użyć środka okna. Oto kod z mojej klasy kamer:
publicRayGetPickRay(){int mouseX =Mouse.getX();int mouseY = WORLD.Byte56Game.getHeight()-Mouse.getY();float windowWidth = WORLD.Byte56Game.getWidth();float windowHeight = WORLD.Byte56Game.getHeight();//get the mouse position in screenSpace coordsdouble screenSpaceX =((float) mouseX /(windowWidth /2)-1.0f)* aspectRatio;double screenSpaceY =(1.0f-(float) mouseY /(windowHeight /2));double viewRatio =Math.tan(((float)Math.PI /(180.f/ViewAngle)/2.00f))* zoomFactor;
screenSpaceX = screenSpaceX * viewRatio;
screenSpaceY = screenSpaceY * viewRatio;//Find the far and near camera spacesVector4f cameraSpaceNear =newVector4f((float)(screenSpaceX *NearPlane),(float)(screenSpaceY *NearPlane),(float)(-NearPlane),1);Vector4f cameraSpaceFar =newVector4f((float)(screenSpaceX *FarPlane),(float)(screenSpaceY *FarPlane),(float)(-FarPlane),1);//Unproject the 2D window into 3D to see where in 3D we're actually clickingMatrix4f tmpView =Matrix4f(view);Matrix4f invView =(Matrix4f) tmpView.invert();Vector4f worldSpaceNear =newVector4f();Matrix4f.transform(invView, cameraSpaceNear, worldSpaceNear);Vector4f worldSpaceFar =newVector4f();Matrix4f.transform(invView, cameraSpaceFar, worldSpaceFar);//calculate the ray position and directionVector3f rayPosition =newVector3f(worldSpaceNear.x, worldSpaceNear.y, worldSpaceNear.z);Vector3f rayDirection =newVector3f(worldSpaceFar.x - worldSpaceNear.x, worldSpaceFar.y - worldSpaceNear.y, worldSpaceFar.z - worldSpaceNear.z);
rayDirection.normalise();returnnewRay(rayPosition, rayDirection);}
Następnie podążam za promieniem, dopóki nie przecina się on z obiektem, możesz to zrobić za pomocą obwiedni lub czegoś podobnego, ponieważ jest to specyficzne dla twojej gry, pozwolę ci sobie z tym poradzić. Zasadniczo odbywa się to przez podążanie za promieniem (dodawanie kierunku promienia do jego punktu początkowego w kółko, dopóki nie wpadniesz na coś).
Następnie chcesz zobaczyć, która twarz jest wybierana, możesz to zrobić, iterując po trójkątach w sześcianie, aby sprawdzić, czy promień ich przecina. Następująca funkcja to robi i zwraca odległość do wybranej twarzy, a następnie po prostu używam przecinającej się twarzy, która jest najbliżej aparatu (więc nie wybierasz tylnej twarzy).
publicstaticfloatRayIntersectsTriangle(Ray R,Vector3f vertex1,Vector3f vertex2,Vector3f vertex3){// Compute vectors along two edges of the triangle.Vector3f edge1 =null, edge2 =null;
edge1 =Vector3f.sub(vertex2, vertex1, edge1);
edge2 =Vector3f.sub(vertex3, vertex1, edge2);// Compute the determinant.Vector3f directionCrossEdge2 =null;
directionCrossEdge2 =Vector3f.cross(R.Direction, edge2, directionCrossEdge2);float determinant =Vector3f.dot(directionCrossEdge2, edge1);// If the ray and triangle are parallel, there is no collision.if(determinant >-.0000001f&& determinant <.0000001f){returnFloat.MAX_VALUE;}float inverseDeterminant =1.0f/ determinant;// Calculate the U parameter of the intersection point.Vector3f distanceVector =null;
distanceVector =Vector3f.sub(R.Position, vertex1, distanceVector);float triangleU =Vector3f.dot(directionCrossEdge2, distanceVector);
triangleU *= inverseDeterminant;// Make sure the U is inside the triangle.if(triangleU <0|| triangleU >1){returnFloat.MAX_VALUE;}// Calculate the V parameter of the intersection point.Vector3f distanceCrossEdge1 =null;
distanceCrossEdge1 =Vector3f.cross(distanceVector, edge1, distanceCrossEdge1);float triangleV =Vector3f.dot(R.Direction, distanceCrossEdge1);
triangleV *= inverseDeterminant;// Make sure the V is inside the triangle.if(triangleV <0|| triangleU + triangleV >1){returnFloat.MAX_VALUE;}// Get the distance to the face from our ray originfloat rayDistance =Vector3f.dot(distanceCrossEdge1, edge2);
rayDistance *= inverseDeterminant;// Is the triangle behind us?if(rayDistance <0){
rayDistance *=-1;returnFloat.MAX_VALUE;}return rayDistance;}
Trójkąt o najmniejszej odległości to wybrany trójkąt. Ponadto, bezwstydna wtyczka do mojej gry, powinieneś ją sprawdzić, śledź ją i głosuj w ankietach, które od czasu do czasu wygłaszam. Dzięki! http://byte56.com
Technika, której szukasz, nazywa się „kompletowaniem” lub „kompletowaniem 3D”. Można to zrobić na kilka sposobów; jednym z bardziej powszechnych jest przekształcenie punktu 2D na ekranie w przestrzeń oka za pomocą odwrotnej transformacji projekcji. Umożliwi to wygenerowanie promienia w przestrzeni widoku, którego można użyć do przetestowania kolizji z fizyczną reprezentacją różnych bitów geometrii sceny w celu ustalenia, który obiekt „trafił” użytkownik.
Możesz także użyć „bufora pobierania” (lub „buforu wyboru”), który obsługuje GL. Zasadniczo wymaga to zapisania unikalnego identyfikatora obiektu w buforze dla każdego piksela, a następnie po prostu przetestowania tego bufora.
Często zadawane pytania dotyczące OpenGL dotyczą obu tych zagadnień (bardziej skupia się na buforze wyboru, ponieważ jest to całkowicie funkcja GL; wybieranie promieniowe jest niezależne od API, z wyjątkiem być może wyodrębnienia aktywnych macierzy z potoku). Oto bardziej konkretny przykład techniki zbierania promieni (na iOS, ale powinna być wystarczająco łatwa do przetłumaczenia). Ta strona zawiera kod źródłowy niektórych przykładów OpenGL Red Book przeniesionych do LWJGL, w tym demo kompletacji.
Należy również pamiętać, że interfejs API do pobierania OpenGL jest przestarzały w GL3 Core. Nadal jest dostępny w pełnym profilu.
nieważne
Heh, wiedza o tym, który termin wyszukać, robi ogromną różnicę :) Jednak właśnie szukałem w Google hasła „przykład wyboru lwjgl”, a ten wątek był jednym z najlepszych hitów!
Odpowiedzi:
Będziesz chciał skorzystać z wyboru 3D. Oto kod, którego używam w mojej grze.
Najpierw rzuciłem promień z aparatu. Używam myszy, ale jeśli używasz tylko tego, na co patrzy użytkownik, możesz po prostu użyć środka okna. Oto kod z mojej klasy kamer:
Następnie podążam za promieniem, dopóki nie przecina się on z obiektem, możesz to zrobić za pomocą obwiedni lub czegoś podobnego, ponieważ jest to specyficzne dla twojej gry, pozwolę ci sobie z tym poradzić. Zasadniczo odbywa się to przez podążanie za promieniem (dodawanie kierunku promienia do jego punktu początkowego w kółko, dopóki nie wpadniesz na coś).
Następnie chcesz zobaczyć, która twarz jest wybierana, możesz to zrobić, iterując po trójkątach w sześcianie, aby sprawdzić, czy promień ich przecina. Następująca funkcja to robi i zwraca odległość do wybranej twarzy, a następnie po prostu używam przecinającej się twarzy, która jest najbliżej aparatu (więc nie wybierasz tylnej twarzy).
Trójkąt o najmniejszej odległości to wybrany trójkąt. Ponadto, bezwstydna wtyczka do mojej gry, powinieneś ją sprawdzić, śledź ją i głosuj w ankietach, które od czasu do czasu wygłaszam. Dzięki! http://byte56.com
źródło
Technika, której szukasz, nazywa się „kompletowaniem” lub „kompletowaniem 3D”. Można to zrobić na kilka sposobów; jednym z bardziej powszechnych jest przekształcenie punktu 2D na ekranie w przestrzeń oka za pomocą odwrotnej transformacji projekcji. Umożliwi to wygenerowanie promienia w przestrzeni widoku, którego można użyć do przetestowania kolizji z fizyczną reprezentacją różnych bitów geometrii sceny w celu ustalenia, który obiekt „trafił” użytkownik.
Możesz także użyć „bufora pobierania” (lub „buforu wyboru”), który obsługuje GL. Zasadniczo wymaga to zapisania unikalnego identyfikatora obiektu w buforze dla każdego piksela, a następnie po prostu przetestowania tego bufora.
Często zadawane pytania dotyczące OpenGL dotyczą obu tych zagadnień (bardziej skupia się na buforze wyboru, ponieważ jest to całkowicie funkcja GL; wybieranie promieniowe jest niezależne od API, z wyjątkiem być może wyodrębnienia aktywnych macierzy z potoku). Oto bardziej konkretny przykład techniki zbierania promieni (na iOS, ale powinna być wystarczająco łatwa do przetłumaczenia). Ta strona zawiera kod źródłowy niektórych przykładów OpenGL Red Book przeniesionych do LWJGL, w tym demo kompletacji.
Zobacz także to pytanie dotyczące SO.
źródło