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?
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.
I think this is a really good idea, and I instantly tried this however
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?
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.
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.
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.
Using a tag for the terrain
using UnityEngine;
public class TerrainCheck : MonoBehaviour
{
public GameObject referenceObject;
public bool IsTerrainLower()
{
RaycastHit hit;
Ray ray = new Ray(referenceObject.transform.position, Vector3.down);
if (Physics.Raycast(ray, out hit))
{
if (hit.collider.CompareTag("Terrain") && hit.point.y < referenceObject.transform.position.y)
{
return true;
}
}
return false;
}
}
Using a layer for the terrain
using UnityEngine;
public class TerrainCheck : MonoBehaviour
{
public GameObject referenceObject;
public LayerMask terrainLayer;
public bool IsTerrainLower()
{
RaycastHit hit;
Ray ray = new Ray(referenceObject.transform.position, Vector3.down);
if (Physics.Raycast(ray, out hit))
{
if (((1 << hit.collider.gameObject.layer) & terrainLayer) != 0 && hit.point.y < referenceObject.transform.position.y)
{
return true;
}
}
return false;
}
}