Unity,获取"actual"当前地形?

Unity, get the "actual" current Terrain?

Unity 有一个很棒的功能 Terrain.sampleHeight(point),它可以立即为您提供脚下地形的高度,而不必投射。

然而,任何不平凡的项目都有不止一个 Terrain。 (事实上​​ ,任何物理上大的场景都不可避免地具有地形拼接,以某种方式。)

Unity 有一个函数 Terrain.activeTerrain,它 - 这不是我编的 - 给你:"first one loaded"

显然那是完全没用的。

事实上,有没有快速获取地形的方法"under you"?然后你可以使用快速函数 .sampleHeight ?

{请注意,当然,您可以...施放以在您下方找到地形!但是你会有你的高度,所以没有必要担心 .sampleHeight !}

简而言之,是否有一个与 sampleHeight 一起使用的匹配函数,它让该函数知道 哪个 地形用于给定的 xyz?

(或者实际上,sampleHeight 只是一个相当无用的演示功能,只能在一个地形的演示中使用吗?)

Is there in fact a fast way to get the Terrain "under you" - so as to then use the fast function .sampleHeight ?

是的,可以做到。

(Or indeed, is sampleHeight just a fairly useless demo function, usable only in demos with one Terrain?)

没有


场景中有 Terrain.activeTerrain which returns the main terrain in the scene. There is also Terrain.activeTerrains(注意末尾的 "s")returns 活动地形

Terrain.activeTerrains得到地形returnsTerrain数组然后用Terrain.GetPosition函数得到它的位置。通过寻找距离玩家位置最近的地形来获取当前地形。您可以使用 Vector3.DistanceVector3.sqrMagnitude(更快)对地形位置进行排序。

Terrain GetClosestCurrentTerrain(Vector3 playerPos)
{
    //Get all terrain
    Terrain[] terrains = Terrain.activeTerrains;

    //Make sure that terrains length is ok
    if (terrains.Length == 0)
        return null;

    //If just one, return that one terrain
    if (terrains.Length == 1)
        return terrains[0];

    //Get the closest one to the player
    float lowDist = (terrains[0].GetPosition() - playerPos).sqrMagnitude;
    var terrainIndex = 0;

    for (int i = 1; i < terrains.Length; i++)
    {
        Terrain terrain = terrains[i];
        Vector3 terrainPos = terrain.GetPosition();

        //Find the distance and check if it is lower than the last one then store it
        var dist = (terrainPos - playerPos).sqrMagnitude;
        if (dist < lowDist)
        {
            lowDist = dist;
            terrainIndex = i;
        }
    }
    return terrains[terrainIndex];
}

用法:

假设玩家的位置是transform.position:

//Get the current terrain
Terrain terrain = GetClosestCurrentTerrain(transform.position);
Vector3 point = new Vector3(0, 0, 0);
//Can now use SampleHeight
float yHeight = terrain.SampleHeight(point);

虽然可以用 Terrain.SampleHeight 做到这一点,但这可以通过从玩家位置到地形的简单光线投射来简化。

Vector3 SampleHeightWithRaycast(Vector3 playerPos)
{
    float groundDistOffset = 2f;
    RaycastHit hit;
    //Raycast down to terrain
    if (Physics.Raycast(playerPos, -Vector3.up, out hit))
    {
        //Get y position
        playerPos.y = (hit.point + Vector3.up * groundDistOffset).y;
    }
    return playerPos;
}

原来答案很简单NO,Unity没有提供这样的功能。

Terrain.GetPosition() = Terrain.transform.position = 世界排名
工作方式:

Terrain[] _terrains = Terrain.activeTerrains;

int GetClosestCurrentTerrain(Vector3 playerPos)
{
    //Get the closest one to the player
    var center = new Vector3(_terrains[0].transform.position.x + _terrains[0].terrainData.size.x / 2, playerPos.y, _terrains[0].transform.position.z + _terrains[0].terrainData.size.z / 2);
    float lowDist = (center - playerPos).sqrMagnitude;
    var terrainIndex = 0;

    for (int i = 0; i < _terrains.Length; i++)
    {
        center = new Vector3(_terrains[i].transform.position.x + _terrains[i].terrainData.size.x / 2, playerPos.y, _terrains[i].transform.position.z + _terrains[i].terrainData.size.z / 2);

        //Find the distance and check if it is lower than the last one then store it
        var dist = (center - playerPos).sqrMagnitude;
        if (dist < lowDist)
        {
            lowDist = dist;
            terrainIndex = i;
        }
    }
    return terrainIndex;
}

您可以使用此功能获取离您当前位置最近的地形:

int GetClosestTerrain(Vector3 CheckPos)
{
    int terrainIndex = 0;
    float lowDist = float.MaxValue;

    for (int i = 0; i < _terrains.Length; i++)
    {
      var center = new Vector3(_terrains[i].transform.position.x + _terrains[i].terrainData.size.x / 2, CheckPos.y, _terrains[i].transform.position.z + _terrains[i].terrainData.size.z / 2);

      float dist = Vector3.Distance(center, CheckPos);

      if (dist < lowDist)
      {
        lowDist = dist;
        terrainIndex = i;
      }
    }
    return terrainIndex;
}

然后你可以像这样使用函数:

private Terrain[] _terrains;

void Start()
  {
    _terrains = Terrain.activeTerrains;

    Vector3 start_pos = Vector3.zero;

    start_pos.y = _terrains[GetClosestTerrain(start_pos)].SampleHeight(start_pos);

  }
public static Terrain GetClosestTerrain(Vector3 position)
{
    return Terrain.activeTerrains.OrderBy(x =>
    {
        var terrainPosition = x.transform.position;
        var terrainSize = x.terrainData.size * 0.5f;
        var terrainCenter = new Vector3(terrainPosition.x + terrainSize.x, position.y, terrainPosition.z + terrainSize.z);
        return Vector3.Distance(terrainCenter, position);
    }).First();
}