Je développe un jeu avec un terrain de type Minecraft composé de blocs. Étant donné que le rendu de base et le chargement de blocs sont maintenant effectués, je souhaite implémenter la sélection de blocs.
Par conséquent, je dois découvrir à quel bloc la caméra à la première personne est confrontée. J'ai déjà entendu parler de ne pas projeter toute la scène, mais j'ai décidé de ne pas le faire car cela semble hacky et n'est pas précis. Peut-être que je pourrais en quelque sorte lancer un rayon dans la direction de la vue, mais je ne sais pas comment vérifier la collision avec un bloc dans mes données de voxel. Bien sûr, ces calculs doivent être effectués sur le CPU car j'ai besoin des résultats pour effectuer des opérations de logique de jeu.
Alors, comment pourrais-je savoir quel bloc se trouve devant la caméra? Si c'est préférable, comment pourrais-je lancer un rayon et vérifier les collisions?
la source
Réponses:
Lorsque j'ai eu ce problème en travaillant sur mes cubes , j'ai trouvé l'article "Un algorithme de traversée rapide de voxel pour le traçage de rayons" de John Amanatides et Andrew Woo, 1987 qui décrit un algorithme qui peut être appliqué à cette tâche; il est précis et ne nécessite qu'une seule itération de boucle par voxel intersecté.
J'ai écrit une implémentation des parties pertinentes de l'algorithme de l'article en JavaScript. Mon implémentation ajoute deux fonctionnalités: elle permet de spécifier une limite sur la distance du raycast (utile pour éviter les problèmes de performances ainsi que pour définir une `` portée '' limitée), et calcule également la face de chaque voxel dans laquelle le rayon est entré.
Le
origin
vecteur d' entrée doit être mis à l'échelle de telle sorte que la longueur latérale d'un voxel soit 1. La longueur dudirection
vecteur n'est pas significative mais peut affecter la précision numérique de l'algorithme.L'algorithme fonctionne en utilisant une représentation paramétrée du rayon,
origin + t * direction
. Pour chaque axe de coordonnées, nous gardons une trace de lat
valeur que nous aurions si nous avons fait un pas suffisant pour franchir une limite de voxel le long de cet axe (ie changer la partie entière de la coordonnée) dans les variablestMaxX
,tMaxY
ettMaxZ
. Ensuite, nous faisons un pas (en utilisant les variablesstep
ettDelta
) le long de l'axe qui a le moinstMax
- c'est-à-dire de la limite de voxel la plus proche.Lien permanent vers cette version de la source sur GitHub .
la source
function intbounds(s,ds) { return (ds > 0? Math.ceil(s)-s: s-Math.floor(s)) / Math.abs(ds); }
. CommeInfinity
c'est plus grand que tous les nombres, je ne pense pas que vous ayez besoin de vous prémunir contre le fait que ds soit 0.1/ds
entraîne plutôt l'incrémentation de l'un des autres axes. Le correctif consiste à écrireintfloor
pour vérifier si les deuxds
sont négatifs et s'ils
s'agit d'une valeur entière (mod renvoie 0), et renvoie 0,0 dans ce cas.Regardez peut-être l' algorithme de ligne de Bresenham , en particulier si vous travaillez avec des blocs d'unité (comme la plupart des jeux minecraftish le font).
Fondamentalement, cela prend deux points et trace une ligne ininterrompue entre eux. Si vous lancez un vecteur du joueur à sa distance de cueillette maximale, vous pouvez l'utiliser, et les joueurs se positionnent comme des points.
J'ai une implémentation 3D en python ici: bresenham3d.py .
la source
Pour trouver le premier bloc devant la caméra, créez une boucle for qui boucle de 0 à une distance maximale. Ensuite, multipliez le vecteur avant de la caméra par le compteur et vérifiez si le bloc à cette position est solide. Si c'est le cas, enregistrez la position du bloc pour une utilisation ultérieure et arrêtez la boucle.
Si vous voulez également pouvoir placer des blocs, le choix du visage n'est pas plus difficile. Il suffit de revenir en boucle à partir du bloc et de trouver le premier bloc vide.
la source
J'ai fait un post sur Reddit avec mon implémentation , qui utilise l'algorithme de ligne de Bresenham. Voici un exemple d'utilisation que vous en feriez:
Voici l'implémentation elle-même:
la source