Hi, I am trying to build a height span map of an object. It’s like a height map, but instead of having only one height value for each point of the grid, there should be a series of heights indicating height spans.
To build a heightmap, I would just cast a ray from each point of the grid, but for heightspan maps it is trickier. As raycasts stop at the first hit, I tried to cast rays in a loop until there is no more hit. That way I get a sequence of heights for each point.
But raycasts only hit the outside of colliders, they do not hit from the inside. So now for each point of the grid, I loop to cast rays in one direction, then I loop in the opposite direction. This yields better results, but it is not a perfect height span map.
Is there a better method to build a height span map? Are raycasts the way to go but I’m doing it wrong?
Edit for clarification:
While heightmaps are most often used in the case of terrains, my use case is different. The concept is the same though. In my case, the goal is to build the heightspan map of an object (any object, with concave and convex parts) on top of my reference grid. To build a heightmap of the outer surface of that object, using raycasts work fine. Now to retrieve the heights of the intersections between the collider and my grid, raycasting works somehow but I have a feeling it is not the best way…
Here is some code that gives me my current height spans (I postprocess it for ordering and filtering):
private void findPointHeightSpans(Vector3 origin, Coordinates coordinates, Dictionary<Coordinates, List<HeightSpanHit>> heightSpanMap, bool up)
{
RaycastHit hit;
while (Physics.Raycast(origin, up ? Vector3.up : Vector3.down, out hit, Mathf.Infinity, myColliderLayerMask))
{
List<HeightSpanHit> hits;
if (heightSpanMap.ContainsKey(coordinates))
{
hits = heightSpanMap[coordinates];
}
else
{
hits = new List<HeightSpanHit>();
heightSpanMap[coordinates] = hits;
}
float hitHeight = hit.point.y;
hits.Add(new HeightSpanHit(hitHeight, hit.normal.y < 0));
origin.y = hitHeight + (up ? 0.001f : -0.001f); // add a millimeter to avoid hitting the same point in an infinite loop
}
}
private void buildHeightSpanMap()
{
Dictionary<Coordinates, List<HeightSpanHit>> heightSpanMap = new Dictionary<Coordinates, List<HeightSpanHit>>();
...
for (int y = minY; y <= maxY; y++)
{
for (int x = minX; x <= maxX; x++)
{
Coordinates coordinates = new Coordinates(x, y);
Vector3 vertexWorld = canvas.VertexCoordinatesToWorldPosition(x, y);
// cast vertical rays from below
vertexWorld.y = 0;
findPointHeightSpans(vertexWorld, coordinates, heightSpanMap, true);
// cast vertical rays from above
vertexWorld.y = 1000f;
findPointHeightSpans(vertexWorld, coordinates, heightSpanMap, false);
}
}
}