Comment aplatir le terrain sous un objet de jeu?

10

J'ai un script qui crée un objet terrain et le peint avec des textures, mais j'ai un problème. Lorsque j'essaie de placer des objets de jeu (comme le simple objet d'eau que l'unité fournit), j'utilise un Raycast pour déterminer la hauteur correcte pour placer l'objet de jeu, mais cela garantit simplement qu'il est correctement placé à ce point particulier.

Comment pourrais-je aplatir le terrain sous l'objet de jeu afin qu'il n'entre pas dans le terrain ou ne traîne pas dans le ciel dans le cas des collines?

Rapida
la source
3
Trouvez tous les sommets qui forment les triangles de terrain sous l'objet de jeu. Faites la même coordonnée y de tous ces sommets.
MichaelHouse

Réponses:

6

Comme je l'ai dit dans mon commentaire, vous voudrez trouver tous les sommets qui composent les triangles sous votre objet de jeu et définir leur valeur y sur la même valeur.

Je développerai mon commentaire avec des étapes plus détaillées. Je ne connais pas trop Unity, donc je ne connais pas les meilleurs outils à utiliser pour le travail, mais je crois que je peux vous aider à démarrer sur la bonne voie.

Méthode de la force brute:

  1. Lancez une grille de rayons directement depuis votre objet de jeu. La grille doit être suffisamment serrée pour ne manquer aucun triangle sur la surface du terrain.
  2. Pour chaque rayon qui frappe quelque chose, vous pouvez obtenir le triangle dans le maillage du terrain avec les éléments suivants:

    RaycastHit hit;
    if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
        return;
    
    MeshCollider meshCollider = hit.collider as MeshCollider;
    if (meshCollider == null || meshCollider.sharedMesh == null)
        return;
    
    Mesh mesh = meshCollider.sharedMesh;
    Vector3[] vertices = mesh.vertices;
    int[] triangles = mesh.triangles;
    Vector3 p0 = vertices[triangles[hit.triangleIndex * 3 + 0]];
    Vector3 p1 = vertices[triangles[hit.triangleIndex * 3 + 1]];
    Vector3 p2 = vertices[triangles[hit.triangleIndex * 3 + 2]];
  3. p0, p1 et p2 sont toutes les positions des trois sommets qui composent le triangle qui a été touché. Vous souhaitez ajuster chacune de ces positions de sommets pour avoir la même yvaleur. Vous pouvez soit collecter tous les sommets, puis les définir tous sur une yvaleur moyenne , ou vous pouvez utiliser la yvaleur initiale choisie que vous avez trouvée lors du placement de votre objet de jeu.

Optimisations:

  • Au lieu de simplement lancer une grille de rayons, vous pouvez balayer un collisionneur de l'objet de jeu et collecter les points de contact des collisions entre le collisionneur d'objet de jeu et le maillage de collision du terrain. Ensuite, pour chacun de ces points de contact, effectuez les étapes ci-dessus pour obtenir les sommets que vous souhaitez déplacer.

  • Créez votre terrain de manière à ce que chaque sommet xet chaque zvaleur soient alignés sur une grille et ne varient que dans leur yvaleur. Maintenant, vous pouvez facilement obtenir les limites de votre objet de jeu et modifier toutes les valeurs y des sommets à l'intérieur de ces limites.

Cette dernière optimisation est vraiment une méthode alternative qui serait probablement facile à mettre en œuvre et assez efficace.

MichaelHouse
la source
D'après ce que je peux dire, l'objet Terrain ( docs.unity3d.com/Documentation/ScriptReference/Terrain.html ) a un TerrainCollider ( docs.unity3d.com/Documentation/ScriptReference/… ) et non un MeshCollider ( docs.unity3d.com/Documentation / ScriptReference /… ), il manque donc une propriété sharedMesh que vous essayez d'utiliser à l'étape 2. J'ai supposé que j'aurais besoin d'une sorte de logique pour modifier la carte de hauteur stockée par la propriété terrainData.
Rapida
Vous pouvez vérifier ici: forum.unity3d.com/threads/… En outre, il semble que l'objet terrain ait un maillage régulier, donc la deuxième optimisation peut être votre meilleur pari.
MichaelHouse
1

Il veut généralement que le sol sous l'objet soit plat et que le sol immédiatement autour de lui soit lissé.

Si le terrain est fait à partir d'une grille et que le bâtiment est aligné sur l'axe, c'est beaucoup plus facile.

Dans le cas général, vous subdivisez les triangles sur lesquels se trouve le bâtiment, puis définissez le y de tous les sommets sur les triangles sur lesquels le bâtiment se trouve sur le même y , puis effectuez un lissage de déplacement au milieu pour tous les sommets à une certaine distance qui sont pas eux-mêmes sous un bâtiment.

J'ai utilisé cette approche pour mettre des routes sur un terrain en 3D.

Vous souhaitez généralement appliquer une séparation minimale entre les bâtiments afin d'avoir suffisamment de terrain à lisser. Ou vous pouvez exécuter l'algorithme provisoirement avant le placement et voir si un certain seuil de pente est dépassé et ainsi contrôler où l'utilisateur peut placer des bâtiments.

Volonté
la source