Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Problems getting accurate y-value at terrain position

Discussion in 'Physics' started by bettywhite, Jun 25, 2020.

  1. bettywhite

    bettywhite

    Joined:
    Oct 22, 2019
    Posts:
    14
    Howdy,

    I am trying to create random waypoints for my NPCs to navigate towards on my terrain. Randomly generating x and z coordinates is fine, but I cannot get accurate y-values that sit on the terrain.

    I have tried raycasting the terrain layer with the following code but my attempts to raycast do not hit anything and return (0, 0, 0) every time despite the randomly generating locations being above the terrain and raycasting downward. Note: I have both the mask and the terrain set to my "ground" layer.

    Code (CSharp):
    1. void GetRestDestination()
    2. {
    3.       RaycastHit rayHit;
    4.       Vector3 aboveRestDest = new Vector3(restX, 2f, restZ);
    5.  
    6.       //raycast from destination downwards into the mask object (the ground)
    7.       Physics.Raycast(aboveRestDest, Vector3.down, out rayHit, Mathf.Infinity, mask);
    8.       Debug.Log(rayHit.point);
    9.  
    10.       restDestination = rayHit.point;
    11. }
    Another approach I have tried is using Terrain.activeTerrain.SampleHeight, but for some reason this yields y-values that are 40-50 units higher than the actual location. For this, I have been trying the following code:

    Code (CSharp):
    1. float restX = Random.Range(-10f, 9.0f);
    2. float restZ = Random.Range(0f, 60f);
    3. float restY = Terrain.activeTerrain.SampleHeight(new Vector3(restX, 0, restZ));
    4. restDestination = new Vector3(restX, restY, restZ);
    Any help would be greatly appreciated as neither of the two methods people have been using to solve this problem have been working. Thanks for your time!
     
    Last edited: Jun 25, 2020
  2. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    You should be able to use .SampleHeight the value returned is relative to terrain space, so if that is not at 0,0,0 you will need to correct for it.
     
  3. bettywhite

    bettywhite

    Joined:
    Oct 22, 2019
    Posts:
    14
    Hey, thanks for responding. I had tried adjusting the .Sampleheight already and it does seem to reduce the disparity between position and terrain down to about 35 units (from 50-odd), but the position it is returning is still way above the terrain.

    I've been measuring the disparity difference across a few tests and it ranges from being between 33 and 51 units above the desired location.

    For reference, the adjusted code now looks like:
    Code (CSharp):
    1. restX = Random.Range(-10f, 9f);
    2. restY = Random.Range(0f, 60f);
    3. restDestination = new Vector3(restX, 0, restY);
    4. restDestination.y = Terrain.activeTerrain.SampleHeight(restDestination) + Terrain.activeTerrain.transform.position.y;
     
  4. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    Hi,
    If you open the attached package in a new Unity 2019.3.15f1 you can see the results.

    There is a terrain parented to a positioner object (initially set at 0,0,0) and a measure object on the surface of the terrain with a parent, RandomParent (also initially 0,0,0).

    The object uses this script:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class GetHeight : MonoBehaviour
    6. {
    7.     // Start is called before the first frame update
    8.     void Start()
    9.     {
    10.         Debug.Log("Approx Y @ Base of measure: " + (transform.position.y - 0.5f));
    11.         GetRestDestination();
    12.         GetTerrainHeight();
    13.     }
    14.  
    15.  
    16.     void GetRestDestination()
    17.     {
    18.         Physics.Raycast(transform.position, Vector3.down, out RaycastHit rayHit, Mathf.Infinity);
    19.         Debug.Log("Raycast height: " + rayHit.point.y);
    20.     }
    21.  
    22.  
    23.     void GetTerrainHeight()
    24.     {
    25.         Debug.Log("SampleHeight value: " + Terrain.activeTerrain.SampleHeight(transform.position));
    26.     }
    27.  
    28. }
    You will see initially they all give the same answer. If you provide a +1 y offset to the RandomParent, you will see the object's estimated position is in error as it is based on the object's transform.position. Reset RandomParent to 0,0,0

    Change the Positioner object (terrain's parent) to 0, -1, 0 and you will see that the ray cast remains correct, the measuring stick position stays the same (or you can move it to be correct, it does not matter) and the SampleHeight value is now in error by 1m.

    I suspect your problem is one of the following:

    1. Your terrain has a parent that is not 0,0,0 in world space. I accept you have corrected for this.
    2. Those random sample points of yours are not where you think they are (create a primitive at them during run time, so you can see where you are measuring).
    3. Perhaps your mask does not contain what you expect.
    4. You need to make a simple replicator like I have and add in complexity until you find the problem.

    Sorry I cannot find your problem.
     

    Attached Files:

    bettywhite likes this.
  5. bettywhite

    bettywhite

    Joined:
    Oct 22, 2019
    Posts:
    14
    Hey AITheSlacker, sorry for my late response!

    Holy hell, THANK YOU for your help getting back on track. It turns out it was indeed a problem with the terrain parent object (or rather, a problem with the parent's parent), so I wasn't correcting/adjusting the location properly. All is now working (for now!).

    I wish you the best in your own endeavours and hope the internet is as patient and kind to you in your own experiences with coding confusion. :)
     
    AlTheSlacker likes this.