Question

Je construis un jeu de société en WebGL.Le tableau peut être tourné / zoomé.J'ai besoin d'un moyen de traduire un clic sur l'élément du canevas (x, y) dans le point pertinent dans l'espace 3D (x, y, z).Le résultat final est que je veux connaître la coordonnée (x, y, z) qui contient le point qui touche l'objet le plus proche de l'utilisateur.Par exemple, l'utilisateur clique sur une pièce et vous imaginez un rayon voyageant à travers l'espace 3D qui traverse à la fois la pièce et le plateau de jeu, mais je veux la coordonnée (x, y, z) de la pièce à l'endroit où elle étaittouché.

J'ai l'impression que cela doit être un problème très courant, mais je n'arrive pas à trouver une solution dans mes googles.Il doit y avoir un moyen de projeter la vue actuelle de l'espace 3D en 2D afin que vous puissiez mapper chaque point dans l'espace 2D au point pertinent dans l'espace 3D.Je veux que l'utilisateur puisse passer la souris sur un espace du tableau et que le spot change de couleur.

Était-ce utile?

La solution

Vous recherchez une fonction de non-projection, qui convertit les coordonnées de l'écran en un rayon projeté de la position de la caméra vers le monde 3D. Vous devez ensuite effectuer des tests d'intersection rayon / triangle pour trouver le triangle le plus proche de la caméra qui coupe également le rayon.

J'ai un exemple de non-projection disponible à jax / camera.j # L568 - mais vous devrez toujours implémenter l'intersection rayon / triangle. J'ai une implémentation de cela à jax / triangle.js # L113 < a>.

Il existe cependant une alternative plus simple et (généralement) plus rapide, appelée «picking». Utilisez ceci si vous voulez sélectionner un objet entier (par exemple, une pièce d'échecs), et si vous ne vous souciez pas de l'endroit où la souris a réellement cliqué. La méthode WebGL pour ce faire est de rendre la scène entière dans différentes nuances de bleu (le bleu est une clé, tandis que le rouge et le vert sont utilisés pour les identifiants uniques des objets de la scène) vers une texture, puis relisez un pixel à partir de cette texture. Le décodage du RVB dans l'ID de l'objet vous donnera l'objet sur lequel vous avez cliqué. Encore une fois, j'ai implémenté cela et il est disponible à jax / world.js # L82 . (Voir aussi les lignes 146, 162, 175.)

Les deux approches ont des avantages et des inconvénients (traités ici et dans certains des commentaires après ) et vous devrez déterminer quelle approche répond le mieux à vos besoins. La sélection est plus lente avec des scènes énormes, mais la non-projection en pur JS est extrêmement lente (puisque JS lui-même n'est pas si rapide) donc ma meilleure recommandation serait d'expérimenter les deux.

Pour info, vous pouvez également consulter le projet GLU et déprotéger le code, sur lequel j'ai basé mon code de manière approximative: http:// www .opengl.org / wiki / GluProject_and_gluUnProject_code

Autres conseils

Je travaille actuellement sur ce problème - l'approche que j'adopte est

  1. Rendu des objets pour sélectionner un tampon chacun avec une couleur unique
  2. Lire le pixel de la mémoire tampon, mapper vers l'objet sélectionné
  3. Rendre l'objet sélectionné dans le tampon avec chaque couleur de pixel en fonction de la profondeur Z
  4. Lire le pixel de la mémoire tampon, revenir à la profondeur Z
  5. Nous avons sélectionné un objet et une approximation de Z pour les coordonnées de sélection

Voici la démo fonctionnelle

function onMouseUp(event) {

    event.preventDefault();        
    x_pos = (event.clientX / window.innerWidth) * 2 - 1;
    y_pos = -(event.clientY / window.innerHeight) * 2 + 1;
    z_pos = 0.5;

    var vector = new THREE.Vector3( x_pos , y_pos , z_pos );

    var projector = new THREE.Projector();
    projector.unprojectVector(vector, camera);
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
    var intersects = raycaster.intersectObjects(intersectObjects);

    if (intersects.length > 0) {

        xp = intersects[0].point.x.toFixed(2);
        yp = intersects[0].point.y.toFixed(2);
        zp = intersects[0].point.z.toFixed(2);  
        destination = new THREE.Vector3( xp , yp , zp );

        radians =  Math.atan2( ( driller.position.x - xp) , (driller.position.z - zp));
        radians += 90 * (Math.PI / 180);
        console.log(radians);

        var tween = new TWEEN.Tween(driller.rotation).to({ y : radians },200).easing(TWEEN.Easing.Linear.None).start();

    }

weissner-doors.de/drone/

cultivé à partir de l'un des fils. pas sûr de (x, y, z) mais vous pouvez obtenir le canvas(x,y) en utilisant

getBoundingClientRect ()

function getCanvasCoord(){
  var mx = event.clientX;
  var my = event.clientY;
  var canvas = document.getElementById('canvasId');
  var rect = canvas.getBoundingClientRect();// check if your browser supports this
  mx = mx - rect.left;
  my = my - rect.top;
  return {x: mx , y: my};
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top