Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question How to get all terrain points within a sphere?

Discussion in 'Scripting' started by FinTerra, Nov 30, 2023.

  1. FinTerra

    FinTerra

    Joined:
    May 1, 2015
    Posts:
    13
    Hey all,

    when using the unity terrain and determining a point on the terrain via raycast, I want to get a collection of terrain points that are within a sphere with the raycast point as the center.

    Now, to get all the points within a vertical cylinder is easy: Just return all the points that are within a circle in the flat 2d heightmap.

    However, this is not the same as comparing a sphere, see the attached image (black is the terrain, e.g., one steep peak, red is the sphere, blue is the cylinder, the striped areas are the parts of the terrain that are marked by the geometric shape). In this example, the cylinder would mark a lot more points than the sphere.

    I realise that I can initially grab all the points within the cylinder and then sample the heights and compare their distance to the center of the sphere and exclude them if the distance is greater than the radius.

    But I would like to know if I am missing a more efficient method here, like some inbuilt function I overlooked or use a vertex shader.

    Thanks for your input :)


    ps: I think you cannot access the vertex information of a terrain directly: here or here
     

    Attached Files:

  2. Thinted

    Thinted

    Joined:
    Nov 21, 2023
    Posts:
    2
    1. Get points within a cylinder using the terrain's heightmap.
    2. Sample heights to obtain 3D positions.
    3. Exclude points whose distance from the sphere's center is greater than the sphere's radius.
    4. Consider using optimizations like spatial partitioning and custom shaders for efficiency.
    Vector3 raycastPoint = // Obtain raycast point
    float sphereRadius = // Specify sphere radius

    List<Vector3> pointsInCylinder = GetPointsWithinCylinder(raycastPoint, cylinderRadius);
    List<Vector3> pointsWithinSphere = new List<Vector3>();

    foreach (Vector3 point in pointsInCylinder) {
    Vector3 terrainPoint = GetTerrainPointFromHeightmap(point);
    float distance = Vector3.Distance(terrainPoint, raycastPoint);

    if (distance <= sphereRadius) {
    pointsWithinSphere.Add(terrainPoint);
    }
    }
    // pointsWithinSphere contains points within the sphere

    Optimize using spatial data structures and custom shaders for better performance. Adjust parameters as needed for specific project requirements.
     
  3. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,297
    They already said that they understood they COULD use the technique you described. You also should use the code tags to properly format your code so it's readable.

    @FinTerra , if you have to iterate through all the points, you can at least check if it's inside the AABB of the sphere before calculating the distance. For a SphereCollider, this can be done with a collider's .bounds which is already calculated for you. Otherwise, check if the
    Mathf.Abs(xTerrainPoint - xSphereCenter) > sphereRadius
    then also check Y, then also check Z, and only calculate the distance if you're within all of those box dimensions.
     
  4. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    775
    I apologize if I'm wrong but Thinted's post is probably a ChatGPT suggestion. There shouldn't be any need for spatial partitioning as the GetHeights function will take the points of interest directly from the specified region of the height map. There's no searching required.
     
    halley likes this.
  5. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,297
    You're right that it can help but you're still going to want to do some calculations. GetHeights() is integer sample based, not world coordinate based. You should figure out what span of integer samples are within the world span of X and Z of interest. You can then still check the Y heights against the Y axis bounds of the sphere in question before you check if a hill or valley happens to poke into the sphere or not.
     
  6. FinTerra

    FinTerra

    Joined:
    May 1, 2015
    Posts:
    13
    @halley, thanks yes the AABB will filter even more irrelevant points easily.

    So, this sounds like I am not overlooking some built-in terrain method for this :)