Search Unity

Question How to find out if a GameObject is below Terrain.

Discussion in 'Editor & General Support' started by Drake4, Mar 24, 2023.

  1. Drake4

    Drake4

    Joined:
    Jun 17, 2022
    Posts:
    30
    Guys,

    I want to know if a given game object is below or above terrain. The terrain can have any shape. How do I do that?

    I know that raycast is a solution. A solution which, I do not want to resort to unless it is the only solution - may not even do it if it is the only one.

    I hope for a different one, like asking for the clostest point on terrain, and getting a terrain normal (which hopefull always points towards the sky above of the the terrain) so that when the terrain normal is anti-parallel to the vector from closest point to myGameObject I know that I am underground?

    Cheers!
     
  2. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    720
    Can't you just check if the object's y-position is lower than that of the terrain at the object's position? I don't think you can create an overhang with Unity terrain.

    Code (CSharp):
    1.  
    2.     public static Vector3 GetWorldPos(Vector3 point) {
    3.         point.y +=  Terrain.activeTerrain.SampleHeight(point) + Terrain.activeTerrain.transform.position.y;
    4.  
    5.         return result;
    6.     }
    I use that code to snap a world-space position onto the terrain. You could then check the result's y value.
     
  3. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Why not? What's wrong with a raycast? Seems like the ideal solution here.
     
  4. Drake4

    Drake4

    Joined:
    Jun 17, 2022
    Posts:
    30
    I think this is a really good idea, and I instantly tried this however

    Code (CSharp):
    1. Terrain.activeTerrain.SampleHeight(point)
    Always returns 0 no matter what point I put in. I believe this is not the way it is supposed to work.

    I got a similiar problem with terrainCollider.ClosestPoint(point) which returns point. No matter if point is on, above or below terrain. Any thoughts why that could be?
     
  5. Drake4

    Drake4

    Joined:
    Jun 17, 2022
    Posts:
    30
    Well, in my observation, Raycast costs more performance than other solutions, the code required usually ends up to be fairly complex compared to analytical solutions and there are several things which can go wrong with raycasting. I am actually not sure if you can cast a ray from below terrain and get a colision.
     
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    The code required to do what you want would be 1-2 lines. It is not terribly complex and not sure what you mean about things "going wrong"? It's also very performant.

    You would not cast the ray from below you would cast it from above.
     
  7. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    720
    Do you have multiple terrain tiles? My code just kinda...assumes activeTerrain is the right thing.
     
  8. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,183
    Code to perform a raycast shouldn't be "fairly complex". If it is you may be doing something wrong and it may explain why think the performance isn't as ideal as it should be. Here's an example of what it should look like.

    Code (csharp):
    1. using UnityEngine;
    2.  
    3. public class TerrainCheck : MonoBehaviour
    4. {
    5.     public GameObject referenceObject;
    6.  
    7.     public bool IsTerrainLower()
    8.     {
    9.         RaycastHit hit;
    10.         Ray ray = new Ray(referenceObject.transform.position, Vector3.down);
    11.  
    12.         if (Physics.Raycast(ray, out hit))
    13.         {
    14.             if (hit.collider.CompareTag("Terrain") && hit.point.y < referenceObject.transform.position.y)
    15.             {
    16.                 return true;
    17.             }
    18.         }
    19.  
    20.         return false;
    21.     }
    22. }

    Code (csharp):
    1. using UnityEngine;
    2.  
    3. public class TerrainCheck : MonoBehaviour
    4. {
    5.     public GameObject referenceObject;
    6.     public LayerMask terrainLayer;
    7.  
    8.     public bool IsTerrainLower()
    9.     {
    10.         RaycastHit hit;
    11.         Ray ray = new Ray(referenceObject.transform.position, Vector3.down);
    12.  
    13.         if (Physics.Raycast(ray, out hit))
    14.         {
    15.             if (((1 << hit.collider.gameObject.layer) & terrainLayer) != 0 && hit.point.y < referenceObject.transform.position.y)
    16.             {
    17.                 return true;
    18.             }
    19.         }
    20.  
    21.         return false;
    22.     }
    23. }
     
  9. Drake4

    Drake4

    Joined:
    Jun 17, 2022
    Posts:
    30
    I only got one terrain.