How to get all terrain points within a sphere?

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 :slight_smile:

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

  • Get points within a cylinder using the terrain’s heightmap.
  • Sample heights to obtain 3D positions.
  • Exclude points whose distance from the sphere’s center is greater than the sphere’s radius.
  • Consider using optimizations like spatial partitioning and custom shaders for efficiency.

Vector3 raycastPoint = // Obtain raycast point
float sphereRadius = // Specify sphere radius

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

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.

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.

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.

1 Like

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.

@halley1 , 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 :slight_smile: