Comment déterminez-vous quel objet / surface l'utilisateur pointe vers lwjgl?
9
Le titre dit à peu près tout. Je travaille sur un projet simple «permet de s'habituer à lwjgl» impliquant la manipulation d'un cube rubik, et je ne sais pas comment dire de quel côté / carré l'utilisateur pointe.
Remarque: de nombreux moteurs AFAIK le font entièrement sur le processeur, séparément du rendu et sans utiliser OpenGL du tout, car c'est plus rapide (mais plus compliqué).
user253751
Réponses:
8
Vous voudrez utiliser la cueillette 3D. Voici un code que j'utilise dans mon jeu.
J'ai d'abord lancé un rayon depuis ma caméra. J'utilise la souris, mais si vous n'utilisez que l'endroit où l'utilisateur regarde, vous pouvez simplement utiliser le centre de la fenêtre. Voici ce code de ma classe d'appareil photo:
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);}
Ensuite, je suis le rayon jusqu'à ce qu'il intersecte avec un objet, vous pouvez le faire avec des boîtes englobantes ou quelque chose de similaire, car cela est spécifique à votre jeu, je vous laisse gérer cela. Généralement, cela se fait en suivant le rayon (en ajoutant la direction du rayon à son point de départ encore et encore 'jusqu'à ce que vous tombiez sur quelque chose).
Ensuite, vous voulez voir quelle face est sélectionnée, vous pouvez le faire en itérant sur les triangles de votre cube pour voir si le rayon les intersecte. La fonction suivante fait cela et renvoie la distance au visage sélectionné, puis j'utilise simplement le visage intersecté le plus proche de la caméra (donc vous ne choisissez pas la face arrière).
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;}
Le triangle avec la distance la plus courte est le triangle choisi. Aussi, plug sans vergogne pour mon jeu, vous devriez le vérifier, le suivre et voter dans les sondages que je publie occasionnellement. Merci! http://byte56.com
La technique que vous recherchez est appelée "cueillette" ou "cueillette 3D". Il y a plusieurs façons de le faire; l'une des plus courantes consiste à transformer un point 2D sur l'écran en espace oculaire en utilisant l'inverse de la transformation de projection. Cela vous permettra de générer un rayon dans l'espace de vue, que vous pouvez utiliser pour tester la collision avec la représentation physique de vos différents bits de géométrie de scène afin de déterminer quel objet l'utilisateur a `` touché ''.
Vous pouvez également utiliser un "tampon de sélection" (ou "tampon de sélection") que GL prend en charge. Cela implique essentiellement d'écrire un identifiant d'objet unique dans un tampon pour chaque pixel, puis de simplement tester ce tampon.
La FAQ OpenGL a de brèves discussions sur les deux (elle se concentre davantage sur le tampon de sélection car il s'agit entièrement d'une fonctionnalité GL; la sélection de rayons est indépendante de l'API, sauf peut-être pour extraire les matrices actives du pipeline). Voici un exemple plus spécifique de la technique de sélection de rayons (pour iOS, mais elle devrait se traduire assez facilement). Ce site contient du code source pour certains des exemples OpenGL Red Book portés sur LWJGL, qui incluent une démo de sélection.
Notez également que l'API de sélection OpenGL est déconseillée dans GL3 Core. Il est toujours disponible dans le profil complet.
nul
Hé, savoir quel terme rechercher fait une énorme différence :) Cependant, je viens de chercher sur google pour 'lwjgl picking example', et ce fil a été l'un des meilleurs hits!
Réponses:
Vous voudrez utiliser la cueillette 3D. Voici un code que j'utilise dans mon jeu.
J'ai d'abord lancé un rayon depuis ma caméra. J'utilise la souris, mais si vous n'utilisez que l'endroit où l'utilisateur regarde, vous pouvez simplement utiliser le centre de la fenêtre. Voici ce code de ma classe d'appareil photo:
Ensuite, je suis le rayon jusqu'à ce qu'il intersecte avec un objet, vous pouvez le faire avec des boîtes englobantes ou quelque chose de similaire, car cela est spécifique à votre jeu, je vous laisse gérer cela. Généralement, cela se fait en suivant le rayon (en ajoutant la direction du rayon à son point de départ encore et encore 'jusqu'à ce que vous tombiez sur quelque chose).
Ensuite, vous voulez voir quelle face est sélectionnée, vous pouvez le faire en itérant sur les triangles de votre cube pour voir si le rayon les intersecte. La fonction suivante fait cela et renvoie la distance au visage sélectionné, puis j'utilise simplement le visage intersecté le plus proche de la caméra (donc vous ne choisissez pas la face arrière).
Le triangle avec la distance la plus courte est le triangle choisi. Aussi, plug sans vergogne pour mon jeu, vous devriez le vérifier, le suivre et voter dans les sondages que je publie occasionnellement. Merci! http://byte56.com
la source
La technique que vous recherchez est appelée "cueillette" ou "cueillette 3D". Il y a plusieurs façons de le faire; l'une des plus courantes consiste à transformer un point 2D sur l'écran en espace oculaire en utilisant l'inverse de la transformation de projection. Cela vous permettra de générer un rayon dans l'espace de vue, que vous pouvez utiliser pour tester la collision avec la représentation physique de vos différents bits de géométrie de scène afin de déterminer quel objet l'utilisateur a `` touché ''.
Vous pouvez également utiliser un "tampon de sélection" (ou "tampon de sélection") que GL prend en charge. Cela implique essentiellement d'écrire un identifiant d'objet unique dans un tampon pour chaque pixel, puis de simplement tester ce tampon.
La FAQ OpenGL a de brèves discussions sur les deux (elle se concentre davantage sur le tampon de sélection car il s'agit entièrement d'une fonctionnalité GL; la sélection de rayons est indépendante de l'API, sauf peut-être pour extraire les matrices actives du pipeline). Voici un exemple plus spécifique de la technique de sélection de rayons (pour iOS, mais elle devrait se traduire assez facilement). Ce site contient du code source pour certains des exemples OpenGL Red Book portés sur LWJGL, qui incluent une démo de sélection.
Voir aussi cette question sur SO.
la source